Skip to content
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

(#32) Support for commit-msg hook with msg-file flag #37

Merged
merged 3 commits into from
Mar 3, 2019
Merged
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
41 changes: 34 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,26 +23,53 @@ Flags:
--subject-regex=".*" Commit subject line must conform to this regular expression (default: ".*").
--subject-len=2147483646 Commit subject line cannot exceed this length (default: math.MaxInt32 - 1).
--body-regex=".*" Commit message body must conform to this regular expression (default: ".*").
--since="1970-01-01" A date in "yyyy-MM-dd" format starting from which commits will be analyzed (default: "1970-01-01")
--since="1970-01-01" A date in "yyyy-MM-dd" format starting from which commits will be analyzed (default: "1970-01-01").
--msg-file="" Only analyze the commit message found in this file (default: "").
```
Additionally, it will look for configurations in a file `.gitlint` in the current directory if it exists. This file's format is just the same command line flags but each on a separate line. *Flags passed through the command line take precedence.*

## Integrate to your CI
### Lint your commit msg when committing

Use the [`download-gitlint.sh`](https://raw.githubusercontent.com/llorllale/go-gitlint/master/download-gitlint.sh) script:
Add a `commit-msg` hook to your Git repo:

`curl -sfL https://raw.githubusercontent.com/llorllale/go-gitlint/master/download-gitlint.sh | sh -s 1.0.0`
1. Create hook: `echo 'gitlint --msg-file=$1' > .git/hooks/commit-msg`
2. Make it executable: `chmod +x .git/hooks/commit-msg`

Specifying the version is optional; if you just want the latest, omit the `-s <version>` part.
Now your commits will be validated after saving and closing the commit message in your text editor.

In both cases the correct version for your platform will be downloaded and installed at `$GOPATH/bin`.
### Integrate to your CI

Use [`download-gitlint.sh`](https://raw.githubusercontent.com/llorllale/go-gitlint/master/download-gitlint.sh):

1. `curl https://raw.githubusercontent.com/llorllale/go-gitlint/master/download-gitlint.sh > download-gitlint.sh`
2. `chmod +x download-gitlint.sh`

Usage:
```
$ ./download-gitlint.sh -h
./download-gitlint.sh: download go binaries for llorllale/go-gitlint

Usage: ./download-gitlint.sh [-b] bindir [-d] [tag]
-b sets bindir or installation directory, Defaults to ./bin
-d turns on debug logging
[tag] is a tag from
https://github.com/llorllale/go-gitlint/releases
If tag is missing, then the latest will be used.

Generated by godownloader
https://github.com/goreleaser/godownloader
```

### Exit codes

`gitlint`'s exit code will equal the number of issues found with your commit(s).

## Motivation

- [X] Validate format of commit message subject and body
- [X] Lint commit msgs on varios development platforms (Windows, Linux, Mac)
- [X] Configuration from file with cli args taking precedence
- [ ] [`commit-msg`](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks) hook to validate my commit's msg
- [X] [`commit-msg`](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks) hook to validate my commit's msg
- [X] Performance (because a slow pre-commit hook would render the git workflow unmanageable)
- [X] My first Go project :)

Expand Down
40 changes: 30 additions & 10 deletions cmd/go-gitlint/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,12 @@ import (
// Figure out a way to remove these global variables. Whatever command line
// parser we choose should be able to auto-generate usage.
var (
path = kingpin.Flag("path", `Path to the git repo (default: ".").`).Default(".").String() //nolint[gochecknoglobals]
subjectRegex = kingpin.Flag("subject-regex", `Commit subject line must conform to this regular expression (default: ".*").`).Default(".*").String() //nolint[gochecknoglobals]
subjectLength = kingpin.Flag("subject-len", "Commit subject line cannot exceed this length (default: math.MaxInt32 - 1).").Default(strconv.Itoa(math.MaxInt32 - 1)).Int() //nolint[gochecknoglobals]
bodyRegex = kingpin.Flag("body-regex", `Commit message body must conform to this regular expression (default: ".*").`).Default(".*").String() //nolint[gochecknoglobals]
since = kingpin.Flag("since", `A date in "yyyy-MM-dd" format starting from which commits will be analyzed (default: "1970-01-01")`).Default("1970-01-01").String() //nolint[gochecknoglobals]
path = kingpin.Flag("path", `Path to the git repo (default: ".").`).Default(".").String() //nolint[gochecknoglobals]
subjectRegex = kingpin.Flag("subject-regex", `Commit subject line must conform to this regular expression (default: ".*").`).Default(".*").String() //nolint[gochecknoglobals]
subjectLength = kingpin.Flag("subject-len", "Commit subject line cannot exceed this length (default: math.MaxInt32 - 1).").Default(strconv.Itoa(math.MaxInt32 - 1)).Int() //nolint[gochecknoglobals]
bodyRegex = kingpin.Flag("body-regex", `Commit message body must conform to this regular expression (default: ".*").`).Default(".*").String() //nolint[gochecknoglobals]
since = kingpin.Flag("since", `A date in "yyyy-MM-dd" format starting from which commits will be analyzed (default: "1970-01-01").`).Default("1970-01-01").String() //nolint[gochecknoglobals]
msgFile = kingpin.Flag("msg-file", `Only analyze the commit message found in this file (default: "").`).Default("").String() //nolint[gochecknoglobals]
)

func main() {
Expand All @@ -49,11 +50,23 @@ func main() {
issues.OfBodyRegex(*bodyRegex),
issues.OfSubjectLength(*subjectLength),
},
commits.Since(
*since,
commits.In(
repo.Filesystem(*path),
),
try(
len(*msgFile) > 0,
func() commits.Commits {
file, err := os.Open(*msgFile)
if err != nil {
panic(err)
}
return commits.MsgIn(file)
},
func() commits.Commits {
return commits.Since(
*since,
commits.In(
repo.Filesystem(*path),
),
)
},
),
),
)(),
Expand All @@ -75,3 +88,10 @@ func configure() {
panic(err)
}
}

func try(cond bool, actual, dflt func() commits.Commits) commits.Commits {
if cond {
return actual()
}
return dflt()
}
18 changes: 18 additions & 0 deletions internal/commits/commits.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
package commits

import (
"io"
"io/ioutil"
"strings"
"time"

Expand Down Expand Up @@ -110,3 +112,19 @@ func Since(t string, cmts Commits) Commits {
return filtered
}
}

// MsgIn returns a single fake commit with the message read from this reader.
// This fake commit will have a fake hash and its timestamp will be time.Now().
func MsgIn(reader io.Reader) Commits {
return func() []*Commit {
b, err := ioutil.ReadAll(reader)
if err != nil {
panic(err)
}
return []*Commit{{
Hash: "fakehsh",
Message: string(b),
Date: time.Now(),
}}
}
}
8 changes: 8 additions & 0 deletions internal/commits/commits_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,14 @@ func TestSince(t *testing.T) {
assert.Contains(t, commits, &Commit{Date: after})
}

func TestMsgIn(t *testing.T) {
const message = "test subject\n\ntest body"
commits := MsgIn(strings.NewReader(message))()
assert.Len(t, commits, 1)
assert.Equal(t, "test subject", commits[0].Subject())
assert.Equal(t, "test body", commits[0].Body())
}

// A git repo initialized and with one commit per each of the messages provided.
// This repo is created in a temporary directory; use the cleanup function
// to delete it afterwards.
Expand Down