8000 Add methods to create a signed commit · MustafaJamal/libgit2sharp@508807f · GitHub
[go: up one dir, main page]

Skip to content

Commit 508807f

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 73aa605 commit 508807f

File tree

6 files changed

+189
-8
lines changed

6 files changed

+189
-8
lines changed

LibGit2Sharp.Tests/CommitFixture.cs

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1057,10 +1057,7 @@ public void CanPrettifyAMessage()
10571057
Assert.Equal(expected, Commit.PrettifyMessage(input.Replace('#', ';'), ';'));
10581058
}
10591059

1060-
[Fact]
1061-
public void CanExtractSignatureFromCommit()
1062-
{
1063-
string commitData = @"tree 6b79e22d69bf46e289df0345a14ca059dfc9bdf6
1060+
private readonly string signedCommit = @"tree 6b79e22d69bf46e289df0345a14ca059dfc9bdf6
10641061
parent 34734e478d6cf50c27c9d69026d93974d052c454
10651062
author Ben Burkert <ben@benburkert.com> 1358451456 -0800
10661063
committer Ben Burkert <ben@benburkert.com> 1358451456 -0800
@@ -1085,7 +1082,7 @@ committer Ben Burkert <ben@benburkert.com> 1358451456 -0800
10851082
a simple commit which works
10861083
";
10871084

1088-
string signatureData = @"-----BEGIN PGP SIGNATURE-----
1085+
private readonly string signatureData = @"-----BEGIN PGP SIGNATURE-----
10891086
Version: GnuPG v1.4.12 (Darwin)
10901087
10911088
iQIcBAABAgAGBQJQ+FMIAAoJEH+LfPdZDSs1e3EQAJMjhqjWF+WkGLHju7pTw2al
@@ -1103,19 +1100,23 @@ a simple commit which works
11031100
=ozeK
11041101
-----END PGP SIGNATURE-----";
11051102

1106-
string signedData = @"tree 6b79e22d69bf46e289df0345a14ca059dfc9bdf6
1103+
private readonly string signedData = @"tree 6b79e22d69bf46e289df0345a14ca059dfc9bdf6
11071104
parent 34734e478d6cf50c27c9d69026d93974d052c454
11081105
author Ben Burkert <ben@benburkert.com> 1358451456 -0800
11091106
committer Ben Burkert <ben@benburkert.com> 1358451456 -0800
11101107
11111108
a simple commit which works
11121109
";
11131110

1111+
1112+
[Fact]
1113+
public void CanExtractSignatureFromCommit()
1114+
{
11141115
string repoPath = InitNewRepository();
11151116
using (var repo = new Repository(repoPath))
11161117
{
11171118
var odb = repo.ObjectDatabase;
1118-
var signedId = odb.Write<Commit>(Encoding.UTF8.GetBytes(commitData));
1119+
var signedId = odb.Write<Commit>(Encoding.UTF8.GetBytes(signedCommit));
11191120

11201121
// Look up the commit to make sure we wrote something valid
11211122
var commit = repo.Lookup<Commit>(signedId);
@@ -1124,6 +1125,48 @@ a simple commit which works
11241125
var signatureInfo = Commit.ExtractSignature(repo, signedId, "gpgsig");
11251126
Assert.Equal(signedData, signatureInfo.SignedData);
11261127
Assert.Equal(signatureData, signatureInfo.Signature);
1128+
1129+
signatureInfo = Commit.ExtractSignature(repo, signedId);
1130+
Assert.Equal(signedData, signatureInfo.SignedData);
1131+
Assert.Equal(signatureData, signatureInfo.Signature);
1132+
}
1133+
}
1134+
1135+
[Fact]
1136+
public void CanCreateACommitString()
1137+
{
1138+
string repoPath = SandboxStandardTestRepo();
1139+
using (var repo = new Repository(repoPath))
1140+
{
1141+
var tipCommit = repo.Head.Tip;
1142+
var recreatedCommit = Commit.CreateBuffer(
1143+
tipCommit.Author,
1144+
tipCommit.Committer,
1145+
tipCommit.Message,
1146+
tipCommit.Tree,
1147+
tipCommit.Parents,
1148+
false, null);
1149+
1150+
var recreatedId = repo.ObjectDatabase.Write<Commit>(Encoding.UTF8.GetBytes(recreatedCommit));
1151+
Assert.Equal(tipCommit.Id, recreatedId);
1152+
}
1153+
}
1154+
1155+
[Fact]
1156+
public void CanCreateASignedCommit()
1157+
{
1158+
string repoPath = InitNewRepository();
1159+
using (var repo = new Repository(repoPath))
1160+
{
1161+
var odb = repo.ObjectDatabase;
1162+
var signedId = odb.Write<Commit>(Encoding.UTF8.GetBytes(signedCommit));
1163+
var signedId2 = odb.CreateCommitWithSignature(signedData, signatureData);
1164+
1165+
Assert.Equal(signedId, signedId2);
1166+
1167+
var signatureInfo = Commit.ExtractSignature(repo, signedId2);
1168+
Assert.Equal(signedData, signatureInfo.SignedData);
1169+
Assert.Equal(signatureData, signatureInfo.Signature);
11271170
}
11281171
}
11291172
}

