Skip to content

Commit 446e516

Browse files
feat!: add config lookupAndParse, env option
* precedence is env, 4 config files, then default config * --config flag has highest precedence
1 parent 3931b36 commit 446e516

File tree

2 files changed

+96
-65
lines changed

2 files changed

+96
-65
lines changed

config/config.go

Lines changed: 77 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -9,31 +9,32 @@ import (
99
"path/filepath"
1010

1111
"golang.org/x/mod/semver"
12-
yaml "gopkg.in/yaml.v3"
12+
yaml "gopkg.in/yaml.v2"
1313

1414
"github.com/conventionalcommit/commitlint/internal"
1515
"github.com/conventionalcommit/commitlint/internal/registry"
1616
"github.com/conventionalcommit/commitlint/lint"
1717
)
1818

19-
const (
20-
// ConfigFile represent default config file name
21-
ConfigFile = "commitlint.yaml"
22-
)
19+
const commitlintConfig = "COMMITLINT_CONFIG"
20+
21+
var configFiles = []string{
22+
".commitlint.yml",
23+
".commitlint.yaml",
24+
"commitlint.yml",
25+
"commitlint.yaml",
26+
}
2327

24-
// GetConfig gets the config path according to the precedence
25-
// if needed parses given config file and returns config instance
26-
func GetConfig(confPath string) (*lint.Config, error) {
27-
confFilePath, useDefault, err := getConfigPath(confPath)
28+
// Parse parse given file in confPath, and return Config instance, error if any
29+
func Parse(confPath string) (*lint.Config, error) {
30+
confPath = filepath.Clean(confPath)
31+
confBytes, err := os.ReadFile(confPath)
2832
if err != nil {
2933
return nil, err
3034
}
3135

32-
if useDefault {
33-
return defConf, nil
34-
}
35-
36-
conf, err := Parse(confFilePath)
36+
conf := &lint.Config{}
37+
err = yaml.UnmarshalStrict(confBytes, conf)
3738
if err != nil {
3839
return nil, err
3940
}
@@ -49,55 +50,18 @@ func GetConfig(confPath string) (*lint.Config, error) {
4950
return conf, nil
5051
}
5152

52-
// getConfigPath returns config file path following below order
53-
// 1. commitlint.yaml in current directory
54-
// 2. confFilePath parameter
55-
// 3. use default config
56-
func getConfigPath(confFilePath string) (confPath string, isDefault bool, retErr error) {
57-
// get current directory
58-
currentDir, err := os.Getwd()
59-
if err != nil {
60-
return "", false, err
61-
}
62-
63-
// check if conf file exists in current directory
64-
currentDirConf := filepath.Join(currentDir, ConfigFile)
65-
if _, err1 := os.Stat(currentDirConf); !os.IsNotExist(err1) {
66-
return currentDirConf, false, nil
67-
}
68-
69-
// if confFilePath empty,
70-
// means no config in current directory or config flag is empty
71-
// use default config
72-
if confFilePath == "" {
73-
return "", true, nil
74-
}
75-
return filepath.Clean(confFilePath), false, nil
76-
}
77-
78-
// Parse parse given file in confPath, and return Config instance, error if any
79-
func Parse(confPath string) (*lint.Config, error) {
80-
confPath = filepath.Clean(confPath)
81-
confBytes, err := os.ReadFile(confPath)
82-
if err != nil {
83-
return nil, err
84-
}
85-
86-
conf := &lint.Config{}
87-
err = yaml.Unmarshal(confBytes, conf)
88-
if err != nil {
89-
return nil, err
90-
}
91-
return conf, nil
92-
}
93-
9453
// Validate validates given config instance, it checks the following
9554
// If formatters, rules are registered/known
9655
// If arguments to rules are valid
9756
// If version is valid and atleast minimum than commitlint version used
9857
func Validate(conf *lint.Config) []error {
9958
var errs []error
10059

60+
err := isValidVersion(conf.MinVersion)
61+
if err != nil {
62+
errs = append(errs, err)
63+
}
64+
10165
if conf.Formatter == "" {
10266
errs = append(errs, errors.New("formatter is empty"))
10367
} else {
@@ -107,16 +71,10 @@ func Validate(conf *lint.Config) []error {
10771
}
10872
}
10973

110-
err := isValidVersion(conf.MinVersion)
111-
if err != nil {
112-
errs = append(errs, err)
113-
}
114-
11574
for ruleName, r := range conf.Rules {
11675
// Check Severity Level of rule config
11776
switch r.Severity {
118-
case lint.SeverityError:
119-
case lint.SeverityWarn:
77+
case lint.SeverityError, lint.SeverityWarn:
12078
default:
12179
errs = append(errs, fmt.Errorf("unknown severity level '%s' for rule '%s'", r.Severity, ruleName))
12280
}
@@ -136,6 +94,56 @@ func Validate(conf *lint.Config) []error {
13694
return errs
13795
}
13896

97+
// LookupAndParse gets the config path according to the precedence
98+
// if exists, parses the config file and returns config instance
99+
func LookupAndParse() (*lint.Config, error) {
100+
confFilePath, useDefault, err := lookupConfigPath()
101+
if err != nil {
102+
return nil, err
103+
}
104+
105+
if useDefault {
106+
return defConf, nil
107+
}
108+
109+
conf, err := Parse(confFilePath)
110+
if err != nil {
111+
return nil, err
112+
}
113+
return conf, nil
114+
}
115+
116+
// lookupConfigPath returns config file path following below order
117+
// 1. env path
118+
// 2. commitlint.yaml in current directory
119+
// 3. use default config
120+
func lookupConfigPath() (confPath string, isDefault bool, retErr error) {
121+
envConf := os.Getenv(commitlintConfig)
122+
if envConf != "" {
123+
envConf = filepath.Clean(envConf)
124+
if _, err1 := os.Stat(envConf); !os.IsNotExist(err1) {
125+
return envConf, false, nil
126+
}
127+
}
128+
129+
// get current directory
130+
currentDir, err := os.Getwd()
131+
if err != nil {
132+
return "", false, err
133+
}
134+
135+
// check if conf file exists in current directory
136+
for _, confFile := range configFiles {
137+
currentDirConf := filepath.Join(currentDir, confFile)
138+
if _, err1 := os.Stat(currentDirConf); !os.IsNotExist(err1) {
139+
return currentDirConf, false, nil
140+
}
141+
}
142+
143+
// default config
144+
return "", true, nil
145+
}
146+
139147
// WriteToFile util func to write config object to given file
140148
func WriteToFile(outFilePath string, conf *lint.Config) (retErr error) {
141149
f, err := os.Create(outFilePath)
@@ -158,6 +166,12 @@ func WriteToFile(outFilePath string, conf *lint.Config) (retErr error) {
158166
}()
159167

160168
enc := yaml.NewEncoder(w)
169+
defer func() {
170+
err := enc.Close()
171+
if retErr == nil && err != nil {
172+
retErr = err
173+
}
174+
}()
161175
return enc.Encode(conf)
162176
}
163177

internal/cmd/lint.go

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package cmd
22

33
import (
44
"os"
5+
"path/filepath"
56

67
"github.com/conventionalcommit/commitlint/config"
78
"github.com/conventionalcommit/commitlint/lint"
@@ -30,8 +31,8 @@ func runLint(confFilePath, fileInput string) (lintResult string, hasError bool,
3031
return resStr, hasErrorSeverity(res), nil
3132
}
3233

33-
func getLinter(confFilePath string) (*lint.Linter, lint.Formatter, error) {
34-
conf, err := config.GetConfig(confFilePath)
34+
func getLinter(confParam string) (*lint.Linter, lint.Formatter, error) {
35+
conf, err := getConfig(confParam)
3536
if err != nil {
3637
return nil, nil, err
3738
}
@@ -49,6 +50,21 @@ func getLinter(confFilePath string) (*lint.Linter, lint.Formatter, error) {
4950
return linter, format, nil
5051
}
5152

53+
func getConfig(confParam string) (*lint.Config, error) {
54+
if confParam != "" {
55+
confParam = filepath.Clean(confParam)
56+
return config.Parse(confParam)
57+
}
58+
59+
// If config param is empty, lookup for defaults
60+
conf, err := config.LookupAndParse()
61+
if err != nil {
62+
return nil, err
63+
}
64+
65+
return conf, nil
66+
}
67+
5268
func getCommitMsg(fileInput string) (string, error) {
5369
commitMsg, err := readStdInPipe()
5470
if err != nil {
@@ -64,6 +80,7 @@ func getCommitMsg(fileInput string) (string, error) {
6480
fileInput = "./.git/COMMIT_EDITMSG"
6581
}
6682

83+
fileInput = filepath.Clean(fileInput)
6784
inBytes, err := os.ReadFile(fileInput)
6885
if err != nil {
6986
return "", err

0 commit comments

Comments
 (0)