Skip to content

Refactor: Consistent Error Handling & Improved README #19

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ commitlint checks if your commit message meets the [conventional commit format](
- [Commit Types](#commit-types)
- [Available Rules](#available-rules)
- [Available Formatters](#available-formatters)
- [Common Installation Issues](#common-installation-issues)
- [Extensibility](#extensibility)
- [FAQ](#faq)
- [License](#license)
Expand Down Expand Up @@ -247,6 +248,60 @@ Total 1 errors, 0 warnings, 0 other severities
{"input":"fear: do not fear for commit message","issues":[{"description":"type 'fear' is not allowed, you can use one of [build chore ci docs feat fix perf refactor revert style test]","name":"type-enum","severity":"error"}]}
```

## Common Installation Issues

If you encounter the `command not found: commitlint` error after installing `commitlint`, this likely means the binary is not in your system's `PATH`. Follow these steps to resolve this issue:

1. **Ensure `GOPATH/bin` is in your `PATH`**:
By default, Go installs binaries to `$GOPATH/bin` or `$HOME/go/bin` if `GOPATH` is not set. Add this directory to your `PATH`:

```bash
export PATH=$PATH:$GOPATH/bin
```

Or, if `GOPATH` is not set:

```bash
export PATH=$PATH:$HOME/go/bin
```

Add this line to your shell configuration file (e.g., `~/.bashrc`, `~/.zshrc`) to make the change permanent:

```bash
echo 'export PATH=$PATH:$HOME/go/bin' >> ~/.zshrc
source ~/.zshrc
```

2. **Verify the Installation**:
Confirm that the `commitlint` binary is in the expected directory:

```bash
ls $GOPATH/bin/commitlint
```

Or:

```bash
ls $HOME/go/bin/commitlint
```

3. **Reinstall if Necessary**:
If the binary is missing, reinstall `commitlint`:

```bash
go install github.com/conventionalcommit/commitlint@latest
```

4. **Post-Verification**:
After following these steps, try running `commitlint` again:

```bash
commitlint init --global
```

This should allow `commitlint` to be recognized as a command in your terminal.


## Extensibility

## FAQ
Expand Down
10 changes: 5 additions & 5 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
module github.com/conventionalcommit/commitlint

go 1.17
go 1.23.0

require (
github.com/conventionalcommit/parser v0.7.1
github.com/urfave/cli/v2 v2.11.1
golang.org/x/mod v0.5.1
github.com/urfave/cli/v2 v2.27.5
golang.org/x/mod v0.21.0
gopkg.in/yaml.v2 v2.4.0
)

require (
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
)
8 changes: 8 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,24 @@ github.com/conventionalcommit/parser v0.7.1 h1:oAzcrEqyyGnzCeNOBqGx2qnxISxneUuBi
github.com/conventionalcommit/parser v0.7.1/go.mod h1:k3teTA7nWpRrk7sjAihpAXm+1QLu1OscGrxclMHgEyc=
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc=
github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/urfave/cli/v2 v2.11.1 h1:UKK6SP7fV3eKOefbS87iT9YHefv7iB/53ih6e+GNAsE=
github.com/urfave/cli/v2 v2.11.1/go.mod h1:f8iq5LtQ/bLxafbdBSLPPNsgaW0l/2fYYEHhAyPlwvo=
github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w=
github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4=
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38=
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
Expand Down
19 changes: 10 additions & 9 deletions internal/cmd/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ package cmd
import (
"fmt"

cli "github.com/urfave/cli/v2"
"github.com/urfave/cli/v2"

"github.com/conventionalcommit/commitlint/internal"
)
Expand Down Expand Up @@ -49,7 +49,8 @@ func newLintCmd() *cli.Command {
Action: func(ctx *cli.Context) error {
confFilePath := ctx.String("config")
fileInput := ctx.String("message")
return lintMsg(confFilePath, fileInput)
err := lintMsg(confFilePath, fileInput)
return handleError(err, "Failed to run lint command")
},
}
}
Expand All @@ -76,7 +77,7 @@ func newInitCmd() *cli.Command {
hooksPath := ctx.String("hookspath")

err := initLint(confPath, hooksPath, isGlobal, isReplace)
if err != nil {
if handleError(err, "Failed to initialize commitlint") != nil {
if isHookExists(err) {
fmt.Println("commitlint init failed")
fmt.Println("run with --replace to replace existing files")
Expand Down Expand Up @@ -112,7 +113,7 @@ func newConfigCmd() *cli.Command {
isReplace := ctx.Bool("replace")
fileName := ctx.String("file")
err := configCreate(fileName, isReplace)
if err != nil {
if handleError(err, "Failed to create config file") != nil {
if isConfExists(err) {
fmt.Println("config create failed")
fmt.Println("run with --replace to replace existing file")
Expand Down Expand Up @@ -144,10 +145,10 @@ func newConfigCmd() *cli.Command {
return nil
}
if len(errs) == 1 {
return errs[0]
return handleError(errs[0], "Config check failed")
}
merr := multiError(errs)
return &merr
return handleError(&merr, "Config check failed")
},
}

Expand All @@ -170,9 +171,9 @@ func newHookCmd() *cli.Command {
isReplace := ctx.Bool("replace")
hooksPath := ctx.String("hookspath")
err := hookCreate(hooksPath, isReplace)
if err != nil {
if handleError(err, "Failed to create hooks") != nil {
if isHookExists(err) {
fmt.Println("create failed. hook files already exists")
fmt.Println("create failed. hook files already exist")
fmt.Println("run with --replace to replace existing hook files")
return nil
}
Expand All @@ -195,7 +196,7 @@ func newDebugCmd() *cli.Command {
Name: "debug",
Usage: "prints useful information for debugging",
Action: func(ctx *cli.Context) error {
return printDebug()
return handleError(printDebug(), "Debugging information failed")
},
}
}
Expand Down
3 changes: 2 additions & 1 deletion internal/cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import (

// Run runs commitlint cli with os.Args
func Run() error {
return newCliApp().Run(os.Args)
err := newCliApp().Run(os.Args)
return handleError(err, "Failed to run commitlint CLI")
}

type multiError []error
Expand Down
13 changes: 7 additions & 6 deletions internal/cmd/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,41 +11,42 @@ import (
// configCreate is the callback function for create config command
func configCreate(fileName string, isReplace bool) (retErr error) {
outPath := filepath.Join(".", fileName)

// if config file already exists skip creating or overwriting it
if _, err := os.Stat(outPath); !os.IsNotExist(err) {
if !isReplace {
return errConfigExist
return handleError(errConfigExist, "Config file already exists")
}
}

outFilePath := filepath.Clean(outPath)
f, err := os.Create(outFilePath)
if err != nil {
if handleError(err, "Failed to create config file") != nil {
return err
}
defer func() {
err := f.Close()
if retErr == nil && err != nil {
retErr = err
retErr = handleError(err, "Failed to close config file")
}
}()

w := bufio.NewWriter(f)
defer func() {
err := w.Flush()
if retErr == nil && err != nil {
retErr = err
retErr = handleError(err, "Failed to flush writer")
}
}()

defConf := config.NewDefault()
return config.WriteTo(w, defConf)
return handleError(config.WriteTo(w, defConf), "Failed to write config to file")
}

// configCheck is the callback function for check/verify command
func configCheck(confPath string) []error {
conf, err := config.Parse(confPath)
if err != nil {
if handleError(err, "Failed to parse configuration file") != nil {
return []error{err}
}
return config.Validate(conf)
Expand Down
12 changes: 6 additions & 6 deletions internal/cmd/debug.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,22 @@ func printDebug() error {
w.WriteByte('\n')

gitVer, err := getGitVersion()
if err != nil {
if handleError(err, "Failed to get Git version") != nil {
return err
}

localConf, err := getGitHookConfig(false)
if err != nil {
if handleError(err, "Failed to get local Git hook configuration") != nil {
return err
}

globalConf, err := getGitHookConfig(true)
if err != nil {
if handleError(err, "Failed to get global Git hook configuration") != nil {
return err
}

confFile, confType, err := internal.LookupConfigPath()
if err != nil {
if handleError(err, "Failed to lookup configuration path") != nil {
return err
}

Expand Down Expand Up @@ -67,7 +67,7 @@ func getGitVersion() (string, error) {
cmd.Stdout = b
cmd.Stderr = os.Stderr
err := cmd.Run()
if err != nil {
if handleError(err, "Failed to execute 'git version' command") != nil {
return "", err
}

Expand All @@ -90,7 +90,7 @@ func getGitHookConfig(isGlobal bool) (string, error) {
cmd.Stdout = b

err := cmd.Run()
if err != nil {
if handleError(err, "Failed to execute 'git config core.hooksPath' command") != nil {
return "", err
}

Expand Down
17 changes: 17 additions & 0 deletions internal/cmd/error.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package cmd

import (
"fmt"
"os"

"github.com/urfave/cli/v2"
)

// handleError handles and logs errors in a consistent way
func handleError(err error, customMessage string) error {
if err != nil {
fmt.Fprintf(os.Stderr, "ERROR: %s - %v\n", customMessage, err)
return cli.Exit(customMessage, 1)
}
return nil
}
Loading