LibGit2Sharp/Commit.cs

Lines changed: 36 additions & 0 deletions
< 10000 td data-grid-cell-id="diff-b2f28cc1a02ee0e036a6bd8ea2cd52d7b977657436dd7e1512da86cfb28a43bd-166-189-1" data-selected="false" role="gridcell" style="background-color:var(--diffBlob-additionNum-bgColor, var(--diffBlob-addition-bgColor-num));text-align:center" tabindex="-1" valign="top" class="focusable-grid-cell diff-line-number position-relative left-side">189
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,42 @@ public static SignatureInfo ExtractSignature(Repository repo, ObjectId id)
164164
return Proxy.git_commit_extract_signature(repo.Handle, id, null);
165165
}
166166

167+
/// <summary>
168+
/// Create a commit in-memory
169+
/// <para>
170+
/// Prettifing the message includes:
171+
/// * Removing empty lines from the beginning and end.
172+
/// * Removing trailing spaces from every line.
173+
/// * Turning multiple consecutive empty lines between paragraphs into just one empty line.
174+
/// * Ensuring the commit message ends with a newline.
175+
/// * Removing every line starting with the <paramref name="commentChar"/>.
176+
/// </para>
177+
/// </summary>
178+
/// <param name="author">The <see cref="Signature"/> of who made the change.</param>
179+
/// <param name="committer">The <see cref="Signature"/> of who added the change to the repository.</param>
180+
/// <param name="message">The description of why a change was made to the repository.</param>
181+
/// <param name="tree">The <see cref="Tree"/> of the <see cref="Commit"/> to be created.</param>
182+
/// <param name="parents">The parents of the <see cref="Commit"/> to be created.</param>
183+
/// <param name="prettifyMessage">True to prettify the message, or false to leave it as is.</param>
184+
/// <param name="commentChar">When non null, lines starting with this character will be stripped if prettifyMessage is true.</param>
185+
/// <returns>The contents of the commit object.</returns>
186+
public static string CreateBuffer(Signature author, Signature committer, string message, Tree tree, IEnumerable<Commit> parents, bool prettifyMessage, char? commentChar)
187+
{
188+
Ensure.ArgumentNotNull(message, "message");
+
Ensure.ArgumentDoesNotContainZeroByte(message, "message");
190+
Ensure.ArgumentNotNull(author, "author");
191+
Ensure.ArgumentNotNull(committer, "committer");
192+
Ensure.ArgumentNotNull(tree, "tree");
193+
Ensure.ArgumentNotNull(parents, "parents");
194+
195+
if (prettifyMessage)
196+
{
197+
message = Proxy.git_message_prettify(message, commentChar);
198+
}
199+
200+
return Proxy.git_commit_create_buffer(tree.repo.Handle, author, committer, message, tree, parents.ToArray());
201+
}
202+
167203
private class ParentsCollection : ICollection<Commit>
168204
{
169205
private readonly Lazy<ICollection<Commit>> _parents;

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: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,61 @@ 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+
Tree tree,
397+
Commit[] parents)
398+
{
399+
using (SignatureHandle authorHandle = author.BuildHandle())
400+
using (SignatureHandle committerHandle = committer.BuildHandle())
401+
using (var treeHandle = Proxy.git_object_lookup(tree.repo.Handle, tree.Id, GitObjectType.Tree))
402+
using (var buf = new GitBuf())
403+
{
404+
ObjectHandle[] handles = new ObjectHandle[0];
405+
try
406+
{
407+
handles = parents.Select(c => Proxy.git_object_lookup(c.repo.Handle, c.Id, GitObjectType.Commit)).ToArray();
408+
var ptrs = handles.Select(p => p.AsIntPtr()).ToArray();
409+
int res;
410+
fixed(IntPtr* objs = ptrs)
411+
{
412+
res = NativeMethods.git_commit_create_buffer(buf,
413+
repo,
414+
authorHandle,
415+
committerHandle,
416+
null,
417+
message,
418+< F41A /span>
treeHandle,
419+
new UIntPtr((ulong)parents.LongCount()),
420+
objs);
421+
}
422+
Ensure.ZeroResult(res);
423+
}
424+
finally
425+
{
426+
foreach (var handle in handles)
427+
{
428+
handle.Dispose();
429+
}
430+
}
431+
432+
return LaxUtf8Marshaler.FromNative(buf.ptr);
433+
}
434+
}
435+
436+
public static unsafe ObjectId git_commit_create_with_signature(RepositoryHandle repo, string commitContent,
437+
string signature, string field)
438+
{
439+
GitOid id;
440+
int res = NativeMethods.git_commit_create_with_signature(out id, repo, commitContent, signature, field);
441+
Ensure.ZeroResult(res);
442+
443+
return id;
444+
}
445+
391446
public static unsafe string git_commit_message(ObjectHandle obj)
392447
{
393448
return NativeMethods.git_commit_message(obj);

LibGit2Sharp/GitObject.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public abstract class GitObject : IEquatable<GitObject>, IBelongToARepository
2828
/// <summary>
2929
/// The <see cref="Repository"/> containing the object.
3030
/// </summary>
31-
protected readonly Repository repo;
31+
internal readonly Repository repo;
3232

3333
/// <summary>
3434
/// Needed for mocking purposes.

LibGit2Sharp/ObjectDatabase.cs

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

425+
/// <summary>
426+
/// Inserts a <see cref="Commit"/> into the object database after attaching the given signature.
427+
/// </summary>
428+
/// <param name="commitContent">The raw unsigned commit</param>
429+
/// <param name="signature">The signature data </param>
430+
/// <param name="field">The header field in the commit in which to store the signature</param>
431+
/// <returns>The created <see cref="Commit"/>.</returns>
432+
public virtual ObjectId CreateCommitWithSignature(string commitContent, string signature, string field)
433+
{
434+
return Proxy.git_commit_create_with_signature(repo.Handle, commitContent, signature, field);
435+
}
436+
437+
/// <summary>
438+
/// Inserts a <see cref="Commit"/> into the object database after attaching the given signature.
439+
/// <para>
440+
/// This overload uses the default header field of "gpgsig"
441+
/// </para>
442+
/// </summary>
443+
/// <param name="commitContent">The raw unsigned commit</param>
444+
/// <param name="signature">The signature data </param>
445+
/// <returns>The created <see cref="Commit"/>.</returns>
446+
public virtual ObjectId CreateCommitWithSignature(string commitContent, string signature)
447+
{
448+
return Proxy.git_commit_create_with_signature(repo.Handle, commitContent, signature, null);
449+
}
450+
425451
/// <summary>
426452
/// Inserts a <see cref="TagAnnotation"/> into the object database, pointing to a specific <see cref="GitObject"/>.
427453
/// </summary>

0 commit comments

Comments
 (0)
0