Skip to content

Commit 177ef4f

Browse files
committed
Add methods to create a signed commit
First you need to create a buffer which you can apply the signature function to. You can then create the commit object the data and its signature.
1 parent 83f0a77 commit 177ef4f

File tree

4 files changed

+178
-7
lines changed

4 files changed

+178
-7
lines changed

LibGit2Sharp.Tests/CommitFixture.cs

Lines changed: 51 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1047,10 +1047,7 @@ public void CanNotAmendACommitInAWayThatWouldLeadTheNewCommitToBecomeEmpty()
10471047
}
10481048
}
10491049

1050-
[Fact]
1051-
public void CanExtractSignatureFromCommit()
1052-
{
1053-
string commitData = @"tree 6b79e22d69bf46e289df0345a14ca059dfc9bdf6
1050+
private readonly string signedCommit = @"tree 6b79e22d69bf46e289df0345a14ca059dfc9bdf6
10541051
parent 34734e478d6cf50c27c9d69026d93974d052c454
10551052
author Ben Burkert <ben@benburkert.com> 1358451456 -0800
10561053
committer Ben Burkert <ben@benburkert.com> 1358451456 -0800
@@ -1075,7 +1072,7 @@ committer Ben Burkert <ben@benburkert.com> 1358451456 -0800
10751072
a simple commit which works
10761073
";
10771074

1078-
string signatureData = @"-----BEGIN PGP SIGNATURE-----
1075+
private readonly string signatureData = @"-----BEGIN PGP SIGNATURE-----
10791076
Version: GnuPG v1.4.12 (Darwin)
10801077
10811078
iQIcBAABAgAGBQJQ+FMIAAoJEH+LfPdZDSs1e3EQAJMjhqjWF+WkGLHju7pTw2al
@@ -1093,19 +1090,24 @@ a simple commit which works
10931090
=ozeK
10941091
-----END PGP SIGNATURE-----";
10951092

1096-
string signedData = @"tree 6b79e22d69bf46e289df0345a14ca059dfc9bdf6
1093+
private readonly string signedData = @"tree 6b79e22d69bf46e289df0345a14ca059dfc9bdf6
10971094
parent 34734e478d6cf50c27c9d69026d93974d052c454
10981095
author Ben Burkert <ben@benburkert.com> 1358451456 -0800
10991096
committer Ben Burkert <ben@benburkert.com> 1358451456 -0800
11001097
11011098
a simple commit which works
11021099
";
11031100

1101+
1102+
1103+
[Fact]
1104+
public void CanExtractSignatureFromCommit()
1105+
{
11041106
string repoPath = InitNewRepository();
11051107
using (var repo = new Repository(repoPath))
11061108
{
11071109
var odb = repo.ObjectDatabase;
1108-
var signedId = odb.Write<Commit>(Encoding.UTF8.GetBytes(commitData));
1110+
var signedId = odb.Write<Commit>(Encoding.UTF8.GetBytes(signedCommit));
11091111

11101112
// Look up the commit to make sure we wrote something valid
11111113
var commit = repo.Lookup<Commit>(signedId);
@@ -1114,6 +1116,48 @@ a simple commit which works
11141116
var signatureInfo = Commit.ExtractSignature(repo, signedId, "gpgsig");
11151117
Assert.Equal(signedData, signatureInfo.SignedData);
11161118
Assert.Equal(signatureData, signatureInfo.Signature);
1119+
1120+
signatureInfo = Commit.ExtractSignature(repo, signedId);
1121+
Assert.Equal(signedData, signatureInfo.SignedData);
1122+
Assert.Equal(signatureData, signatureInfo.Signature);
1123+
}
1124+
}
1125+
1126+
[Fact]
1127+
public void CanCreateACommitString()
1128+
{
1129+
string repoPath = SandboxStandardTestRepo();
1130+
using (var repo = new Repository(repoPath))
1131+
{
1132+
var tipCommit = repo.Head.Tip;
1133+
var recreatedCommit = repo.ObjectDatabase.CreateCommitBuffer(
1134+
tipCommit.Author,
1135+
tipCommit.Committer,
1136+
tipCommit.Message,
1137+
tipCommit.Tree,
1138+
tipCommit.Parents,
1139+
false, null);
1140+
1141+
var recreatedId = repo.ObjectDatabase.Write<Commit>(Encoding.UTF8.GetBytes(recreatedCommit));
1142+
Assert.Equal(tipCommit.Id, recreatedId);
1143+
}
1144+
}
1145+
1146+
[Fact]
1147+
public void CanCreateASignedCommit()
1148+
{
1149+
string repoPath = InitNewRepository();
1150+
using (var repo = new Repository(repoPath))
1151+
{
1152+
var odb = repo.ObjectDatabase;
1153+
var signedId = odb.Write<Commit>(Encoding.UTF8.GetBytes(signedCommit));
1154+
var signedId2 = odb.CreateCommitWithSignature(signedData, signatureData);
1155+
1156+
Assert.Equal(signedId, signedId2);
1157+
1158+
var signatureInfo = Commit.ExtractSignature(repo, signedId2);
1159+
Assert.Equal(signedData, signatureInfo.SignedData);
1160+
Assert.Equal(signatureData, signatureInfo.Signature);
11171161
}
11181162
}
11191163
}

