Skip to content

Commit f54f387

Browse files
committed
MEDIUM: add support for junit file format reporting
1 parent f3633ce commit f54f387

File tree

11 files changed

+138
-32
lines changed

11 files changed

+138
-32
lines changed

.aspell.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,4 @@ allowed:
3636
- url
3737
- english
3838
- lang
39+
- junit

aspell/aspell.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"sort"
1010
"strings"
1111

12+
"github.com/haproxytech/check-commit/v5/junit"
1213
"github.com/haproxytech/check-commit/v5/match"
1314

1415
"github.com/fatih/camelcase"
@@ -121,7 +122,7 @@ func (a Aspell) checkSingle(data string, allowedWords []string) error {
121122
return nil
122123
}
123124

124-
func (a Aspell) Check(subjects []string, commitsFull []string, content []map[string]string) error {
125+
func (a Aspell) Check(subjects []string, commitsFull []string, content []map[string]string, junitSuite junit.Interface) error {
125126
var commitsFullData []string
126127
for _, c := range commitsFull {
127128
commit := []string{}
@@ -171,6 +172,7 @@ func (a Aspell) Check(subjects []string, commitsFull []string, content []map[str
171172
imports = match.GetImportWordsFromGoFile(name)
172173
}
173174
if err := a.checkSingle(v, imports); err != nil {
175+
junitSuite.AddMessageFailed(name, "aspell check failed", err.Error())
174176
log.Println(name, err.Error())
175177
response += fmt.Sprintf("%s\n", err)
176178
}
@@ -183,6 +185,7 @@ func (a Aspell) Check(subjects []string, commitsFull []string, content []map[str
183185

184186
for _, subject := range checks {
185187
if err := a.checkSingle(subject, []string{}); err != nil {
188+
junitSuite.AddMessageFailed("commit message", "aspell check failed", err.Error())
186189
log.Println("commit message", err.Error())
187190
response += fmt.Sprintf("%s\n", err)
188191
}

aspell/aspell_test.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package aspell
22

33
import (
44
"testing"
5+
6+
"github.com/haproxytech/check-commit/v5/junit"
57
)
68

79
func Test_checkWithAspell(t *testing.T) {
@@ -107,7 +109,7 @@ func TestAspell_Check(t *testing.T) {
107109
AllowedWords: tt.fields.AllowedWords,
108110
HelpText: tt.fields.HelpText,
109111
}
110-
if err := a.Check(tt.args.subjects, tt.args.commitsFull, tt.args.content); (err != nil) != tt.wantErr {
112+
if err := a.Check(tt.args.subjects, tt.args.commitsFull, tt.args.content, &junit.JunitSuiteDummy{}); (err != nil) != tt.wantErr {
111113
t.Errorf("Aspell.Check() error = %v, wantErr %v", err, tt.wantErr)
112114
}
113115
})

aspell_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"testing"
88

99
"github.com/haproxytech/check-commit/v5/aspell"
10+
"github.com/haproxytech/check-commit/v5/junit"
1011
)
1112

1213
func Test_Aspell(t *testing.T) {
@@ -35,7 +36,7 @@ func Test_Aspell(t *testing.T) {
3536
}
3637
err = aspell.Check([]string{"subject"}, []string{"body"}, []map[string]string{
3738
{filename: readme},
38-
})
39+
}, &junit.JunitSuiteDummy{})
3940
if err != nil {
4041
t.Errorf("checkWithAspell() error = %v", err)
4142
}

check.go

Lines changed: 49 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"unicode/utf8"
1717

1818
"github.com/google/go-github/v56/github"
19+
"github.com/haproxytech/check-commit/v5/junit"
1920
gitlab "gitlab.com/gitlab-org/api/client-go"
2021

2122
git "github.com/go-git/go-git/v5"
@@ -90,24 +91,33 @@ TagOrder:
9091

9192
var ErrSubjectMessageFormat = errors.New("invalid subject message format")
9293

93-
func checkSubjectText(subject string) error {
94+
func checkSubjectText(subject string, junitSuite junit.Interface) error {
9495
subjectLen := utf8.RuneCountInString(subject)
9596
subjectParts := strings.Fields(subject)
9697
subjectPartsLen := len(subjectParts)
9798

9899
if subject != strings.Join(subjectParts, " ") {
100+
junitSuite.AddMessageFailed(ErrSubjectMessageFormat.Error(), "malformatted subject string (trailing or double spaces?)", fmt.Sprintf("subject: %s", subject))
99101
return fmt.Errorf(
100102
"malformatted subject string (trailing or double spaces?): '%s' (%w)",
101103
subject, ErrSubjectMessageFormat)
102104
}
103105

104106
if subjectPartsLen < MINSUBJECTPARTS || subjectPartsLen > MAXSUBJECTPARTS {
107+
junitSuite.AddMessageFailed(
108+
ErrSubjectMessageFormat.Error(),
109+
fmt.Sprintf("subject word count out of bounds [words %d < %d < %d]", MINSUBJECTPARTS, subjectPartsLen, MAXSUBJECTPARTS),
110+
fmt.Sprintf("subject: %s", subject))
105111
return fmt.Errorf(
106112
"subject word count out of bounds [words %d < %d < %d] '%s': %w",
107113
MINSUBJECTPARTS, subjectPartsLen, MAXSUBJECTPARTS, subjectParts, ErrSubjectMessageFormat)
108114
}
109115

110116
if subjectLen < MINSUBJECTLEN || subjectLen > MAXSUBJECTLEN {
117+
junitSuite.AddMessageFailed(
118+
ErrSubjectMessageFormat.Error(),
119+
fmt.Sprintf("subject length out of bounds [len %d < %d < %d]", MINSUBJECTLEN, subjectLen, MAXSUBJECTLEN),
120+
fmt.Sprintf("subject: %s", subject))
111121
return fmt.Errorf(
112122
"subject length out of bounds [len %d < %d < %d] '%s': %w",
113123
MINSUBJECTLEN, subjectLen, MAXSUBJECTLEN, subject, ErrSubjectMessageFormat)
@@ -128,6 +138,7 @@ func (c CommitPolicyConfig) CheckPatchTypes(tag, severity string, patchTypeName
128138
}
129139

130140
if c.PatchTypes[patchTypeName].Scope == "" {
141+
131142
log.Printf("unable to verify severity %s without definitions", severity)
132143

133144
break // subject has severity but there is no definition to verify it
@@ -148,10 +159,11 @@ func (c CommitPolicyConfig) CheckPatchTypes(tag, severity string, patchTypeName
148159

149160
var ErrTagScope = errors.New("invalid tag and or severity")
150161

151-
func (c CommitPolicyConfig) CheckSubject(rawSubject []byte) error {
162+
func (c CommitPolicyConfig) CheckSubject(rawSubject []byte, junitSuite junit.Interface) error {
152163
// check for ascii-only before anything else
153164
for i := 0; i < len(rawSubject); i++ {
154165
if rawSubject[i] > unicode.MaxASCII {
166+
junitSuite.AddMessageFailed("", "non-ascii characters detected in commit subject", fmt.Sprintf("subject: %s", rawSubject))
155167
log.Printf("non-ascii characters detected in in subject:\n%s", hex.Dump(rawSubject))
156168

157169
return fmt.Errorf("non-ascii characters in commit subject: %w", ErrTagScope)
@@ -174,6 +186,7 @@ func (c CommitPolicyConfig) CheckSubject(rawSubject []byte) error {
174186
submatch := r.FindSubmatchIndex(rawSubject)
175187
if len(submatch) == 0 { // no match
176188
if !tagOK {
189+
junitSuite.AddMessageFailed("", "invalid or missing tag/severity in commit message", fmt.Sprintf("subject: %s", rawSubject))
177190
log.Printf("unable to find match in %s\n", rawSubject)
178191

179192
return fmt.Errorf("invalid tag or no tag found, searched through [%s]: %w",
@@ -199,6 +212,7 @@ func (c CommitPolicyConfig) CheckSubject(rawSubject []byte) error {
199212
candidates = append(candidates, string(tagPart))
200213

201214
if !tagOK {
215+
junitSuite.AddMessageFailed("", "invalid tag/severity in commit message", fmt.Sprintf("subject: %s", rawSubject))
202216
log.Printf("unable to find match in %s\n", candidates)
203217

204218
return fmt.Errorf("invalid tag or no tag found, searched through [%s]: %w",
@@ -208,10 +222,11 @@ func (c CommitPolicyConfig) CheckSubject(rawSubject []byte) error {
208222

209223
submatch := r.FindSubmatchIndex(rawSubject)
210224
if len(submatch) != 0 { // no match
225+
junitSuite.AddMessageFailed("", "unprocessed tags detected in commit message", fmt.Sprintf("subject: %s", rawSubject))
211226
return fmt.Errorf("detected unprocessed tags, %w", ErrTagScope)
212227
}
213228

214-
return checkSubjectText(string(rawSubject))
229+
return checkSubjectText(string(rawSubject), junitSuite)
215230
}
216231

217232
func (c CommitPolicyConfig) IsEmpty() bool {
@@ -268,7 +283,7 @@ func LoadCommitPolicy(filename string) (CommitPolicyConfig, error) {
268283
return commitPolicy, nil
269284
}
270285

271-
func getGithubCommitData() ([]string, []string, []map[string]string, error) {
286+
func getGithubCommitData(junitSuite junit.Interface) ([]string, []string, []map[string]string, error) {
272287
token := os.Getenv("API_TOKEN")
273288
repo := os.Getenv("GITHUB_REPOSITORY")
274289
ref := os.Getenv("GITHUB_REF")
@@ -285,22 +300,26 @@ func getGithubCommitData() ([]string, []string, []map[string]string, error) {
285300
if event == "pull_request" {
286301
repoSlice := strings.SplitN(repo, "/", 2)
287302
if len(repoSlice) < 2 {
303+
junitSuite.AddMessageFailed("", "error fetching owner and project from repo", fmt.Sprintf("invalid repository format: %s", repo))
288304
return nil, nil, nil, fmt.Errorf("error fetching owner and project from repo %s", repo)
289305
}
290306
owner := repoSlice[0]
291307
project := repoSlice[1]
292308

293309
refSlice := strings.SplitN(ref, "/", 4)
294310
if len(refSlice) < 3 {
295-
return nil, nil, nil, fmt.Errorf("error fetching pr from ref %s", ref)
311+
junitSuite.AddMessageFailed("", "error fetching PR number from ref", fmt.Sprintf("invalid ref format: %s", ref))
312+
return nil, nil, nil, fmt.Errorf("error fetching PR from ref %s", ref)
296313
}
297314
prNo, err := strconv.Atoi(refSlice[2])
298315
if err != nil {
299-
return nil, nil, nil, fmt.Errorf("Error fetching pr number from %s: %w", refSlice[2], err)
316+
junitSuite.AddMessageFailed("", "error fetching PR number from ref", fmt.Sprintf("invalid pr number: %s", refSlice[2]))
317+
return nil, nil, nil, fmt.Errorf("Error fetching PR number from %s: %w", refSlice[2], err)
300318
}
301319

302320
commits, _, err := githubClient.PullRequests.ListCommits(ctx, owner, project, prNo, &github.ListOptions{})
303321
if err != nil {
322+
junitSuite.AddMessageFailed("", "error fetching commits", err.Error())
304323
return nil, nil, nil, fmt.Errorf("error fetching commits: %w", err)
305324
}
306325

@@ -315,6 +334,7 @@ func getGithubCommitData() ([]string, []string, []map[string]string, error) {
315334
}
316335
if len(l) > 1 {
317336
if l[1] != "" {
337+
junitSuite.AddMessageFailed("", "empty line between subject and body is required", fmt.Sprintf("%s %s", hash, l[0]))
318338
return nil, nil, nil, fmt.Errorf("empty line between subject and body is required: %s %s", hash, l[0])
319339
}
320340
}
@@ -326,6 +346,7 @@ func getGithubCommitData() ([]string, []string, []map[string]string, error) {
326346

327347
files, _, err := githubClient.PullRequests.ListFiles(ctx, owner, project, prNo, &github.ListOptions{})
328348
if err != nil {
349+
junitSuite.AddMessageFailed("", "error fetching files", err.Error())
329350
return nil, nil, nil, fmt.Errorf("error fetching files: %w", err)
330351
}
331352
content := map[string]string{}
@@ -339,20 +360,23 @@ func getGithubCommitData() ([]string, []string, []map[string]string, error) {
339360
}
340361
return subjects, messages, diffs, nil
341362
} else {
363+
junitSuite.AddMessageFailed("", "unsupported event name", fmt.Sprintf("unsupported event name: %s", event))
342364
return nil, nil, nil, fmt.Errorf("unsupported event name: %s", event)
343365
}
344366
}
345367

346-
func getLocalCommitData() ([]string, []string, []map[string]string, error) {
368+
func getLocalCommitData(junitSuite junit.Interface) ([]string, []string, []map[string]string, error) {
347369
repo, err := git.PlainOpen(".")
348370
if err != nil {
371+
junitSuite.AddMessageFailed("", "error opening local git repository", err.Error())
349372
return nil, nil, nil, err
350373
}
351374

352375
iter, err := repo.Log(&git.LogOptions{
353376
Order: git.LogOrderCommitterTime,
354377
})
355378
if err != nil {
379+
junitSuite.AddMessageFailed("", "error getting git log iterator", err.Error())
356380
return nil, nil, nil, err
357381
}
358382

@@ -372,6 +396,7 @@ func getLocalCommitData() ([]string, []string, []map[string]string, error) {
372396
break
373397
}
374398
if err != nil {
399+
junitSuite.AddMessageFailed("", "error iterating through git commits", err.Error())
375400
return nil, nil, nil, err
376401
}
377402
if committer == "" {
@@ -392,6 +417,7 @@ func getLocalCommitData() ([]string, []string, []map[string]string, error) {
392417
}
393418
if len(l) > 1 {
394419
if l[1] != "" {
420+
junitSuite.AddMessageFailed("", "empty line between subject and body is required", fmt.Sprintf("%s %s", commitHash, l[0]))
395421
return nil, nil, nil, fmt.Errorf("empty line between subject and body is required: %s %s", commitHash, l[0])
396422
}
397423
}
@@ -409,13 +435,15 @@ func getLocalCommitData() ([]string, []string, []map[string]string, error) {
409435
tree2, _ := commit2.Tree()
410436
changes, err := object.DiffTree(tree2, tree1)
411437
if err != nil {
438+
junitSuite.AddMessageFailed("", "error getting git commit changes", err.Error())
412439
return nil, nil, nil, err
413440
}
414441

415442
// Print the list of changed files and their content (patch)
416443
for _, change := range changes {
417444
patch, err := change.Patch()
418445
if err != nil {
446+
junitSuite.AddMessageFailed("", "error getting git patch", err.Error())
419447
return nil, nil, nil, err
420448
}
421449
for _, file := range patch.FilePatches() {
@@ -455,28 +483,32 @@ func cleanGitPatch(patch string) string {
455483
return patch
456484
}
457485

458-
func getGitlabCommitData() ([]string, []string, []map[string]string, error) {
486+
func getGitlabCommitData(junitSuite junit.Interface) ([]string, []string, []map[string]string, error) {
459487
gitlab_url := os.Getenv("CI_API_V4_URL")
460488
token := os.Getenv("API_TOKEN")
461489
mri := os.Getenv("CI_MERGE_REQUEST_IID")
462490
project := os.Getenv("CI_MERGE_REQUEST_PROJECT_ID")
463491

464492
gitlabClient, err := gitlab.NewClient(token, gitlab.WithBaseURL(gitlab_url))
465493
if err != nil {
466-
log.Fatalf("Failed to create gitlab client: %v", err)
494+
junitSuite.AddMessageFailed("", "failed to create gitlab client", err.Error())
495+
return nil, nil, nil, fmt.Errorf("failed to create gitlab client: %w", err)
467496
}
468497

469498
mrIID, err := strconv.Atoi(mri)
470499
if err != nil {
500+
junitSuite.AddMessageFailed("", "invalid merge request id", err.Error())
471501
return nil, nil, nil, fmt.Errorf("invalid merge request id %s", mri)
472502
}
473503

474504
projectID, err := strconv.Atoi(project)
475505
if err != nil {
506+
junitSuite.AddMessageFailed("", "invalid project id", err.Error())
476507
return nil, nil, nil, fmt.Errorf("invalid project id %s", project)
477508
}
478509
commits, _, err := gitlabClient.MergeRequests.GetMergeRequestCommits(projectID, mrIID, &gitlab.GetMergeRequestCommitsOptions{})
479510
if err != nil {
511+
junitSuite.AddMessageFailed("", "error fetching commits", err.Error())
480512
return nil, nil, nil, fmt.Errorf("error fetching commits: %w", err)
481513
}
482514

@@ -489,6 +521,7 @@ func getGitlabCommitData() ([]string, []string, []map[string]string, error) {
489521
if len(l) > 0 {
490522
if len(l) > 1 {
491523
if l[1] != "" {
524+
junitSuite.AddMessageFailed("", "empty line between subject and body is required", fmt.Sprintf("%s %s", hash, l[0]))
492525
return nil, nil, nil, fmt.Errorf("empty line between subject and body is required: %s %s", hash, l[0])
493526
}
494527
}
@@ -497,6 +530,7 @@ func getGitlabCommitData() ([]string, []string, []map[string]string, error) {
497530
messages = append(messages, c.Message)
498531
diff, _, err := gitlabClient.MergeRequests.ListMergeRequestDiffs(projectID, mrIID, &gitlab.ListMergeRequestDiffsOptions{})
499532
if err != nil {
533+
junitSuite.AddMessageFailed("", "error fetching commit changes", err.Error())
500534
return nil, nil, nil, fmt.Errorf("error fetching commit changes: %w", err)
501535
}
502536
content := map[string]string{}
@@ -513,25 +547,25 @@ func getGitlabCommitData() ([]string, []string, []map[string]string, error) {
513547
return subjects, messages, diffs, nil
514548
}
515549

516-
func getCommitData(repoEnv string) ([]string, []string, []map[string]string, error) {
550+
func getCommitData(repoEnv string, junitSuite junit.Interface) ([]string, []string, []map[string]string, error) {
517551
if repoEnv == GITHUB {
518-
return getGithubCommitData()
552+
return getGithubCommitData(junitSuite)
519553
} else if repoEnv == GITLAB {
520-
return getGitlabCommitData()
554+
return getGitlabCommitData(junitSuite)
521555
} else if repoEnv == LOCAL {
522-
return getLocalCommitData()
556+
return getLocalCommitData(junitSuite)
523557
}
524558
return nil, nil, nil, fmt.Errorf("unrecognized git environment %s", repoEnv)
525559
}
526560

527561
var ErrSubjectList = errors.New("subjects contain errors")
528562

529-
func (c CommitPolicyConfig) CheckSubjectList(subjects []string) error {
563+
func (c CommitPolicyConfig) CheckSubjectList(subjects []string, junitSuite junit.Interface) error {
530564
errors := false
531565

532566
for _, subject := range subjects {
533567
subject = strings.Trim(subject, "'")
534-
if err := c.CheckSubject([]byte(subject)); err != nil {
568+
if err := c.CheckSubject([]byte(subject), junitSuite); err != nil {
535569
log.Printf("%s, original subject message '%s'", err, subject)
536570

537571
errors = true

check_different_policy_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"fmt"
55
"testing"
66

7+
"github.com/haproxytech/check-commit/v5/junit"
78
yaml "gopkg.in/yaml.v3"
89
)
910

@@ -100,7 +101,7 @@ func TestDifferentPolicy(t *testing.T) {
100101
tt := tt
101102
t.Run(tt.name, func(t *testing.T) {
102103
t.Parallel()
103-
if err := c.CheckSubject([]byte(tt.subject)); (err != nil) != tt.wantErr {
104+
if err := c.CheckSubject([]byte(tt.subject), &junit.JunitSuiteDummy{}); (err != nil) != tt.wantErr {
104105
t.Errorf("checkSubject() error = %v, wantErr %v", err, tt.wantErr)
105106
}
106107
})

check_test.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package main
22

33
import (
44
"testing"
5+
6+
"github.com/haproxytech/check-commit/v5/junit"
57
)
68

79
func TestCheckSubject(t *testing.T) {
@@ -13,7 +15,7 @@ func TestCheckSubject(t *testing.T) {
1315
tt := tt
1416
t.Run(tt.name, func(t *testing.T) {
1517
t.Parallel()
16-
if err := c.CheckSubject([]byte(tt.subject)); (err != nil) != tt.wantErr {
18+
if err := c.CheckSubject([]byte(tt.subject), &junit.JunitSuiteDummy{}); (err != nil) != tt.wantErr {
1719
t.Errorf("checkSubject() error = %v, wantErr %v", err, tt.wantErr)
1820
}
1921
})

0 commit comments

Comments
 (0)