From 874e6530532edee61b699d57411bad33b7568b28 Mon Sep 17 00:00:00 2001 From: Tyler Wanek Date: Mon, 4 Feb 2019 17:19:55 -0700 Subject: [PATCH 1/2] Use same API for signingCb in all places that can be crypto signed Any place where we implement a callback pattern for signing commits/tags follows the same API: `type SigningCB = (content: string) => { code: number, field?: string, signedData?: string };` --- lib/commit.js | 108 +++++++---- lib/rebase.js | 25 ++- lib/repository.js | 95 +++++---- lib/tag.js | 30 ++- test/tests/commit.js | 447 +++++++++++++++++++++++++++++++++---------- test/tests/rebase.js | 361 +++++++++++++++++++++++++++++++++- test/tests/tag.js | 230 ++++++++++++++++++---- 7 files changed, 1071 insertions(+), 225 deletions(-) diff --git a/lib/commit.js b/lib/commit.js index 02b3679d5..701b944e0 100644 --- a/lib/commit.js +++ b/lib/commit.js @@ -60,8 +60,7 @@ Commit.prototype.amend = function ( * @param {String} messageEncoding * @param {String} message * @param {Tree|Oid} tree - * @param {String} signatureField - * @param {Function} onSignature + * @param {Function} onSignature Callback to be called with string to be signed * @return {Oid} */ Commit.prototype.amendWithSignature = function( @@ -71,13 +70,12 @@ Commit.prototype.amendWithSignature = function( messageEncoding, message, tree, - signatureField, onSignature ) { - var repo = this.repo; - var parentOids = this.parents(); - var _this = this; - var promises = []; + let repo = this.repo; + let parentOids = this.parents(); + let _this = this; + let promises = []; if (tree instanceof NodeGit.Oid) { promises.push(repo.getTree(tree)); @@ -89,22 +87,27 @@ Commit.prototype.amendWithSignature = function( promises.push(repo.getCommit(parentOid)); }); - var treeObject; - var parents; - var commitContent; - var commitOid; - var commit; - - var createCommitPromise = Promise.all(promises) + let treeObject; + let parents; + let commitContent; + let commit; + let skippedSigning; + let resolvedAuthor; + let resolvedCommitter; + let resolvedMessageEncoding; + let resolvedMessage; + let resolvedTree; + + let createCommitPromise = Promise.all(promises) .then(function(results) { treeObject = fp.head(results); parents = fp.tail(results); return _this.getTree(); }) .then(function(commitTreeResult) { - var commitTree = commitTreeResult; + let commitTree = commitTreeResult; - var truthyArgs = fp.omitBy( + let truthyArgs = fp.omitBy( fp.isNil, { author, @@ -115,7 +118,7 @@ Commit.prototype.amendWithSignature = function( } ); - var commitFields = { + let commitFields = { author: _this.author(), committer: _this.committer(), messageEncoding: _this.messageEncoding(), @@ -123,7 +126,7 @@ Commit.prototype.amendWithSignature = function( tree: commitTree }; - var { + ({ author: resolvedAuthor, committer: resolvedCommitter, messageEncoding: resolvedMessageEncoding, @@ -132,7 +135,7 @@ Commit.prototype.amendWithSignature = function( } = fp.assign( commitFields, truthyArgs - ); + )); return Commit.createBuffer( repo, @@ -152,30 +155,61 @@ Commit.prototype.amendWithSignature = function( } return onSignature(commitContent); }) - .then(function(signature) { - return Commit.createWithSignature( - repo, - commitContent, - signature, - signatureField - ); + .then(function({ code, field, signedData }) { + switch (code) { + case NodeGit.Error.CODE.OK: + return Commit.createWithSignature( + repo, + commitContent, + signedData, + field + ); + case NodeGit.Error.CODE.PASSTHROUGH: + skippedSigning = true; + return Commit.create( + repo, + updateRef, + resolvedAuthor, + resolvedCommitter, + resolvedMessageEncoding, + resolvedMessage, + resolvedTree, + parents.length, + parents + ); + default: { + const error = new Error( + `Commit.amendWithSignature threw with error code ${code}` + ); + error.errno = code; + throw error; + } + } }); if (!updateRef) { return createCommitPromise; } - return createCommitPromise.then(function(commitOidResult) { - commitOid = commitOidResult; - return repo.getCommit(commitOid); - }).then(function(commitResult) { - commit = commitResult; - return repo.getReference(updateRef); - }).then(function(ref) { - return ref.setTarget(commitOid, `commit (amend): ${commit.summary()}`); - }).then(function() { - return commitOid; - }); + return createCommitPromise + .then(function(commitOid) { + if (skippedSigning) { + return commitOid; + } + + return repo.getCommit(commitOid) + .then(function(commitResult) { + commit = commitResult; + return repo.getReference(updateRef); + }).then(function(ref) { + return ref.setTarget( + commitOid, + `commit (amend): ${commit.summary()}` + ); + }).then(function() { + return commitOid; + }); + }); }; /** diff --git a/lib/rebase.js b/lib/rebase.js index 0d9521760..e55f0ddde 100644 --- a/lib/rebase.js +++ b/lib/rebase.js @@ -9,8 +9,8 @@ var _abort = Rebase.prototype.abort; var _commit = Rebase.prototype.commit; function defaultRebaseOptions(options, checkoutStrategy) { - var checkoutOptions; - var mergeOptions; + let checkoutOptions; + let mergeOptions; if (options) { options = shallowClone(options); @@ -19,6 +19,27 @@ function defaultRebaseOptions(options, checkoutStrategy) { delete options.checkoutOptions; delete options.mergeOptions; + if (options.signingCb) { + let signingCb = options.signingCb; + options.signingCb = function ( + signatureBuf, + signatureFieldBuf, + commitContent + ) { + return Promise.resolve(signingCb(commitContent)) + .then(function({ code, field, signedData }) { + if (code === NodeGit.Error.CODE.OK) { + signatureBuf.setString(signedData); + if (field) { + signatureFieldBuf.setString(field); + } + } + + return code; + }); + }; + } + options = normalizeOptions(options, NodeGit.RebaseOptions); } else { options = normalizeOptions({}, NodeGit.RebaseOptions); diff --git a/lib/repository.js b/lib/repository.js index 3636c9a6e..ea3b7fb65 100644 --- a/lib/repository.js +++ b/lib/repository.js @@ -658,25 +658,24 @@ Repository.prototype.createCommitBuffer = function( * @param {String} message * @param {Tree|Oid|String} Tree * @param {Array} parents - * @param {String} signature_field typically "gpgsig" * @param {Function} onSignature Callback to be called with string to be signed * @return {Oid} The oid of the commit */ Repository.prototype.createCommitWithSignature = function( - updateRef, - author, - committer, - message, - tree, - parents, - signature_field, - onSignature) { + updateRef, + author, + committer, + message, + tree, + parents, + onSignature +) { var repo = this; var promises = []; - var commit_content; - var commit_oid; + var commitContent; var commit; + var skippedSigning; parents = parents || []; @@ -707,35 +706,65 @@ Repository.prototype.createCommitWithSignature = function( parents.length, parents ); - }).then(function(commit_contentResult) { - commit_content = commit_contentResult; - if (!commit_content.endsWith("\n")) { - commit_content += "\n"; + }).then(function(commitContentResult) { + commitContent = commitContentResult; + if (!commitContent.endsWith("\n")) { + commitContent += "\n"; + } + return onSignature(commitContent); + }).then(function({ code, field, signedData }) { + switch (code) { + case NodeGit.Error.CODE.OK: + return Commit.createWithSignature( + repo, + commitContent, + signedData, + field + ); + case NodeGit.Error.CODE.PASSTHROUGH: + skippedSigning = true; + return Commit.create( + repo, + updateRef, + author, + committer, + null /* use default message encoding */, + message, + tree, + parents.length, + parents + ); + default: { + const error = new Error( + "Repository.prototype.createCommitWithSignature " + + `threw with error code ${code}` + ); + error.errno = code; + throw error; + } } - return onSignature(commit_content); - }).then(function(signature) { - return Commit.createWithSignature( - repo, - commit_content, - signature, - signature_field); }); if (!updateRef) { return createCommitPromise; } - return createCommitPromise.then(function(commit_oidResult) { - commit_oid = commit_oidResult; - return repo.getCommit(commit_oid); - }).then(function(commitResult) { - commit = commitResult; - return repo.getReference(updateRef); - }).then(function(ref) { - return ref.setTarget(commit_oid, getReflogMessageForCommit(commit)); - }).then(function() { - return commit_oid; - }); + return createCommitPromise + .then(function(commitOid) { + if (skippedSigning) { + return commitOid; + } + + return repo.getCommit(commitOid) + .then(function(commitResult) { + commit = commitResult; + return repo.getReference(updateRef); + }).then(function(ref) { + return ref.setTarget(commitOid, getReflogMessageForCommit(commit)); + }).then(function() { + return commitOid; + }); + }); }; /** diff --git a/lib/tag.js b/lib/tag.js index b94872160..a1183bc85 100644 --- a/lib/tag.js +++ b/lib/tag.js @@ -76,10 +76,30 @@ Tag.createWithSignature = function( tagBuffer = tagBufferResult; return signingCallback(tagBuffer); }) - .then((tagSignature) => { - const normalizedEnding = tagSignature.endsWith("\n") ? "" : "\n"; - const signedTagString = tagBuffer + tagSignature + normalizedEnding; - return Tag.createFromBuffer(repo, signedTagString, force); + .then(({ code, signedData }) => { + switch (code) { + case NodeGit.Error.CODE.OK: { + const normalizedEnding = signedData.endsWith("\n") ? "" : "\n"; + const signedTagString = tagBuffer + signedData + normalizedEnding; + return Tag.createFromBuffer(repo, signedTagString, force); + } + case NodeGit.Error.CODE.PASSTHROUGH: + return Tag.create( + repo, + tagName, + target, + tagger, + message, + force + ); + default: { + const error = new Error( + `Tag.createWithSignature threw with error code ${code}` + ); + error.errno = code; + throw error; + } + } }); }; @@ -110,6 +130,6 @@ Tag.prototype.extractSignature = function(signatureType = "gpgsig") { } } - return null; + throw new Error("this tag is not signed"); }); }; diff --git a/test/tests/commit.js b/test/tests/commit.js index 522017bc7..6f212d6a4 100644 --- a/test/tests/commit.js +++ b/test/tests/commit.js @@ -450,45 +450,45 @@ describe("Commit", function() { }); }); - - it("can amend commit with signature", function() { - const signature = "-----BEGIN PGP SIGNATURE-----\n" + - "\n" + - "iQJHBAEBCAAxFiEEKdxGpJ93wnkLaBKfURjJKedOfEMFAlxPKUYTHHN0ZXZla0Bh\n" + - "eG9zb2Z0LmNvbQAKCRBRGMkp5058Q3vcD/0Uf6P68g98Kbvsgjg/aidM1ujruXaw\n" + - "X5WSsCAw+wWGICOj0n+KBnmQruI4HSFz3zykEshuOpcBv1X/+huwDeB/hBqonCU8\n" + - "QdexCdWR70YbT1bufesUwV9v1qwE4WOmFxWXgwh55K0wDRkc0u2aLcwrJkIEEVfs\n" + - "HqZyFzU4kwbGekY/m7d1DsBhWyKEGW9/25WMYmjWOWOiaFjeBaHLlxiEM8KGnMLH\n" + - "wx37NuFuaABgi23AAcBGdeWy04TEuU4S51+bHM3RotrZ2cryW2lEbkkXodhIJcq0\n" + - "RgrStCbvR0ehnOPdYSiRbxK8JNLZuNjHlK2g7wVi+C83vwMQuhU4H6OlYHGVr664\n" + - "4YzL83FdIo7wiMOFd2OOMLlCfHgTun60FvjCs4WHjrwH1fQl287FRPLa/4olBSQP\n" + - "yUXJaZdxm4cB4L/1pmbb/J/XUiOio3MpaN3GFm2hZloUlag1uPDBtCxTl5odvj4a\n" + - "GOmTBWznXxF/zrKnQVSvv+EccNxYFc0VVjAxGgNqPzIxDAKtw1lE5pbBkFpFpNHz\n" + - "StmwZkP9QIJY4hJYQfM+pzHLe8xjexL+Kh/TrYXgY1m/4vJe0HJSsnRnaR8Yfqhh\n" + - "LReqo94VHRYXR0rZQv4py0D9TrWaI8xHLve6ewhLPNRzyaI9fNrinbcPYZZOWnRi\n" + - "ekgUBx+BX6nJOw==\n" + - "=4Hy5\n" + - "-----END PGP SIGNATURE-----"; - - function onSignature(dataToSign) { - return new Promise(function (resolve) { - return resolve(signature); + describe("amendWithSignature", function() { + it("can amend with signature", function() { + const signedData = "-----BEGIN PGP SIGNATURE-----\n" + + "\n" + + "iQJHBAEBCAAxFiEEKdxGpJ93wnkLaBKfURjJKedOfEMFAlxPKUYTHHN0ZXZla0Bh\n" + + "eG9zb2Z0LmNvbQAKCRBRGMkp5058Q3vcD/0Uf6P68g98Kbvsgjg/aidM1ujruXaw\n" + + "X5WSsCAw+wWGICOj0n+KBnmQruI4HSFz3zykEshuOpcBv1X/+huwDeB/hBqonCU8\n" + + "QdexCdWR70YbT1bufesUwV9v1qwE4WOmFxWXgwh55K0wDRkc0u2aLcwrJkIEEVfs\n" + + "HqZyFzU4kwbGekY/m7d1DsBhWyKEGW9/25WMYmjWOWOiaFjeBaHLlxiEM8KGnMLH\n" + + "wx37NuFuaABgi23AAcBGdeWy04TEuU4S51+bHM3RotrZ2cryW2lEbkkXodhIJcq0\n" + + "RgrStCbvR0ehnOPdYSiRbxK8JNLZuNjHlK2g7wVi+C83vwMQuhU4H6OlYHGVr664\n" + + "4YzL83FdIo7wiMOFd2OOMLlCfHgTun60FvjCs4WHjrwH1fQl287FRPLa/4olBSQP\n" + + "yUXJaZdxm4cB4L/1pmbb/J/XUiOio3MpaN3GFm2hZloUlag1uPDBtCxTl5odvj4a\n" + + "GOmTBWznXxF/zrKnQVSvv+EccNxYFc0VVjAxGgNqPzIxDAKtw1lE5pbBkFpFpNHz\n" + + "StmwZkP9QIJY4hJYQfM+pzHLe8xjexL+Kh/TrYXgY1m/4vJe0HJSsnRnaR8Yfqhh\n" + + "LReqo94VHRYXR0rZQv4py0D9TrWaI8xHLve6ewhLPNRzyaI9fNrinbcPYZZOWnRi\n" + + "ekgUBx+BX6nJOw==\n" + + "=4Hy5\n" + + "-----END PGP SIGNATURE-----"; + + const onSignature = () => ({ + code: NodeGit.Error.CODE.OK, + field: "gpgsig", + signedData }); - } - var repo; - var oid; - var commit; - var message; - var parents; + var repo; + var oid; + var commit; + var message; + var parents; - return NodeGit.Repository.open(reposPath) + return NodeGit.Repository.open(reposPath) .then(function(repoResult) { repo = repoResult; return repo.getHeadCommit(); }) .then(function(headCommit) { - message = headCommit.message(); + message = headCommit.message() + "\n"; parents = headCommit.parents(); return headCommit.amendWithSignature( @@ -498,7 +498,6 @@ describe("Commit", function() { null, null, null, - "gpgsig", onSignature ); }) @@ -511,65 +510,65 @@ describe("Commit", function() { return commit.getSignature("gpgsig"); }) .then(function(signatureInfo) { - assert.equal(signatureInfo.signature, signature); + assert.equal(signatureInfo.signature, signedData); assert.equal(commit.message(), message); assert.deepEqual(commit.parents(), parents); }); - }); + }); - it("amending with signature respects overridden arguments", function() { - const signature = "-----BEGIN PGP SIGNATURE-----\n" + - "\n" + - "iQJHBAEBCAAxFiEEKdxGpJ93wnkLaBKfURjJKedOfEMFAlxPKUYTHHN0ZXZla0Bh\n" + - "eG9zb2Z0LmNvbQAKCRBRGMkp5058Q3vcD/0Uf6P68g98Kbvsgjg/aidM1ujruXaw\n" + - "X5WSsCAw+wWGICOj0n+KBnmQruI4HSFz3zykEshuOpcBv1X/+huwDeB/hBqonCU8\n" + - "QdexCdWR70YbT1bufesUwV9v1qwE4WOmFxWXgwh55K0wDRkc0u2aLcwrJkIEEVfs\n" + - "HqZyFzU4kwbGekY/m7d1DsBhWyKEGW9/25WMYmjWOWOiaFjeBaHLlxiEM8KGnMLH\n" + - "wx37NuFuaABgi23AAcBGdeWy04TEuU4S51+bHM3RotrZ2cryW2lEbkkXodhIJcq0\n" + - "RgrStCbvR0ehnOPdYSiRbxK8JNLZuNjHlK2g7wVi+C83vwMQuhU4H6OlYHGVr664\n" + - "4YzL83FdIo7wiMOFd2OOMLlCfHgTun60FvjCs4WHjrwH1fQl287FRPLa/4olBSQP\n" + - "yUXJaZdxm4cB4L/1pmbb/J/XUiOio3MpaN3GFm2hZloUlag1uPDBtCxTl5odvj4a\n" + - "GOmTBWznXxF/zrKnQVSvv+EccNxYFc0VVjAxGgNqPzIxDAKtw1lE5pbBkFpFpNHz\n" + - "StmwZkP9QIJY4hJYQfM+pzHLe8xjexL+Kh/TrYXgY1m/4vJe0HJSsnRnaR8Yfqhh\n" + - "LReqo94VHRYXR0rZQv4py0D9TrWaI8xHLve6ewhLPNRzyaI9fNrinbcPYZZOWnRi\n" + - "ekgUBx+BX6nJOw==\n" + - "=4Hy5\n" + - "-----END PGP SIGNATURE-----"; - - function onSignature(dataToSign) { - return new Promise(function (resolve) { - return resolve(signature); + it("will respects overridden arguments", function() { + const signedData = "-----BEGIN PGP SIGNATURE-----\n" + + "\n" + + "iQJHBAEBCAAxFiEEKdxGpJ93wnkLaBKfURjJKedOfEMFAlxPKUYTHHN0ZXZla0Bh\n" + + "eG9zb2Z0LmNvbQAKCRBRGMkp5058Q3vcD/0Uf6P68g98Kbvsgjg/aidM1ujruXaw\n" + + "X5WSsCAw+wWGICOj0n+KBnmQruI4HSFz3zykEshuOpcBv1X/+huwDeB/hBqonCU8\n" + + "QdexCdWR70YbT1bufesUwV9v1qwE4WOmFxWXgwh55K0wDRkc0u2aLcwrJkIEEVfs\n" + + "HqZyFzU4kwbGekY/m7d1DsBhWyKEGW9/25WMYmjWOWOiaFjeBaHLlxiEM8KGnMLH\n" + + "wx37NuFuaABgi23AAcBGdeWy04TEuU4S51+bHM3RotrZ2cryW2lEbkkXodhIJcq0\n" + + "RgrStCbvR0ehnOPdYSiRbxK8JNLZuNjHlK2g7wVi+C83vwMQuhU4H6OlYHGVr664\n" + + "4YzL83FdIo7wiMOFd2OOMLlCfHgTun60FvjCs4WHjrwH1fQl287FRPLa/4olBSQP\n" + + "yUXJaZdxm4cB4L/1pmbb/J/XUiOio3MpaN3GFm2hZloUlag1uPDBtCxTl5odvj4a\n" + + "GOmTBWznXxF/zrKnQVSvv+EccNxYFc0VVjAxGgNqPzIxDAKtw1lE5pbBkFpFpNHz\n" + + "StmwZkP9QIJY4hJYQfM+pzHLe8xjexL+Kh/TrYXgY1m/4vJe0HJSsnRnaR8Yfqhh\n" + + "LReqo94VHRYXR0rZQv4py0D9TrWaI8xHLve6ewhLPNRzyaI9fNrinbcPYZZOWnRi\n" + + "ekgUBx+BX6nJOw==\n" + + "=4Hy5\n" + + "-----END PGP SIGNATURE-----"; + + const onSignature = () => ({ + code: NodeGit.Error.CODE.OK, + field: "gpgsig", + signedData }); - } - var repo; - var oid; - var commit; - var message; - var parents; - var commitTree; - - var author = NodeGit.Signature.create( - "Scooby Doo", - "scoob@mystery.com", - 123456789, - 60 - ); - var committer = NodeGit.Signature.create( - "Shaggy Rogers", - "shaggy@mystery.com", - 987654321, - 90 - ); - var tree = Oid.fromString("f4661419a6fbbe865f78644fec722c023ce4b65f"); + var repo; + var oid; + var commit; + var message; + var parents; + var commitTree; + + var author = NodeGit.Signature.create( + "Scooby Doo", + "scoob@mystery.com", + 123456789, + 60 + ); + var committer = NodeGit.Signature.create( + "Shaggy Rogers", + "shaggy@mystery.com", + 987654321, + 90 + ); + var tree = Oid.fromString("f4661419a6fbbe865f78644fec722c023ce4b65f"); - return NodeGit.Repository.open(reposPath) + return NodeGit.Repository.open(reposPath) .then(function(repoResult) { repo = repoResult; return repo.getHeadCommit(); }) .then(function(headCommit) { - message = headCommit.message(); + message = headCommit.message() + "\n"; parents = headCommit.parents(); return headCommit.amendWithSignature( @@ -579,7 +578,6 @@ describe("Commit", function() { null, null, tree, - "gpgsig", onSignature ); }) @@ -596,13 +594,96 @@ describe("Commit", function() { return commit.getSignature("gpgsig"); }) .then(function(signatureInfo) { - assert.equal(signatureInfo.signature, signature); + assert.equal(signatureInfo.signature, signedData); assert.equal(commit.message(), message); assert.deepEqual(commit.parents(), parents); assert.deepEqual(commitTree.id(), tree); assert.deepEqual(commit.author(), author); assert.deepEqual(commit.committer(), committer); }); + }); + + it("can optionally skip signing process", function() { + const onSignature = () => ({ + code: NodeGit.Error.CODE.PASSTHROUGH + }); + + var repo; + var oid; + var commit; + var message; + var parents; + + return NodeGit.Repository.open(reposPath) + .then(function(repoResult) { + repo = repoResult; + return repo.getHeadCommit(); + }) + .then(function(headCommit) { + message = headCommit.message(); + parents = headCommit.parents(); + + return headCommit.amendWithSignature( + null, + null, + null, + null, + null, + null, + onSignature + ); + }) + .then(function(oidResult) { + oid = oidResult; + return NodeGit.Commit.lookup(repo, oid); + }) + .then(function(commitResult) { + commit = commitResult; + return commit.getSignature("gpgsig") + .then(function() { + assert.fail("Should not have a signature"); + }, function(error) { + if (error && error.message === "this commit is not signed") { + return; + } + throw error; + }); + }) + .then(function(signatureInfo) { + assert.equal(commit.message(), message); + assert.deepEqual(commit.parents(), parents); + }); + }); + + it("will throw if signing callback returns an error code", function() { + const onSignature = () => ({ + code: NodeGit.Error.CODE.ERROR + }); + + return NodeGit.Repository.open(reposPath) + .then(function(repo) { + return repo.getHeadCommit(); + }) + .then(function(headCommit) { + return headCommit.amendWithSignature( + null, + null, + null, + null, + null, + null, + onSignature + ); + }) + .then(function() { + assert.fail("amendWithSignature should have failed."); + }, function(error) { + if (error && error.errno === NodeGit.Error.CODE.ERROR) { + return; + } + throw error; + }); + }); }); it("has an owner", function() { @@ -946,10 +1027,8 @@ describe("Commit", function() { }); describe("Commit's Signature", function() { - it("Can create a signed commit in a repo", function() { - - var signature = "-----BEGIN PGP SIGNATURE-----\n" + + var signedData = "-----BEGIN PGP SIGNATURE-----\n" + "Version: GnuPG v1.4.12 (Darwin)\n" + "\n" + "iQIcBAABAgAGBQJQ+FMIAAoJEH+LfPdZDSs1e3EQAJMjhqjWF+WkGLHju7pTw2al\n" + @@ -967,11 +1046,11 @@ describe("Commit", function() { "=ozeK\n" + "-----END PGP SIGNATURE-----"; - function onSignature(dataToSign) { - return new Promise(function (resolve) { - return resolve(signature); - }); - } + const onSignature = () => ({ + code: NodeGit.Error.CODE.OK, + field: "gpgsig", + signedData + }); var test = this; var expectedCommitId = "ccb99bb20716ef7c37e92c7b8db029a7af7f747b"; @@ -1028,8 +1107,8 @@ describe("Commit", function() { "message", treeOid, [parent], - "gpgsig", - onSignature); + onSignature + ); }) .then(function(commitId) { assert.equal(expectedCommitId, commitId); @@ -1039,7 +1118,7 @@ describe("Commit", function() { return commit.getSignature("gpgsig"); }) .then(function(signatureInfo) { - assert.equal(signature, signatureInfo.signature); + assert.equal(signedData, signatureInfo.signature); return reinitialize(test); }, function(reason) { return reinitialize(test) @@ -1050,8 +1129,7 @@ describe("Commit", function() { }); it("Can create a signed commit in a repo and update refs", function() { - - var signature = "-----BEGIN PGP SIGNATURE-----\n" + + var signedData = "-----BEGIN PGP SIGNATURE-----\n" + "Version: GnuPG v1.4.12 (Darwin)\n" + "\n" + "iQIcBAABAgAGBQJQ+FMIAAoJEH+LfPdZDSs1e3EQAJMjhqjWF+WkGLHju7pTw2al\n" + @@ -1069,11 +1147,11 @@ describe("Commit", function() { "=ozeK\n" + "-----END PGP SIGNATURE-----"; - function onSignature(dataToSign) { - return new Promise(function (resolve) { - return resolve(signature); - }); - } + const onSignature = () => ({ + code: NodeGit.Error.CODE.OK, + field: "gpgsig", + signedData + }); var test = this; var expectedCommitId = "ccb99bb20716ef7c37e92c7b8db029a7af7f747b"; @@ -1130,7 +1208,6 @@ describe("Commit", function() { "message", treeOid, [parent], - "gpgsig", onSignature); }) .then(function(commitId) { @@ -1141,7 +1218,7 @@ describe("Commit", function() { return commit.getSignature("gpgsig"); }) .then(function(signatureInfo) { - assert.equal(signature, signatureInfo.signature); + assert.equal(signedData, signatureInfo.signature); return repo.getHeadCommit(); }) .then(function(headCommit) { @@ -1244,5 +1321,173 @@ describe("Commit", function() { ); }); }); + + it("Can be optionally skipped to create without signature", function() { + const onSignature = () => ({ + code: NodeGit.Error.CODE.PASSTHROUGH + }); + + var test = this; + var expectedCommitId = "c9bffe040519231d32431c101bca4efc0917f64c"; + var fileName = "newfile.txt"; + var fileContent = "hello world"; + + var repo; + var index; + var treeOid; + var parent; + + return NodeGit.Repository.open(reposPath) + .then(function(repoResult) { + repo = repoResult; + return fse.writeFile(path.join(repo.workdir(), fileName), fileContent); + }) + .then(function() { + return repo.refreshIndex(); + }) + .then(function(indexResult) { + index = indexResult; + }) + .then(function() { + return index.addByPath(fileName); + }) + .then(function() { + return index.write(); + }) + .then(function() { + return index.writeTree(); + }) + .then(function(oidResult) { + treeOid = oidResult; + return NodeGit.Reference.nameToId(repo, "HEAD"); + }) + .then(function(head) { + return repo.getCommit(head); + }) + .then(function(parentResult) { + parent = parentResult; + return Promise.all([ + NodeGit.Signature.create("Foo Bar", "foo@bar.com", 123456789, 60), + NodeGit.Signature.create("Foo A Bar", "foo@bar.com", 987654321, 90) + ]); + }) + .then(function(signatures) { + var author = signatures[0]; + var committer = signatures[1]; + + return repo.createCommitWithSignature( + null, + author, + committer, + "message", + treeOid, + [parent], + onSignature + ); + }) + .then(function(commitId) { + assert.equal(expectedCommitId, commitId); + return NodeGit.Commit.lookup(repo, commitId); + }) + .then(function(commit) { + return commit.getSignature("gpgsig") + .then(function() { + assert.fail("Should not have been able to retrieve gpgsig"); + }, function(error) { + if (error && error.message === "this commit is not signed") { + return; + } + throw error; + }); + }) + .then(function() { + return reinitialize(test); + }, function(reason) { + return reinitialize(test) + .then(function() { + return Promise.reject(reason); + }); + }); + }); + + it("Will throw if the signing cb returns an error code", function() { + const onSignature = () => ({ + code: NodeGit.Error.CODE.ERROR + }); + + var test = this; + var fileName = "newfile.txt"; + var fileContent = "hello world"; + + var repo; + var index; + var treeOid; + var parent; + + return NodeGit.Repository.open(reposPath) + .then(function(repoResult) { + repo = repoResult; + return fse.writeFile(path.join(repo.workdir(), fileName), fileContent); + }) + .then(function() { + return repo.refreshIndex(); + }) + .then(function(indexResult) { + index = indexResult; + }) + .then(function() { + return index.addByPath(fileName); + }) + .then(function() { + return index.write(); + }) + .then(function() { + return index.writeTree(); + }) + .then(function(oidResult) { + treeOid = oidResult; + return NodeGit.Reference.nameToId(repo, "HEAD"); + }) + .then(function(head) { + return repo.getCommit(head); + }) + .then(function(parentResult) { + parent = parentResult; + return Promise.all([ + NodeGit.Signature.create("Foo Bar", "foo@bar.com", 123456789, 60), + NodeGit.Signature.create("Foo A Bar", "foo@bar.com", 987654321, 90) + ]); + }) + .then(function(signatures) { + var author = signatures[0]; + var committer = signatures[1]; + + return repo.createCommitWithSignature( + null, + author, + committer, + "message", + treeOid, + [parent], + onSignature + ); + }) + .then(function() { + assert.fail("createCommitWithSignature should have failed."); + }, function(error) { + if (error && error.errno === NodeGit.Error.CODE.ERROR) { + return; + } + throw error; + }) + .then(function() { + return reinitialize(test); + }, function(reason) { + return reinitialize(test) + .then(function() { + return Promise.reject(reason); + }); + }); + }); }); }); diff --git a/test/tests/rebase.js b/test/tests/rebase.js index f852a8651..839b50582 100644 --- a/test/tests/rebase.js +++ b/test/tests/rebase.js @@ -1661,11 +1661,11 @@ describe("Rebase", function() { return NodeGit.Rebase.init(repository, ourAnnotatedCommit, theirAnnotatedCommit, null, { - signingCb: (signatureBuf, signatureFieldBuf, commitContent) => { - signatureBuf.setString("A moose was here."); - signatureFieldBuf.setString("moose-sig"); - return 0; - } + signingCb: (commitContent) => ({ + code: NodeGit.Error.CODE.OK, + field: "moose-sig", + signedData: "A moose was here." + }) }); }) .then(function(newRebase) { @@ -1725,4 +1725,355 @@ describe("Rebase", function() { assert.equal(signature, "A moose was here."); }); }); + + it("can optionally skip signing commits", function() { + var baseFileName = "baseNewFile.txt"; + var ourFileName = "ourNewFile.txt"; + var theirFileName = "theirNewFile.txt"; + + var baseFileContent = "How do you feel about Toll Roads?"; + var ourFileContent = "I like Toll Roads. I have an EZ-Pass!"; + var theirFileContent = "I'm skeptical about Toll Roads"; + + var ourSignature = NodeGit.Signature.create + ("Ron Paul", "RonPaul@TollRoadsRBest.info", 123456789, 60); + var theirSignature = NodeGit.Signature.create + ("Greg Abbott", "Gregggg@IllTollYourFace.us", 123456789, 60); + + var repository = this.repository; + var ourCommit; + var ourBranch; + var theirBranch; + var rebase; + + return fse.writeFile(path.join(repository.workdir(), baseFileName), + baseFileContent) + // Load up the repository index and make our initial commit to HEAD + .then(function() { + return RepoUtils.addFileToIndex(repository, baseFileName); + }) + .then(function(oid) { + assert.equal(oid.toString(), + "b5cdc109d437c4541a13fb7509116b5f03d5039a"); + + return repository.createCommit("HEAD", ourSignature, + ourSignature, "initial commit", oid, []); + }) + .then(function(commitOid) { + assert.equal(commitOid.toString(), + "be03abdf0353d05924c53bebeb0e5bb129cda44a"); + + return repository.getCommit(commitOid).then(function(commit) { + ourCommit = commit; + }).then(function() { + return repository.createBranch(ourBranchName, commitOid) + .then(function(branch) { + ourBranch = branch; + return repository.createBranch(theirBranchName, commitOid); + }); + }); + }) + .then(function(branch) { + theirBranch = branch; + return fse.writeFile(path.join(repository.workdir(), theirFileName), + theirFileContent); + }) + .then(function() { + return RepoUtils.addFileToIndex(repository, theirFileName); + }) + .then(function(oid) { + assert.equal(oid.toString(), + "be5f0fd38a39a67135ad68921c93cd5c17fefb3d"); + + return repository.createCommit(theirBranch.name(), theirSignature, + theirSignature, "they made a commit", oid, [ourCommit]); + }) + .then(function(commitOid) { + assert.equal(commitOid.toString(), + "e9ebd92f2f4778baf6fa8e92f0c68642f931a554"); + + return removeFileFromIndex(repository, theirFileName); + }) + .then(function() { + return fse.remove(path.join(repository.workdir(), theirFileName)); + }) + .then(function() { + return fse.writeFile(path.join(repository.workdir(), ourFileName), + ourFileContent); + }) + .then(function() { + return RepoUtils.addFileToIndex(repository, ourFileName); + }) + .then(function(oid) { + assert.equal(oid.toString(), + "77867fc0bfeb3f80ab18a78c8d53aa3a06207047"); + + return repository.createCommit(ourBranch.name(), ourSignature, + ourSignature, "we made a commit", oid, [ourCommit]); + }) + .then(function(commitOid) { + assert.equal(commitOid.toString(), + "e7f37ee070837052937e24ad8ba66f6d83ae7941"); + + return removeFileFromIndex(repository, ourFileName); + }) + .then(function() { + return fse.remove(path.join(repository.workdir(), ourFileName)); + }) + .then(function() { + return repository.checkoutBranch(ourBranchName); + }) + .then(function() { + return Promise.all([ + repository.getReference(ourBranchName), + repository.getReference(theirBranchName) + ]); + }) + .then(function(refs) { + assert.equal(refs.length, 2); + + return Promise.all([ + NodeGit.AnnotatedCommit.fromRef(repository, refs[0]), + NodeGit.AnnotatedCommit.fromRef(repository, refs[1]) + ]); + }) + .then(function(annotatedCommits) { + assert.equal(annotatedCommits.length, 2); + + var ourAnnotatedCommit = annotatedCommits[0]; + var theirAnnotatedCommit = annotatedCommits[1]; + + assert.equal(ourAnnotatedCommit.id().toString(), + "e7f37ee070837052937e24ad8ba66f6d83ae7941"); + assert.equal(theirAnnotatedCommit.id().toString(), + "e9ebd92f2f4778baf6fa8e92f0c68642f931a554"); + + return NodeGit.Rebase.init(repository, ourAnnotatedCommit, + theirAnnotatedCommit, null, { + signingCb: () => ({ + code: NodeGit.Error.CODE.PASSTHROUGH + }) + }); + }) + .then(function(newRebase) { + rebase = newRebase; + + // there should only be 1 rebase operation to perform + assert.equal(rebase.operationEntrycount(), 1); + + return rebase.next(); + }) + .then(function(rebaseOperation) { + assert.equal(rebaseOperation.type(), + NodeGit.RebaseOperation.REBASE_OPERATION.PICK); + assert.equal(rebaseOperation.id().toString(), + "e7f37ee070837052937e24ad8ba66f6d83ae7941"); + + // Make sure we don't crash calling the signature CB + // after collecting garbage. + garbageCollect(); + + return rebase.commit(null, ourSignature); + }) + .then(function(commitOid) { + assert.equal(commitOid.toString(), + "b937100ee0ea17ef20525306763505a7fe2be29e"); + + // git_rebase_operation_current returns the index of the rebase + // operation that was last applied, so after the first operation, it + // should be 0. + assert.equal(rebase.operationCurrent(), 0); + + return rebase.finish(ourSignature, {}); + }) + .then(function(result) { + assert.equal(result, 0); + + return repository.getBranchCommit(ourBranchName); + }) + .then(function(commit) { + // verify that the "ours" branch has moved to the correct place + assert.equal(commit.id().toString(), + "b937100ee0ea17ef20525306763505a7fe2be29e"); + + return commit.parent(0); + }) + .then(function(parent) { + // verify that we are on top of "their commit" + assert.equal(parent.id().toString(), + "e9ebd92f2f4778baf6fa8e92f0c68642f931a554"); + return NodeGit.Commit.extractSignature( + repository, + "b937100ee0ea17ef20525306763505a7fe2be29e", + "moose-sig" + ) + .then(function() { + assert.fail("This commit should not be signed."); + }, function (error) { + if (error && error.message === "this commit is not signed") { + return; + } + throw error; + }); + }); + }); + + it("will throw if commit signing cb returns an error code", function() { + var baseFileName = "baseNewFile.txt"; + var ourFileName = "ourNewFile.txt"; + var theirFileName = "theirNewFile.txt"; + + var baseFileContent = "How do you feel about Toll Roads?"; + var ourFileContent = "I like Toll Roads. I have an EZ-Pass!"; + var theirFileContent = "I'm skeptical about Toll Roads"; + + var ourSignature = NodeGit.Signature.create + ("Ron Paul", "RonPaul@TollRoadsRBest.info", 123456789, 60); + var theirSignature = NodeGit.Signature.create + ("Greg Abbott", "Gregggg@IllTollYourFace.us", 123456789, 60); + + var repository = this.repository; + var ourCommit; + var ourBranch; + var theirBranch; + var rebase; + + return fse.writeFile(path.join(repository.workdir(), baseFileName), + baseFileContent) + // Load up the repository index and make our initial commit to HEAD + .then(function() { + return RepoUtils.addFileToIndex(repository, baseFileName); + }) + .then(function(oid) { + assert.equal(oid.toString(), + "b5cdc109d437c4541a13fb7509116b5f03d5039a"); + + return repository.createCommit("HEAD", ourSignature, + ourSignature, "initial commit", oid, []); + }) + .then(function(commitOid) { + assert.equal(commitOid.toString(), + "be03abdf0353d05924c53bebeb0e5bb129cda44a"); + + return repository.getCommit(commitOid).then(function(commit) { + ourCommit = commit; + }).then(function() { + return repository.createBranch(ourBranchName, commitOid) + .then(function(branch) { + ourBranch = branch; + return repository.createBranch(theirBranchName, commitOid); + }); + }); + }) + .then(function(branch) { + theirBranch = branch; + return fse.writeFile(path.join(repository.workdir(), theirFileName), + theirFileContent); + }) + .then(function() { + return RepoUtils.addFileToIndex(repository, theirFileName); + }) + .then(function(oid) { + assert.equal(oid.toString(), + "be5f0fd38a39a67135ad68921c93cd5c17fefb3d"); + + return repository.createCommit(theirBranch.name(), theirSignature, + theirSignature, "they made a commit", oid, [ourCommit]); + }) + .then(function(commitOid) { + assert.equal(commitOid.toString(), + "e9ebd92f2f4778baf6fa8e92f0c68642f931a554"); + + return removeFileFromIndex(repository, theirFileName); + }) + .then(function() { + return fse.remove(path.join(repository.workdir(), theirFileName)); + }) + .then(function() { + return fse.writeFile(path.join(repository.workdir(), ourFileName), + ourFileContent); + }) + .then(function() { + return RepoUtils.addFileToIndex(repository, ourFileName); + }) + .then(function(oid) { + assert.equal(oid.toString(), + "77867fc0bfeb3f80ab18a78c8d53aa3a06207047"); + + return repository.createCommit(ourBranch.name(), ourSignature, + ourSignature, "we made a commit", oid, [ourCommit]); + }) + .then(function(commitOid) { + assert.equal(commitOid.toString(), + "e7f37ee070837052937e24ad8ba66f6d83ae7941"); + + return removeFileFromIndex(repository, ourFileName); + }) + .then(function() { + return fse.remove(path.join(repository.workdir(), ourFileName)); + }) + .then(function() { + return repository.checkoutBranch(ourBranchName); + }) + .then(function() { + return Promise.all([ + repository.getReference(ourBranchName), + repository.getReference(theirBranchName) + ]); + }) + .then(function(refs) { + assert.equal(refs.length, 2); + + return Promise.all([ + NodeGit.AnnotatedCommit.fromRef(repository, refs[0]), + NodeGit.AnnotatedCommit.fromRef(repository, refs[1]) + ]); + }) + .then(function(annotatedCommits) { + assert.equal(annotatedCommits.length, 2); + + var ourAnnotatedCommit = annotatedCommits[0]; + var theirAnnotatedCommit = annotatedCommits[1]; + + assert.equal(ourAnnotatedCommit.id().toString(), + "e7f37ee070837052937e24ad8ba66f6d83ae7941"); + assert.equal(theirAnnotatedCommit.id().toString(), + "e9ebd92f2f4778baf6fa8e92f0c68642f931a554"); + + return NodeGit.Rebase.init(repository, ourAnnotatedCommit, + theirAnnotatedCommit, null, { + signingCb: () => ({ + code: NodeGit.Error.CODE.ERROR + }) + }); + }) + .then(function(newRebase) { + rebase = newRebase; + + // there should only be 1 rebase operation to perform + assert.equal(rebase.operationEntrycount(), 1); + + return rebase.next(); + }) + .then(function(rebaseOperation) { + assert.equal(rebaseOperation.type(), + NodeGit.RebaseOperation.REBASE_OPERATION.PICK); + assert.equal(rebaseOperation.id().toString(), + "e7f37ee070837052937e24ad8ba66f6d83ae7941"); + + // Make sure we don't crash calling the signature CB + // after collecting garbage. + garbageCollect(); + + return rebase.commit(null, ourSignature); + }) + .then(function() { + assert.fail("rebase.commit should have failed"); + }, function(error) { + if (error && error.errno === -1) { + return; + } + throw error; + }); + }); }); diff --git a/test/tests/tag.js b/test/tests/tag.js index c43a618a1..51268b40a 100644 --- a/test/tests/tag.js +++ b/test/tests/tag.js @@ -314,44 +314,150 @@ describe("Tag", function() { }); }); - it("can create a tag with a signature and extract the signature", function() { - const targetOid = Oid.fromString(commitPointedTo); - const otherTargetOid = Oid.fromString(commitPointedTo2); - const name = "created-signed-tag-annotationCreate"; - const repository = this.repository; - const signature = Signature.create( - "Shaggy Rogers", - "shaggy@mystery.com", - 987654321, - 90 + describe("createWithSignature and extractSignature", function() { + it( + "can create a tag with a signature and extract the signature", + function() { + const targetOid = Oid.fromString(commitPointedTo); + const otherTargetOid = Oid.fromString(commitPointedTo2); + const name = "created-signed-tag-annotationCreate"; + const repository = this.repository; + const signature = Signature.create( + "Shaggy Rogers", + "shaggy@mystery.com", + 987654321, + 90 + ); + const signatureLines = [ + "-----BEGIN PGP SIGNATURE-----", + "iQIzBAABCAAdFiEEKdxGpJ93wnkLaBKfURjJKedOfEMFAlxR4JUACgkQURjJKedO", + "fEN+8A//cXmkRmhzQMdTEdrxty7tVKQ7lVhL7r7e+cB84hO7WrDn8549c7/Puflu", + "idanWfyoAEMSNWDgY84lx/t3I3YYKXsLDPT93HiMhCXmPVZcfLxlARRL1rrNZV4q", + "L9hhqb9bFrRNBn6YebhygeLXLHlDKEZzx8W9jnDLU8Px8UTkwdQIDnPDfT7UOPPU", + "MYDgP3OwWwoG8dUlZXaHjtFz29wPlJo177MwdLYwn4zpEIysoY1ev5IKWD+LPW4g", + "vdQnaK1x3dozmG8YLUZw5iW7ap9DpahbAGQgdy1z1ypiNUjNuhaP8zkG1ci6X88N", + "6MIoQ+YqfowRJJTIr1lzssxsRI1syjfS6smnI4ZNE6S+6mIKN96ES2OZF+rn4xnD", + "PofR9Qh2gPq++ULriPE/cX7ZkZ0/ZDZGDfIGvricB8JEJhISZn/VMX/KScJs+rFq", + "KWN5Au6Uc2pEqeq5OP4y2k0QUmKQT9sh9OepnPmfqF8hG6wI8nM67jT/FEOcpr0v", + "qoN2NRXrcq3iZAp07AGq9IdpYhBcEW7MFmOcNt+Zb8SbTMp6DawnREg9xzz1SIkZ", + "Cdp1XoJ6mkVvzBB4T/Esp7j1VztinTX2PpX7C1CE5LC76UfCiEjEWOmWrVuPuA5a", + "oRrJvgPJg8gpVj04r2m8nvUK1gwhxg9ZB+SK+nd3OAd0dnbJwTE=", + "=dW3g", + "-----END PGP SIGNATURE-----" + ]; + const message = "I'm a teapot"; + const signingCallback = (message) => ({ + code: NodeGit.Error.CODE.OK, + signedData: signatureLines.join("\n") + }); + + let odb; + let oid; + let object; + + return repository.odb() + .then((odbResult) => { + odb = odbResult; + + return Tag.createWithSignature( + repository, + name, + targetOid, + signature, + message, + 1, + signingCallback + ); + }) + .then((oidResult) => { + oid = oidResult; + return odb.read(oid); + }) + .then((objectResult) => { + object = objectResult; + const lines = object.toString().split("\n"); + assert(object.type(), Obj.TYPE.TAG); + assert.equal(signatureLines.length + 7, lines.length); + assert.equal(lines[0], `object ${commitPointedTo}`); + assert.equal(lines[1], "type commit"); + assert.equal(lines[2], `tag ${name}`); + assert.equal( + lines[3], + "tagger Shaggy Rogers 987654321 +0130" + ); + assert.equal(lines[4], ""); + assert.equal(lines[5], message); + for (let i = 6; i < 6 + signatureLines.length; i++) { + assert.equal(lines[i], signatureLines[i - 6]); + } + assert.equal(lines[6 + signatureLines.length], ""); + + return Tag.lookup(repository, oid); + }) + .then((tag) => { + return tag.extractSignature(); + }) + .then((tagSignature) => { + assert.equal(tagSignature, signatureLines.join("\n")); + }) + .then(() => { + // overwriting is okay + return Tag.createWithSignature( + repository, + name, + targetOid, + signature, + message, + 1, + signingCallback + ); + }) + .then(() => { + // overwriting is not okay + return Tag.createWithSignature( + repository, + name, + otherTargetOid, + signature, + message, + 0, + signingCallback + ); + }) + .then(() => { + return Promise.reject( + new Error( + "should not be able to create the '" + name + "' tag twice" + ) + ); + }, + () => { + return Promise.resolve(); + }); + } ); - const signatureLines = [ - "-----BEGIN PGP SIGNATURE-----", - "iQIzBAABCAAdFiEEKdxGpJ93wnkLaBKfURjJKedOfEMFAlxR4JUACgkQURjJKedO", - "fEN+8A//cXmkRmhzQMdTEdrxty7tVKQ7lVhL7r7e+cB84hO7WrDn8549c7/Puflu", - "idanWfyoAEMSNWDgY84lx/t3I3YYKXsLDPT93HiMhCXmPVZcfLxlARRL1rrNZV4q", - "L9hhqb9bFrRNBn6YebhygeLXLHlDKEZzx8W9jnDLU8Px8UTkwdQIDnPDfT7UOPPU", - "MYDgP3OwWwoG8dUlZXaHjtFz29wPlJo177MwdLYwn4zpEIysoY1ev5IKWD+LPW4g", - "vdQnaK1x3dozmG8YLUZw5iW7ap9DpahbAGQgdy1z1ypiNUjNuhaP8zkG1ci6X88N", - "6MIoQ+YqfowRJJTIr1lzssxsRI1syjfS6smnI4ZNE6S+6mIKN96ES2OZF+rn4xnD", - "PofR9Qh2gPq++ULriPE/cX7ZkZ0/ZDZGDfIGvricB8JEJhISZn/VMX/KScJs+rFq", - "KWN5Au6Uc2pEqeq5OP4y2k0QUmKQT9sh9OepnPmfqF8hG6wI8nM67jT/FEOcpr0v", - "qoN2NRXrcq3iZAp07AGq9IdpYhBcEW7MFmOcNt+Zb8SbTMp6DawnREg9xzz1SIkZ", - "Cdp1XoJ6mkVvzBB4T/Esp7j1VztinTX2PpX7C1CE5LC76UfCiEjEWOmWrVuPuA5a", - "oRrJvgPJg8gpVj04r2m8nvUK1gwhxg9ZB+SK+nd3OAd0dnbJwTE=", - "=dW3g", - "-----END PGP SIGNATURE-----" - ]; - const message = "I'm a teapot"; - const signingCallback = (message) => { - return signatureLines.join("\n"); - }; - let odb; - let oid; - let object; + it("can optionally skip the signing process", function() { + const targetOid = Oid.fromString(commitPointedTo); + const otherTargetOid = Oid.fromString(commitPointedTo2); + const name = "created-signed-tag-annotationCreate"; + const repository = this.repository; + const signature = Signature.create( + "Shaggy Rogers", + "shaggy@mystery.com", + 987654321, + 90 + ); + const message = "I'm a teapot"; + const signingCallback = () => ({ + code: NodeGit.Error.CODE.PASSTHROUGH + }); - return repository.odb() + let odb; + let oid; + let object; + + return repository.odb() .then((odbResult) => { odb = odbResult; @@ -373,7 +479,7 @@ describe("Tag", function() { object = objectResult; const lines = object.toString().split("\n"); assert(object.type(), Obj.TYPE.TAG); - assert.equal(signatureLines.length + 7, lines.length); + assert.equal(7, lines.length); assert.equal(lines[0], `object ${commitPointedTo}`); assert.equal(lines[1], "type commit"); assert.equal(lines[2], `tag ${name}`); @@ -383,18 +489,21 @@ describe("Tag", function() { ); assert.equal(lines[4], ""); assert.equal(lines[5], message); - for (let i = 6; i < 6 + signatureLines.length; i++) { - assert.equal(lines[i], signatureLines[i - 6]); - } - assert.equal(lines[6 + signatureLines.length], ""); + assert.equal(lines[6], ""); return Tag.lookup(repository, oid); }) .then((tag) => { return tag.extractSignature(); }) - .then((tagSignature) => { - assert.equal(tagSignature, signatureLines.join("\n")); + .then(function() { + assert.fail("Tag should not have been signed."); + }, function(error) { + if (error && error.message === "this tag is not signed") { + return; + } + + throw error; }) .then(() => { // overwriting is okay @@ -428,8 +537,45 @@ describe("Tag", function() { () => { return Promise.resolve(); }); + }); + + it("will throw if signing callback returns an error code", function() { + const targetOid = Oid.fromString(commitPointedTo); + const name = "created-signed-tag-annotationCreate"; + const repository = this.repository; + const signature = Signature.create( + "Shaggy Rogers", + "shaggy@mystery.com", + 987654321, + 90 + ); + const message = "I'm a teapot"; + const signingCallback = () => ({ + code: NodeGit.Error.CODE.ERROR + }); + + + return Tag.createWithSignature( + repository, + name, + targetOid, + signature, + message, + 1, + signingCallback + ) + .then(function() { + assert.fail("Should not have been able to create tag"); + }, function(error) { + if (error && error.errno === NodeGit.Error.CODE.ERROR) { + return; + } + throw error; + }); + }); }); + it("can create a new signed tag with Tag.annotationCreate", function() { var oid = Oid.fromString(commitPointedTo); var name = "created-signed-tag-annotationCreate"; From 4ee0ca9c7c5ca68a6e8893db3f6289354e64d5bd Mon Sep 17 00:00:00 2001 From: Tyler Wanek Date: Tue, 5 Feb 2019 12:53:56 -0700 Subject: [PATCH 2/2] Use enum here for consistency in test --- test/tests/rebase.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/tests/rebase.js b/test/tests/rebase.js index 839b50582..610721185 100644 --- a/test/tests/rebase.js +++ b/test/tests/rebase.js @@ -2070,7 +2070,7 @@ describe("Rebase", function() { .then(function() { assert.fail("rebase.commit should have failed"); }, function(error) { - if (error && error.errno === -1) { + if (error && error.errno === NodeGit.Error.CODE.ERROR) { return; } throw error;