LibGit2Sharp/Core/NativeMethods.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,27 @@ internal static extern unsafe int git_commit_create_from_ids(
316316
UIntPtr parentCount,
317317
[MarshalAs(UnmanagedType.LPArray)] [In] IntPtr[] parents);
318318

319+
[DllImport(libgit2)]
320+
internal static extern unsafe int git_commit_create_buffer(
321+
GitBuf res,
322+
git_repository* repo,
323+
git_signature* author,
324+
git_signature* committer,
325+
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string encoding,
326+
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string message,
327+
git_object* tree,
328+
UIntPtr parent_count,
329+
IntPtr* parents /* git_commit** originally */);
330+
331+
[DllImport(libgit2)]
332+
internal static extern unsafe int git_commit_create_with_signature(
333+
out GitOid id,
334+
git_repository* repo,
335+
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string commit_content,
336+
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string signature,
337+
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string signature_field);
338+
339+
319340
[DllImport(libgit2)]
320341
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(LaxUtf8NoCleanupMarshaler))]
321342
internal static extern unsafe string git_commit_message(git_object* commit);

LibGit2Sharp/Core/Proxy.cs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,48 @@ public static unsafe ObjectId git_commit_create(
388388
}
389389
}
390390

391+
public static unsafe string git_commit_create_buffer(
392+
RepositoryHandle repo,
393+
Signature author,
394+
Signature committer,
395+
string message,
396+
ObjectHandle tree,
397+
ObjectHandle[] parents)
398+
{
399+
using (SignatureHandle authorHandle = author.BuildHandle())
400+
using (SignatureHandle committerHandle = committer.BuildHandle())
401+
using (var buf = new GitBuf())
402+
{
403+
var ptrs = parents.Select(p => p.AsIntPtr()).ToArray();
404+
int res;
405+
fixed(IntPtr* objs = ptrs)
406+
{
407+
res = NativeMethods.git_commit_create_buffer(buf,
408+
repo,
409+
authorHandle,
410+
committerHandle,
411+
null,
412+
message,
413+
tree,
414+
new UIntPtr((ulong)parents.LongCount()),
415+
objs);
416+
}
417+
Ensure.ZeroResult(res);
418+
419+
return LaxUtf8Marshaler.FromNative(buf.ptr);
420+
}
421+
}
422+
423+
public static unsafe ObjectId git_commit_create_with_signature(RepositoryHandle repo, string commitContent,
424+
string signature, string field)
425+
{
426+
GitOid id;
427+
int res = NativeMethods.git_commit_create_with_signature(out id, repo, commitContent, signature, field);
428+
Ensure.ZeroResult(res);
429+
430+
return id;
431+
}
432+
391433
public static unsafe string git_commit_message(ObjectHandle obj)
392434
{
393435
return NativeMethods.git_commit_message(obj);

LibGit2Sharp/ObjectDatabase.cs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,70 @@ public virtual Commit CreateCommit(Signature author, Signature committer, string
422422
return commit;
423423
}
424424

425+
/// <summary>
426+
/// Create a commit in-memory but do not write it to the object database.
427+
/// <para>
428+
/// Prettifing the message includes:
429+
/// * Removing empty lines from the beginning and end.
430+
/// * Removing trailing spaces from every line.
431+
/// * Turning multiple consecutive empty lines between paragraphs into just one empty line.
432+
/// * Ensuring the commit message ends with a newline.
433+
/// * Removing every line starting with the <paramref name="commentChar"/>.
434+
/// </para>
435+
/// </summary>
436+
/// <param name="author">The <see cref="Signature"/> of who made the change.</param>
437+
/// <param name="committer">The <see cref="Signature"/> of who added the change to the repository.</param>
438+
/// <param name="message">The description of why a change was made to the repository.</param>
439+
/// <param name="tree">The <see cref="Tree"/> of the <see cref="Commit"/> to be created.</param>
440+
/// <param name="parents">The parents of the <see cref="Commit"/> to be created.</param>
441+
/// <param name="prettifyMessage">True to prettify the message, or false to leave it as is.</param>
442+
/// <param name="commentChar">When non null, lines starting with this character will be stripped if prettifyMessage is true.</param>
443+
/// <returns>The contents of the commit object.</returns>
444+
public virtual string CreateCommitBuffer(Signature author, Signature committer, string message, Tree tree, IEnumerable<Commit> parents, bool prettifyMessage, char? commentChar)
445+
{
446+
Ensure.ArgumentNotNull(message, "message");
447+
Ensure.ArgumentDoesNotContainZeroByte(message, "message");
448+
Ensure.ArgumentNotNull(author, "author");
449+
Ensure.ArgumentNotNull(committer, "committer");
450+
Ensure.ArgumentNotNull(tree, "tree");
451+
Ensure.ArgumentNotNull(parents, "parents");
452+
453+
if (prettifyMessage)
454+
{
455+
message = Proxy.git_message_prettify(message, commentChar);
456+
}
457+
var treeHandle = Proxy.git_object_lookup(repo.Handle, tree.Id, GitObjectType.Tree);
458+
var handles = parents.Select(c => Proxy.git_object_lookup(repo.Handle, c.Id, GitObjectType.Commit));
459+
460+
return Proxy.git_commit_create_buffer(repo.Handle, author, committer, message, treeHandle, handles.ToArray());
461+
}
462+
463+
/// <summary>
464+
/// Inserts a <see cref="Commit"/> into the object database after attaching the given signature.
465+
/// </summary>
466+
/// <param name="commitContent">The raw unsigned commit</param>
467+
/// <param name="signature">The signature data </param>
468+
/// <param name="field">The header field in the commit in which to store the signature</param>
469+
/// <returns>The created <see cref="Commit"/>.</returns>
470+
public virtual ObjectId CreateCommitWithSignature(string commitContent, string signature, string field)
471+
{
472+
return Proxy.git_commit_create_with_signature(repo.Handle, commitContent, signature, field);
473+
}
474+
475+
/// <summary>
476+
/// Inserts a <see cref="Commit"/> into the object database after attaching the given signature.
477+
/// <para>
478+
/// This overload uses the default header field of "gpgsig"
479+
/// </para>
480+
/// </summary>
481+
/// <param name="commitContent">The raw unsigned commit</param>
482+
/// <param name="signature">The signature data </param>
483+
/// <returns>The created <see cref="Commit"/>.</returns>
484+
public virtual ObjectId CreateCommitWithSignature(string commitContent, string signature)
485+
{
486+
return Proxy.git_commit_create_with_signature(repo.Handle, commitContent, signature, null);
487+
}
488+
425489
/// <summary>
426490
/// Inserts a <see cref="TagAnnotation"/> into the object database, pointing to a specific <see cref="GitObject"/>.
427491
/// </summary>

0 commit comments

Comments
 (0)