From 354218d9bb7e97f2eedacd3072181724a8863f4b Mon Sep 17 00:00:00 2001 From: Jesse Hathaway Date: Tue, 2 Jun 2020 12:30:42 -0500 Subject: [PATCH] Add support for parsing git trailers (#614) Adds a wrapper for git_message_trailers which returns a slice of trailer structs. (cherry picked from commit 5241c72e6ebd21085e56a1c6d284c06154a202b5) --- message.go | 42 ++++++++++++++++++++++++++++++++++++++++++ message_test.go | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 message.go create mode 100644 message_test.go diff --git a/message.go b/message.go new file mode 100644 index 0000000..255e8d7 --- /dev/null +++ b/message.go @@ -0,0 +1,42 @@ +package git + +/* +#include +*/ +import "C" +import ( + "runtime" + "unsafe" +) + +// Trailer represents a single git message trailer. +type Trailer struct { + Key string + Value string +} + +// MessageTrailers parses trailers out of a message, returning a slice of +// Trailer structs. Trailers are key/value pairs in the last paragraph of a +// message, not including any patches or conflicts that may be present. +func MessageTrailers(message string) ([]Trailer, error) { + var trailersC C.git_message_trailer_array + + messageC := C.CString(message) + defer C.free(unsafe.Pointer(messageC)) + + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + ecode := C.git_message_trailers(&trailersC, messageC) + if ecode < 0 { + return nil, MakeGitError(ecode) + } + defer C.git_message_trailer_array_free(&trailersC) + trailers := make([]Trailer, trailersC.count) + var trailer *C.git_message_trailer + for i, p := 0, uintptr(unsafe.Pointer(trailersC.trailers)); i < int(trailersC.count); i, p = i+1, p+unsafe.Sizeof(C.git_message_trailer{}) { + trailer = (*C.git_message_trailer)(unsafe.Pointer(p)) + trailers[i] = Trailer{Key: C.GoString(trailer.key), Value: C.GoString(trailer.value)} + } + return trailers, nil +} diff --git a/message_test.go b/message_test.go new file mode 100644 index 0000000..f33ccb7 --- /dev/null +++ b/message_test.go @@ -0,0 +1,42 @@ +package git + +import ( + "fmt" + "reflect" + "testing" +) + +func TestTrailers(t *testing.T) { + t.Parallel() + tests := []struct { + input string + expected []Trailer + }{ + { + "commit with zero trailers\n", + []Trailer{}, + }, + { + "commit with one trailer\n\nCo-authored-by: Alice \n", + []Trailer{ + Trailer{Key: "Co-authored-by", Value: "Alice "}, + }, + }, + { + "commit with two trailers\n\nCo-authored-by: Alice \nSigned-off-by: Bob \n", + []Trailer{ + Trailer{Key: "Co-authored-by", Value: "Alice "}, + Trailer{Key: "Signed-off-by", Value: "Bob "}}, + }, + } + for _, test := range tests { + fmt.Printf("%s", test.input) + actual, err := MessageTrailers(test.input) + if err != nil { + t.Errorf("Trailers returned an unexpected error: %v", err) + } + if !reflect.DeepEqual(test.expected, actual) { + t.Errorf("expecting %#v\ngot %#v", test.expected, actual) + } + } +}