< Summary - go-semantic-release Coverage

Information
Line coverage
96%
Covered lines: 93
Uncovered lines: 3
Coverable lines: 96
Total lines: 146
Line coverage: 96.8%
Branch coverage
N/A
Covered branches: 0
Total branches: 0
Branch coverage: N/A
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
Lint0%00100%
checkType0%00100%
checkScope0%00100%
checkDescription0%00100%
checkSubjectLength0%0081.25%
checkBody0%00100%

File(s)

/home/runner/work/go-semantic-release/go-semantic-release/internal/adapters/lint/conventional.go

#LineLine coverage
 1package lint
 2
 3import (
 4  "fmt"
 5  "strings"
 6
 7  "github.com/jedi-knights/go-semantic-release/internal/domain"
 8  "github.com/jedi-knights/go-semantic-release/internal/ports"
 9)
 10
 11// Compile-time interface compliance check.
 12var _ ports.CommitLinter = (*ConventionalLinter)(nil)
 13
 14// ConventionalLinter validates commits against conventional commit rules.
 15type ConventionalLinter struct {
 16  config domain.LintConfig
 17}
 18
 19// NewConventionalLinter creates a new conventional commit linter.
 20func NewConventionalLinter(cfg domain.LintConfig) *ConventionalLinter {
 21  return &ConventionalLinter{config: cfg}
 22}
 23
 24// Lint checks a single commit against all configured rules.
 1025func (l *ConventionalLinter) Lint(commit domain.Commit) []domain.LintViolation {
 1026  violations := make([]domain.LintViolation, 0, 5)
 1027
 1028  violations = append(violations, l.checkType(commit)...)
 1029  violations = append(violations, l.checkScope(commit)...)
 1030  violations = append(violations, l.checkDescription(commit)...)
 1031  violations = append(violations, l.checkSubjectLength(commit)...)
 1032  violations = append(violations, l.checkBody(commit)...)
 1033
 1034  return violations
 1035}
 36
 1037func (l *ConventionalLinter) checkType(commit domain.Commit) []domain.LintViolation {
 138  if commit.Type == "" {
 139    return []domain.LintViolation{{
 140      Rule:     "type-empty",
 141      Message:  "commit message must have a type (e.g., feat, fix)",
 142      Severity: domain.LintError,
 143    }}
 144  }
 45
 946  if len(l.config.AllowedTypes) > 0 {
 947    allowed := false
 948    for _, t := range l.config.AllowedTypes {
 849      if commit.Type == t {
 850        allowed = true
 851        break
 52      }
 53    }
 154    if !allowed {
 155      return []domain.LintViolation{{
 156        Rule:     "type-enum",
 157        Message:  fmt.Sprintf("type %q is not allowed; allowed types: %s", commit.Type, strings.Join(l.config.AllowedTyp
 158        Severity: domain.LintError,
 159      }}
 160    }
 61  }
 62
 863  return nil
 64}
 65
 1066func (l *ConventionalLinter) checkScope(commit domain.Commit) []domain.LintViolation {
 167  if l.config.RequireScope && commit.Scope == "" {
 168    return []domain.LintViolation{{
 169      Rule:     "scope-empty",
 170      Message:  "commit message must have a scope",
 171      Severity: domain.LintError,
 172    }}
 173  }
 74
 275  if commit.Scope != "" && len(l.config.AllowedScopes) > 0 {
 276    allowed := false
 277    for _, s := range l.config.AllowedScopes {
 178      if commit.Scope == s {
 179        allowed = true
 180        break
 81      }
 82    }
 183    if !allowed {
 184      return []domain.LintViolation{{
 185        Rule:     "scope-enum",
 186        Message:  fmt.Sprintf("scope %q is not allowed; allowed scopes: %s", commit.Scope, strings.Join(l.config.Allowed
 187        Severity: domain.LintError,
 188      }}
 189    }
 90  }
 91
 892  return nil
 93}
 94
 1095func (l *ConventionalLinter) checkDescription(commit domain.Commit) []domain.LintViolation {
 196  if commit.Description == "" {
 197    return []domain.LintViolation{{
 198      Rule:     "description-empty",
 199      Message:  "commit message must have a description",
 1100      Severity: domain.LintError,
 1101    }}
 1102  }
 103
 1104  if strings.HasSuffix(commit.Description, ".") {
 1105    return []domain.LintViolation{{
 1106      Rule:     "description-trailing-period",
 1107      Message:  "description must not end with a period",
 1108      Severity: domain.LintWarning,
 1109    }}
 1110  }
 111
 8112  return nil
 113}
 114
 10115func (l *ConventionalLinter) checkSubjectLength(commit domain.Commit) []domain.LintViolation {
 4116  if l.config.MaxSubjectLength <= 0 {
 4117    return nil
 4118  }
 119
 6120  subject := commit.Message
 0121  if idx := strings.IndexByte(subject, '\n'); idx >= 0 {
 0122    subject = subject[:idx]
 0123  }
 124
 1125  if len(subject) > l.config.MaxSubjectLength {
 1126    return []domain.LintViolation{{
 1127      Rule:     "subject-max-length",
 1128      Message:  fmt.Sprintf("subject line is %d characters, maximum is %d", len(subject), l.config.MaxSubjectLength),
 1129      Severity: domain.LintWarning,
 1130    }}
 1131  }
 132
 5133  return nil
 134}
 135
 10136func (l *ConventionalLinter) checkBody(commit domain.Commit) []domain.LintViolation {
 1137  if l.config.RequireBody && commit.Body == "" {
 1138    return []domain.LintViolation{{
 1139      Rule:     "body-empty",
 1140      Message:  "commit message must have a body",
 1141      Severity: domain.LintWarning,
 1142    }}
 1143  }
 144
 9145  return nil
 146}