Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 34 additions & 51 deletions git/commits.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@ package git

import (
"bytes"
"encoding/json"
"fmt"
"log"
"os"
"os/exec"
"strings"
Expand All @@ -16,7 +13,7 @@ import (
// If commitrange is a git still range 12345...54321, then it will be isolated set of commits.
// If commitrange is a single commit, all ancestor commits up through the hash provided.
func Commits(commitrange string) ([]CommitEntry, error) {
cmdArgs := []string{"git", "log", prettyFormat + formatCommit, commitrange}
cmdArgs := []string{"git", "log", `--pretty=format:%H`, commitrange}
if debug() {
logrus.Infof("[git] cmd: %q", strings.Join(cmdArgs, " "))
}
Expand All @@ -36,61 +33,47 @@ func Commits(commitrange string) ([]CommitEntry, error) {
return commits, nil
}

// CommitEntry represents a single commit's information from `git`
type CommitEntry map[string]string
// FieldNames are for the formating and rendering of the CommitEntry structs.
// Keys here are from git log pretty format "format:..."
var FieldNames = map[string]string{
"%h": "abbreviated_commit",
"%p": "abbreviated_parent",
"%t": "abbreviated_tree",
"%aD": "author_date",
"%aE": "author_email",
"%aN": "author_name",
"%b": "body",
"%H": "commit",
"%N": "commit_notes",
"%cD": "committer_date",
"%cE": "committer_email",
"%cN": "committer_name",
"%e": "encoding",
"%P": "parent",
"%D": "refs",
"%f": "sanitized_subject_line",
"%GS": "signer",
"%GK": "signer_key",
"%s": "subject",
"%G?": "verification_flag",
}

var (
prettyFormat = `--pretty=format:`
formatSubject = `%s`
formatBody = `%b`
formatCommit = `%H`
formatAuthorName = `%aN`
formatAuthorEmail = `%aE`
formatCommitterName = `%cN`
formatCommitterEmail = `%cE`
formatSigner = `%GS`
formatCommitNotes = `%N`
formatMap = `{"commit": "%H", "abbreviated_commit": "%h", "tree": "%T", "abbreviated_tree": "%t", "parent": "%P", "abbreviated_parent": "%p", "refs": "%D", "encoding": "%e", "sanitized_subject_line": "%f", "verification_flag": "%G?", "signer_key": "%GK", "author_date": "%aD" , "committer_date": "%cD" }`
)
// CommitEntry represents a single commit's information from `git`.
// See also FieldNames
type CommitEntry map[string]string

// LogCommit assembles the full information on a commit from its commit hash
func LogCommit(commit string) (*CommitEntry, error) {
buf := bytes.NewBuffer([]byte{})
cmdArgs := []string{"git", "log", "-1", prettyFormat + formatMap, commit}
if debug() {
logrus.Infof("[git] cmd: %q", strings.Join(cmdArgs, " "))
}
cmd := exec.Command(cmdArgs[0], cmdArgs[1:]...)
cmd.Stdout = buf
cmd.Stderr = os.Stderr

if err := cmd.Run(); err != nil {
log.Println(strings.Join(cmd.Args, " "))
return nil, err
}
c := CommitEntry{}
output := buf.Bytes()
if err := json.Unmarshal(output, &c); err != nil {
fmt.Println(string(output))
return nil, err
}

// any user provided fields can't be sanitized for the mock-json marshal above
for k, v := range map[string]string{
"subject": formatSubject,
"body": formatBody,
"author_name": formatAuthorName,
"author_email": formatAuthorEmail,
"committer_name": formatCommitterName,
"committer_email": formatCommitterEmail,
"commit_notes": formatCommitNotes,
"signer": formatSigner,
} {
output, err := exec.Command("git", "log", "-1", prettyFormat+v, commit).Output()
if err != nil {
for k, v := range FieldNames {
cmd := exec.Command("git", "log", "-1", `--pretty=format:`+k+``, commit)
cmd.Stdout = buf
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
return nil, err
}
c[k] = strings.TrimSpace(string(output))
c[v] = strings.TrimSpace(string(buf.Bytes()))
}

return &c, nil
Expand Down
55 changes: 55 additions & 0 deletions git/commits_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package git

import (
"encoding/json"
"io/ioutil"
"testing"
)

func TestCommitEntry(t *testing.T) {
c, err := HeadCommit()
if err != nil {
t.Fatal(err)
}
cr, err := Commits(c)
if err != nil {
t.Fatal(err)
}
for _, c := range cr {
for _, cV := range FieldNames {
found := false
for k := range c {
if k == cV {
found = true
}
}
if !found {
t.Errorf("failed to find field names: %q", c)
}
}
}
}

func TestMarshal(t *testing.T) {
buf, err := ioutil.ReadFile("testdata/commits.json")
if err != nil {
t.Fatal(err)
}
cr := []CommitEntry{}
if err := json.Unmarshal(buf, &cr); err != nil {
t.Error(err)
}
for _, c := range cr {
for _, cV := range FieldNames {
found := false
for k := range c {
if k == cV {
found = true
}
}
if !found {
t.Errorf("failed to find field names: %q", c)
}
}
}
}
1 change: 1 addition & 0 deletions git/testdata/commits.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[{"abbreviated_commit":"769b402","abbreviated_parent":"eba7575","abbreviated_tree":"f3490fa","author_date":"Thu, 14 Jan 2016 10:29:35 -0500","author_email":"vbatts@hashbangbash.com","author_name":"Vincent Batts","body":"so you can test and just check return code\n\nSigned-off-by: Vincent Batts \u003cvbatts@hashbangbash.com\u003e","commit":"769b4028a4732f5134848aa970e73e2d6edc3175","commit_notes":"","committer_date":"Thu, 14 Jan 2016 10:29:35 -0500","committer_email":"vbatts@hashbangbash.com","committer_name":"Vincent Batts","encoding":"","parent":"eba7575f7eccc9ee1aa5874769b44a62b612947d","refs":"HEAD -\u003e master, origin/master, origin/HEAD","sanitized_subject_line":"main-adding-a-quiet-flag-to-reduce-the-output","signer":"","signer_key":"","subject":"main: adding a quiet flag to reduce the output","tree":"f3490fa57c956658a78348651bf75dfad15e5f68","verification_flag":"N"},{"abbreviated_commit":"eba7575","abbreviated_parent":"09c2bd4","abbreviated_tree":"77c40ce","author_date":"Tue, 6 Oct 2015 10:55:42 -0400","author_email":"vbatts@hashbangbash.com","author_name":"Vincent Batts","body":"Signed-off-by: Vincent Batts \u003cvbatts@hashbangbash.com\u003e","commit":"eba7575f7eccc9ee1aa5874769b44a62b612947d","commit_notes":"","committer_date":"Tue, 6 Oct 2015 10:55:42 -0400","committer_email":"vbatts@hashbangbash.com","committer_name":"Vincent Batts","encoding":"","parent":"09c2bd43dc6f0508f461f9e1088013abbd3fa3d5","refs":"","sanitized_subject_line":"README-information-about-rules","signer":"","signer_key":"","subject":"README: information about rules","tree":"77c40ce1580d215d8cac2d997d41d08baa6b2546","verification_flag":"N"},{"abbreviated_commit":"09c2bd4","abbreviated_parent":"b243ca4","abbreviated_tree":"f88ab5a","author_date":"Tue, 6 Oct 2015 10:51:22 -0400","author_email":"vbatts@hashbangbash.com","author_name":"Vincent Batts","body":"Signed-off-by: Vincent Batts \u003cvbatts@hashbangbash.com\u003e","commit":"09c2bd43dc6f0508f461f9e1088013abbd3fa3d5","commit_notes":"","committer_date":"Tue, 6 Oct 2015 10:51:22 -0400","committer_email":"vbatts@hashbangbash.com","committer_name":"Vincent Batts","encoding":"","parent":"b243ca47707576f7551094dd26c8e4647f093acf","refs":"","sanitized_subject_line":"README-more-usage","signer":"","signer_key":"","subject":"README: more usage","tree":"f88ab5a60a21f177e37b7eee3ee7c2c0e15f0892","verification_flag":"N"},{"abbreviated_commit":"b243ca4","abbreviated_parent":"d614ccf","abbreviated_tree":"a0c3f0b","author_date":"Tue, 6 Oct 2015 10:47:00 -0400","author_email":"vbatts@hashbangbash.com","author_name":"Vincent Batts","body":"Signed-off-by: Vincent Batts \u003cvbatts@hashbangbash.com\u003e","commit":"b243ca47707576f7551094dd26c8e4647f093acf","commit_notes":"","committer_date":"Tue, 6 Oct 2015 10:48:03 -0400","committer_email":"vbatts@hashbangbash.com","committer_name":"Vincent Batts","encoding":"","parent":"d614ccf9970296e9619e28883748be653801dbf3","refs":"","sanitized_subject_line":"README-adding-install-and-usage","signer":"","signer_key":"","subject":"README: adding install and usage","tree":"a0c3f0b74f503938d7d7c31a5d6e937410d520ae","verification_flag":"N"},{"abbreviated_commit":"d614ccf","abbreviated_parent":"b9413c6","abbreviated_tree":"785f2f5","author_date":"Tue, 6 Oct 2015 10:44:04 -0400","author_email":"vbatts@hashbangbash.com","author_name":"Vincent Batts","body":"for cleanliness and ease of testing\n\nSigned-off-by: Vincent Batts \u003cvbatts@hashbangbash.com\u003e","commit":"d614ccf9970296e9619e28883748be653801dbf3","commit_notes":"","committer_date":"Tue, 6 Oct 2015 10:44:04 -0400","committer_email":"vbatts@hashbangbash.com","committer_name":"Vincent Batts","encoding":"","parent":"b9413c60c83d6f25d8979292d09ddceff0cde111","refs":"","sanitized_subject_line":"run-tests-in-a-runner","signer":"","signer_key":"","subject":"*: run tests in a runner","tree":"785f2f51a0e92f590053745be8e915116e4e8c59","verification_flag":"N"},{"abbreviated_commit":"b9413c6","abbreviated_parent":"5e74abd","abbreviated_tree":"997fcb4","author_date":"Mon, 5 Oct 2015 19:02:31 -0400","author_email":"vbatts@hashbangbash.com","author_name":"Vincent Batts","body":"Signed-off-by: Vincent Batts \u003cvbatts@hashbangbash.com\u003e","commit":"b9413c60c83d6f25d8979292d09ddceff0cde111","commit_notes":"","committer_date":"Mon, 5 Oct 2015 19:02:31 -0400","committer_email":"vbatts@hashbangbash.com","committer_name":"Vincent Batts","encoding":"","parent":"5e74abd1b2560d91647280da8374978763cb3b0f","refs":"","sanitized_subject_line":"shortsubject-add-a-subject-length-check","signer":"","signer_key":"","subject":"shortsubject: add a subject length check","tree":"997fcb4cf30c0f25ac5feb907ff5a977b8a65ae6","verification_flag":"N"},{"abbreviated_commit":"5e74abd","abbreviated_parent":"07a982f","abbreviated_tree":"6605800","author_date":"Mon, 5 Oct 2015 18:55:05 -0400","author_email":"vbatts@hashbangbash.com","author_name":"Vincent Batts","body":"Signed-off-by: Vincent Batts \u003cvbatts@hashbangbash.com\u003e","commit":"5e74abd1b2560d91647280da8374978763cb3b0f","commit_notes":"","committer_date":"Mon, 5 Oct 2015 18:55:05 -0400","committer_email":"vbatts@hashbangbash.com","committer_name":"Vincent Batts","encoding":"","parent":"07a982ff94318262732e6422daa75f1f51340b60","refs":"","sanitized_subject_line":"comments-and-golint","signer":"","signer_key":"","subject":"*: comments and golint","tree":"6605800cc08fc9906b9ab9819413d2adaffd0ed5","verification_flag":"N"},{"abbreviated_commit":"07a982f","abbreviated_parent":"03bda4b","abbreviated_tree":"8a81024","author_date":"Mon, 5 Oct 2015 18:45:33 -0400","author_email":"vbatts@hashbangbash.com","author_name":"Vincent Batts","body":"Signed-off-by: Vincent Batts \u003cvbatts@hashbangbash.com\u003e","commit":"07a982ff94318262732e6422daa75f1f51340b60","commit_notes":"","committer_date":"Mon, 5 Oct 2015 18:49:06 -0400","committer_email":"vbatts@hashbangbash.com","committer_name":"Vincent Batts","encoding":"","parent":"03bda4bcb2e741bc3e540ac171ba229bcfb47b9c","refs":"","sanitized_subject_line":"git-add-verbose-output-of-the-commands-run","signer":"","signer_key":"","subject":"git: add verbose output of the commands run","tree":"8a81024ef0d4e93d5852180f3c3f9ce10ae09cdb","verification_flag":"N"},{"abbreviated_commit":"03bda4b","abbreviated_parent":"c10ba9c","abbreviated_tree":"e41fbcb","author_date":"Mon, 5 Oct 2015 18:29:24 -0400","author_email":"vbatts@hashbangbash.com","author_name":"Vincent Batts","body":"Signed-off-by: Vincent Batts \u003cvbatts@hashbangbash.com\u003e","commit":"03bda4bcb2e741bc3e540ac171ba229bcfb47b9c","commit_notes":"","committer_date":"Mon, 5 Oct 2015 18:49:02 -0400","committer_email":"vbatts@hashbangbash.com","committer_name":"Vincent Batts","encoding":"","parent":"c10ba9c097ba2d5e0d5e834ae43252276a177e94","refs":"","sanitized_subject_line":"main-add-filtering-of-rules-to-run","signer":"","signer_key":"","subject":"main: add filtering of rules to run","tree":"e41fbcb527138c2cf49ee05d8adc55ba5d4d22f6","verification_flag":"N"},{"abbreviated_commit":"c10ba9c","abbreviated_parent":"","abbreviated_tree":"06f0e7a","author_date":"Mon, 5 Oct 2015 16:16:52 -0400","author_email":"vbatts@hashbangbash.com","author_name":"Vincent Batts","body":"Signed-off-by: Vincent Batts \u003cvbatts@hashbangbash.com\u003e","commit":"c10ba9c097ba2d5e0d5e834ae43252276a177e94","commit_notes":"","committer_date":"Mon, 5 Oct 2015 18:48:23 -0400","committer_email":"vbatts@hashbangbash.com","committer_name":"Vincent Batts","encoding":"","parent":"","refs":"","sanitized_subject_line":"Initial-commit","signer":"","signer_key":"","subject":"Initial commit","tree":"06f0e7a5b91783b052759a91c25fab7a22ce3ab4","verification_flag":"N"}]