diff --git a/git/commits.go b/git/commits.go index aad1039..0084877 100644 --- a/git/commits.go +++ b/git/commits.go @@ -2,9 +2,6 @@ package git import ( "bytes" - "encoding/json" - "fmt" - "log" "os" "os/exec" "strings" @@ -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, " ")) } @@ -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 diff --git a/git/commits_test.go b/git/commits_test.go new file mode 100644 index 0000000..0194934 --- /dev/null +++ b/git/commits_test.go @@ -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) + } + } + } +} diff --git a/git/testdata/commits.json b/git/testdata/commits.json new file mode 100644 index 0000000..7735912 --- /dev/null +++ b/git/testdata/commits.json @@ -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"}] \ No newline at end of file