Skip to content

Commit 56b7a20

Browse files
committed
feat: add commit signing
1 parent d8bf7d0 commit 56b7a20

File tree

3 files changed

+116
-1
lines changed

3 files changed

+116
-1
lines changed

pygit2/_pygit2.pyi

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Iterator
1+
from typing import Iterator, Optional
22
from io import IOBase
33
from . import Index, Submodule
44

@@ -459,6 +459,8 @@ class Repository:
459459
def create_blob_fromworkdir(self, path: str) -> Oid: ...
460460
def create_branch(self, name: str, commit: Commit, force = False) -> Branch: ...
461461
def create_commit(self, reference_name: str, author: Signature, committer: Signature, message: str, tree: _OidArg, parents: list[_OidArg], encoding: str = ...) -> Oid: ...
462+
def create_commit_string(self, author: Signature, committer: Signature, message: str, tree: _OidArg, parents: list[_OidArg], encoding: str = ...) -> Oid: ...
463+
def create_commit_with_signature(self, content: str, signature: str, signature_field: Optional[str] = None) -> Oid: ...
462464
def create_note(self, message: str, author: Signature, committer: Signature, annotated_id: str, ref: str = "refs/notes/commits", force: bool = False) -> Oid: ...
463465
def create_reference_direct(self, name: str, target: _OidArg, force: bool, message: str = None) -> Reference: ...
464466
def create_reference_symbolic(self, name: str, target: str, force: bool, message: str = None) -> Reference: ...

src/repository.c

+111
Original file line numberDiff line numberDiff line change
@@ -1110,6 +1110,115 @@ Repository_create_commit(Repository *self, PyObject *args)
11101110
return py_result;
11111111
}
11121112

1113+
PyDoc_STRVAR(Repository_create_commit_string__doc__,
1114+
"create_commit_string(author: Signature, committer: Signature, message: bytes | str, tree: Oid, parents: list[Oid][, encoding: str]) -> str\n"
1115+
"\n"
1116+
"Create a new commit but return it as a string.");
1117+
1118+
PyObject *
1119+
Repository_create_commit_string(Repository *self, PyObject *args)
1120+
{
1121+
Signature *py_author, *py_committer;
1122+
PyObject *py_oid, *py_message, *py_parents, *py_parent;
1123+
PyObject *str;
1124+
char *encoding = NULL;
1125+
git_oid oid;
1126+
git_tree *tree = NULL;
1127+
int parent_count;
1128+
git_commit **parents = NULL;
1129+
git_buf buf = { 0 };
1130+
int i = 0;
1131+
1132+
if (!PyArg_ParseTuple(args, "O!O!OOO!|s",
1133+
&SignatureType, &py_author,
1134+
&SignatureType, &py_committer,
1135+
&py_message,
1136+
&py_oid,
1137+
&PyList_Type, &py_parents,
1138+
&encoding))
1139+
return NULL;
1140+
1141+
size_t len = py_oid_to_git_oid(py_oid, &oid);
1142+
if (len == 0)
1143+
return NULL;
1144+
1145+
PyObject *tmessage;
1146+
const char *message = pgit_borrow_encoding(py_message, encoding, NULL, &tmessage);
1147+
if (message == NULL)
1148+
return NULL;
1149+
1150+
int err = git_tree_lookup_prefix(&tree, self->repo, &oid, len);
1151+
if (err < 0) {
1152+
Error_set(err);
1153+
goto out;
1154+
}
1155+
1156+
parent_count = (int)PyList_Size(py_parents);
1157+
parents = malloc(parent_count * sizeof(git_commit*));
1158+
if (parents == NULL) {
1159+
PyErr_SetNone(PyExc_MemoryError);
1160+
goto out;
1161+
}
1162+
for (; i < parent_count; i++) {
1163+
py_parent = PyList_GET_ITEM(py_parents, i);
1164+
len = py_oid_to_git_oid(py_parent, &oid);
1165+
if (len == 0)
1166+
goto out;
1167+
err = git_commit_lookup_prefix(&parents[i], self->repo, &oid, len);
1168+
if (err < 0) {
1169+
Error_set(err);
1170+
goto out;
1171+
}
1172+
}
1173+
1174+
err = git_commit_create_buffer(&buf, self->repo,
1175+
py_author->signature, py_committer->signature,
1176+
encoding, message, tree, parent_count,
1177+
(const git_commit**)parents);
1178+
if (err < 0) {
1179+
Error_set(err);
1180+
goto out;
1181+
}
1182+
1183+
str = to_unicode_n(buf.ptr, buf.size, NULL, NULL);
1184+
git_buf_dispose(&buf);
1185+
1186+
out:
1187+
Py_DECREF(tmessage);
1188+
git_tree_free(tree);
1189+
while (i > 0) {
1190+
i--;
1191+
git_commit_free(parents[i]);
1192+
}
1193+
free(parents);
1194+
return str;
1195+
}
1196+
1197+
PyDoc_STRVAR(Repository_create_commit_with_signature__doc__,
1198+
"create_commit_with_signature(content: str, signature: str, field_name: str) -> Oid\n"
1199+
"\n"
1200+
"Create a new signed commit object, return its oid.");
1201+
1202+
PyObject *
1203+
Repository_create_commit_with_signature(Repository *self, PyObject *args)
1204+
{
1205+
git_oid oid;
1206+
char *content, *signature;
1207+
char *signature_field = NULL;
1208+
1209+
if (!PyArg_ParseTuple(args, "ss|s", &content, &signature, &signature_field))
1210+
return NULL;
1211+
1212+
int err = git_commit_create_with_signature(&oid, self->repo, content,
1213+
signature, signature_field);
1214+
1215+
if (err < 0) {
1216+
Error_set(err);
1217+
return NULL;
1218+
}
1219+
1220+
return git_oid_to_python(&oid);
1221+
}
11131222

11141223
PyDoc_STRVAR(Repository_create_tag__doc__,
11151224
"create_tag(name: str, oid: Oid, type: int, tagger: Signature[, message: str]) -> Oid\n"
@@ -2277,6 +2386,8 @@ PyMethodDef Repository_methods[] = {
22772386
METHOD(Repository, create_blob_fromdisk, METH_VARARGS),
22782387
METHOD(Repository, create_blob_fromiobase, METH_O),
22792388
METHOD(Repository, create_commit, METH_VARARGS),
2389+
METHOD(Repository, create_commit_string, METH_VARARGS),
2390+
METHOD(Repository, create_commit_with_signature, METH_VARARGS),
22802391
METHOD(Repository, create_tag, METH_VARARGS),
22812392
METHOD(Repository, TreeBuilder, METH_VARARGS),
22822393
METHOD(Repository, walk, METH_VARARGS),

src/repository.h

+2
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ PyObject* Repository_walk(Repository *self, PyObject *args);
4343
PyObject* Repository_create_blob(Repository *self, PyObject *args);
4444
PyObject* Repository_create_blob_fromdisk(Repository *self, PyObject *args);
4545
PyObject* Repository_create_commit(Repository *self, PyObject *args);
46+
PyObject* Repository_create_commit_string(Repository *self, PyObject *args);
47+
PyObject* Repository_create_commit_with_signature(Repository *self, PyObject *args);
4648
PyObject* Repository_create_tag(Repository *self, PyObject *args);
4749
PyObject* Repository_create_branch(Repository *self, PyObject *args);
4850
PyObject* Repository_listall_references(Repository *self, PyObject *args);

0 commit comments

Comments
 (0)