11package main
22
33import (
4- "bytes"
54 "errors"
65 "fmt"
76 "io/ioutil"
87 "log"
98 "os"
10- "os/exec"
119 "regexp"
1210 "strings"
1311 "unicode/utf8"
1412
13+ "github.com/go-git/go-git/v5"
14+ "github.com/go-git/go-git/v5/plumbing"
15+ "github.com/go-git/go-git/v5/plumbing/object"
1516 yaml "gopkg.in/yaml.v2"
1617)
1718
@@ -234,7 +235,66 @@ func LoadCommitPolicy(filename string) (CommitPolicyConfig, error) {
234235 return commitPolicy , nil
235236}
236237
238+ func getCommitSubjects (repo * git.Repository , from , to string ) ([]string , error ) {
239+ var refStrings []string
240+ refStrings = append (refStrings , from )
241+ refStrings = append (refStrings , to )
242+
243+ var hashes []* plumbing.Hash
244+ for _ , refString := range refStrings {
245+ hash , err := repo .ResolveRevision (plumbing .Revision (refString ))
246+ if err != nil {
247+ log .Fatalf ("unable to resolve revision %s to hash" , refString )
248+ }
249+ hashes = append (hashes , hash )
250+ }
251+
252+ var commits []* object.Commit
253+ for _ , hash := range hashes {
254+ commit , err := repo .CommitObject (* hash )
255+ if err != nil {
256+ log .Fatalf ("unable to find commit %s" , hash .String ())
257+ }
258+ commits = append (commits , commit )
259+ }
260+
261+ mergeBase , err := commits [0 ].MergeBase (commits [1 ])
262+ if err != nil {
263+ log .Fatalf ("repo history error %s" , err )
264+ }
265+
266+ cIter , err := repo .Log (& git.LogOptions {From : * hashes [1 ]})
267+ if err != nil {
268+ log .Fatalf ("error getting commit log %s" , err )
269+ }
270+
271+ var ErrReachedMergeBase = errors .New ("reached Merge Base" )
272+
273+ var subjects []string
274+ err = cIter .ForEach (func (c * object.Commit ) error {
275+ if c .Hash == mergeBase [0 ].Hash {
276+ return ErrReachedMergeBase
277+ }
278+ subjects = append (subjects , strings .Split (c .Message , "\n " )[0 ])
279+ return nil
280+ })
281+ if ! errors .Is (err , ErrReachedMergeBase ) {
282+ return []string {}, fmt .Errorf ("error tracing commit history: %w" , err )
283+ }
284+ return subjects , nil
285+ }
286+
237287func main () {
288+
289+ var repoPath string
290+
291+ log .Printf ("os args: %s" , os .Args )
292+
293+ if len (os .Args ) < 2 {
294+ repoPath = "."
295+ } else {
296+ repoPath = os .Args [1 ]
297+ }
238298 commitPolicy , err := LoadCommitPolicy (".check-commit.yml" )
239299 if err != nil {
240300 log .Fatalf ("error reading configuration: %s" , err )
@@ -249,19 +309,20 @@ func main() {
249309 log .Fatalf ("couldn't auto-detect running environment, please set GITHUB_REF and GITHUB_BASE_REF manually" )
250310 }
251311
252- commitRange := fmt .Sprintf ("%s...%s" , gitEnv .Base , gitEnv .Ref )
312+ repo , err := git .PlainOpen (repoPath )
313+ if err != nil {
314+ log .Fatalf ("couldn't open git local git repo: %s" , err )
315+ }
253316
254- out , err := exec . Command ( "git" , "log" , commitRange , "--pretty=format:'%s'" ). Output ( )
317+ subjects , err := getCommitSubjects ( repo , gitEnv . Base , gitEnv . Ref )
255318 if err != nil {
256- log .Fatalf ("Unable to get log subject '%s' " , err )
319+ log .Fatalf ("error getting commit subjects: %s " , err )
257320 }
258321
259- // Check subject
260322 errors := false
261-
262- for _ , subject := range bytes .Split (out , []byte ("\n " )) {
263- subject = bytes .Trim (subject , "'" )
264- if err := commitPolicy .CheckSubject (subject ); err != nil {
323+ for _ , subject := range subjects {
324+ subject = strings .Trim (subject , "'" )
325+ if err := commitPolicy .CheckSubject ([]byte (subject )); err != nil {
265326 log .Printf ("%s, original subject message '%s'" , err , string (subject ))
266327
267328 errors = true
0 commit comments