Skip to content

Commit

Permalink
(#32) Support for commit-msg hook with msg-file flag (#37)
Browse files Browse the repository at this point in the history
  • Loading branch information
llorllale committed Mar 3, 2019
1 parent e7a4e55 commit 8aa4af8
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 17 deletions.
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

0 comments on commit 8aa4af8

Please sign in to comment.