Skip to content

Commit

Permalink
feat(publish): Allow from-package positional to run without a git repo
Browse files Browse the repository at this point in the history
Refs #1933
  • Loading branch information
evocateur committed Feb 14, 2019
1 parent c794244 commit df49bfc
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 7 deletions.
24 changes: 24 additions & 0 deletions commands/publish/__tests__/publish-from-package.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@ jest.mock("../../version/lib/is-anything-committed");
jest.mock("../../version/lib/is-behind-upstream");
jest.mock("../../version/lib/remote-branch-exists");

const fs = require("fs-extra");
const path = require("path");

// mocked or stubbed modules
const writePkg = require("write-pkg");
const npmPublish = require("@lerna/npm-publish");
const PromptUtilities = require("@lerna/prompt");
const output = require("@lerna/output");
Expand Down Expand Up @@ -88,4 +92,24 @@ describe("publish from-package", () => {

expect.assertions(1);
});

it("does not require a git repo", async () => {
getUnpublishedPackages.mockImplementationOnce(packageGraph => [packageGraph.get("package-1")]);

const cwd = await initFixture("independent");

// nuke the git repo first
await fs.remove(path.join(cwd, ".git"));
await lernaPublish(cwd)("from-package");

expect(npmPublish).toHaveBeenCalled();
expect(writePkg.updatedManifest("package-1")).not.toHaveProperty("gitHead");

const logMessages = loggingOutput("info");
expect(logMessages).toContain("Unable to verify working tree, proceed at your own risk");
expect(logMessages).toContain(
"Unable to set temporary gitHead property, it will be missing from registry metadata"
);
expect(logMessages).toContain("Unable to reset working tree changes, this probably isn't a git repo.");
});
});
43 changes: 36 additions & 7 deletions commands/publish/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ class PublishCommand extends Command {
return ["version"];
}

get requiresGit() {
// `lerna publish from-package` doesn't _need_ git, per se
return this.options.bump !== "from-package";
}

initialize() {
if (this.options.skipNpm) {
// TODO: remove in next major release
Expand Down Expand Up @@ -245,7 +250,19 @@ class PublishCommand extends Command {
let chain = Promise.resolve();

// attempting to publish a release with local changes is not allowed
chain = chain.then(() => this.verifyWorkingTreeClean());
chain = chain
.then(() => this.verifyWorkingTreeClean())
.catch(err => {
// an execa error is thrown when git suffers a fatal error (such as no git repository present)
if (err.failed && err.code === 128 && err.stderr && /not a git repository/.test(err.stderr)) {
// (we tried)
this.logger.silly("EWORKINGTREE", err.message);
this.logger.info("FYI", "Unable to verify working tree, proceed at your own risk");
} else {
// validation errors should be preserved
throw err;
}
});

chain = chain.then(() => getUnpublishedPackages(this.packageGraph, this.conf.snapshot));
chain = chain.then(unpublished => {
Expand Down Expand Up @@ -474,11 +491,20 @@ class PublishCommand extends Command {
}

annotateGitHead() {
const gitHead = getCurrentSHA(this.execOpts);
try {
const gitHead = getCurrentSHA(this.execOpts);

for (const pkg of this.packagesToPublish) {
// provide gitHead property that is normally added during npm publish
pkg.set("gitHead", gitHead);
for (const pkg of this.packagesToPublish) {
// provide gitHead property that is normally added during npm publish
pkg.set("gitHead", gitHead);
}
} catch (err) {
// from-package should be _able_ to run without git, but at least we tried
this.logger.silly("EGITHEAD", err.message);
this.logger.info(
"FYI",
"Unable to set temporary gitHead property, it will be missing from registry metadata"
);
}

// writing changes to disk handled in serializeChanges()
Expand All @@ -490,13 +516,16 @@ class PublishCommand extends Command {

resetChanges() {
// the package.json files are changed (by gitHead if not --canary)
// and we should always leave the working tree clean
// and we should always __attempt_ to leave the working tree clean
const { cwd } = this.execOpts;
const dirtyManifests = [this.project.manifest]
.concat(this.packagesToPublish)
.map(pkg => path.relative(cwd, pkg.manifestLocation));

return gitCheckout(dirtyManifests, this.execOpts);
return gitCheckout(dirtyManifests, this.execOpts).catch(err => {
this.logger.silly("EGITCHECKOUT", err.message);
this.logger.info("FYI", "Unable to reset working tree changes, this probably isn't a git repo.");
});
}

execScript(pkg, script) {
Expand Down

0 comments on commit df49bfc

Please sign in to comment.