Skip to content

Commit 76f84c0

Browse files
committed
Merge remote-tracking branch 'thcipriani/message-trailers'
2 parents 0664ee8 + 69653b1 commit 76f84c0

File tree

5 files changed

+106
-0
lines changed

5 files changed

+106
-0
lines changed

docs/recipes/git-log.rst

+15
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,21 @@ Traverse commit history
3434
>>> for commit in repo.walk(last.id, pygit2.GIT_SORT_TIME):
3535
>>> print(commit.message) # or some other operation
3636
37+
======================================================================
38+
Show trailers from the last commit
39+
======================================================================
40+
41+
.. code-block:: bash
42+
43+
$ git log --format='%(trailers:key=Bug)'
44+
45+
.. code-block:: python
46+
47+
>>> last = repo[repo.head.target]
48+
>>> for commit in repo.walk(last.id, pygit2.GIT_SORT_TIME):
49+
>>> print(commit.message_trailers.get('Bug'))
50+
51+
3752
----------------------------------------------------------------------
3853
References
3954
----------------------------------------------------------------------

src/commit.c

+42
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,47 @@ Commit_gpg_signature__get__(Commit *self)
9898
}
9999

100100

101+
PyDoc_STRVAR(Commit_message_trailers__doc__,
102+
"Returns commit message trailers (e.g., Bug: 1234) as a dictionary."
103+
);
104+
105+
PyObject *
106+
Commit_message_trailers__get__(Commit *self)
107+
{
108+
git_message_trailer_array gmt_arr;
109+
int i, trailer_count, err;
110+
PyObject *dict;
111+
PyObject *py_val;
112+
const char *message = git_commit_message(self->commit);
113+
const char *encoding = git_commit_message_encoding(self->commit);
114+
115+
err = git_message_trailers(&gmt_arr, message);
116+
if (err < 0)
117+
return Error_set(err);
118+
119+
dict = PyDict_New();
120+
if (dict == NULL)
121+
goto error;
122+
123+
trailer_count = gmt_arr.count;
124+
for (i=0; i < trailer_count; i++) {
125+
py_val = to_unicode(gmt_arr.trailers[i].value, encoding, NULL);
126+
err = PyDict_SetItemString(dict, gmt_arr.trailers[i].key, py_val);
127+
Py_DECREF(py_val);
128+
if (err < 0)
129+
goto error;
130+
131+
}
132+
133+
git_message_trailer_array_free(&gmt_arr);
134+
return dict;
135+
136+
error:
137+
git_message_trailer_array_free(&gmt_arr);
138+
Py_CLEAR(dict);
139+
return NULL;
140+
}
141+
101142
PyDoc_STRVAR(Commit_raw_message__doc__, "Message (bytes).");
102143

103144
PyObject *
@@ -270,6 +311,7 @@ PyGetSetDef Commit_getseters[] = {
270311
GETTER(Commit, tree_id),
271312
GETTER(Commit, parents),
272313
GETTER(Commit, parent_ids),
314+
GETTER(Commit, message_trailers),
273315
{NULL}
274316
};
275317

src/commit.h

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
PyObject* Commit_get_message_encoding(Commit *commit);
3636
PyObject* Commit_get_message(Commit *commit);
3737
PyObject* Commit_get_raw_message(Commit *commit);
38+
PyObject* Commit_get_message_trailers(Commit *commit);
3839
PyObject* Commit_get_commit_time(Commit *commit);
3940
PyObject* Commit_get_commit_time_offset(Commit *commit);
4041
PyObject* Commit_get_committer(Commit *self);

test/data/trailerrepo.tar

50 KB
Binary file not shown.

test/test_commit_trailer.py

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# Copyright 2010-2021 The pygit2 contributors
2+
#
3+
# This file is free software; you can redistribute it and/or modify
4+
# it under the terms of the GNU General Public License, version 2,
5+
# as published by the Free Software Foundation.
6+
#
7+
# In addition to the permissions in the GNU General Public License,
8+
# the authors give you unlimited permission to link the compiled
9+
# version of this file into combinations with other programs,
10+
# and to distribute those combinations without any restriction
11+
# coming from the use of this file. (The General Public License
12+
# restrictions do apply in other respects; for example, they cover
13+
# modification of the file, and distribution when not linked into
14+
# a combined executable.)
15+
#
16+
# This file is distributed in the hope that it will be useful, but
17+
# WITHOUT ANY WARRANTY; without even the implied warranty of
18+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19+
# General Public License for more details.
20+
#
21+
# You should have received a copy of the GNU General Public License
22+
# along with this program; see the file COPYING. If not, write to
23+
# the Free Software Foundation, 51 Franklin Street, Fifth Floor,
24+
# Boston, MA 02110-1301, USA.
25+
26+
import pygit2
27+
import pytest
28+
29+
from . import utils
30+
31+
32+
@pytest.fixture
33+
def repo(tmp_path):
34+
with utils.TemporaryRepository('trailerrepo.tar', tmp_path) as path:
35+
yield pygit2.Repository(path)
36+
37+
38+
def test_get_trailers_array(repo):
39+
commit_hash = '010231b2fdaee6b21da4f06058cf6c6a3392dd12'
40+
expected_trailers = {
41+
'Bug': '1234',
42+
'Signed-off-by': 'Tyler Cipriani <[email protected]>',
43+
}
44+
commit = repo.get(commit_hash)
45+
trailers = commit.message_trailers
46+
47+
assert trailers['Bug'] == expected_trailers['Bug']
48+
assert trailers['Signed-off-by'] == expected_trailers['Signed-off-by']

0 commit comments

Comments
 (0)