-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Tarmigan Casebolt
committed
Sep 2, 2016
0 parents
commit 0c67f1a
Showing
5 changed files
with
362 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
language: go | ||
go: | ||
- 1.4 | ||
- 1.6 | ||
- tip | ||
env: | ||
- GOOS=linux | ||
- GOOS=windows GOARCH=386 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
|
||
# prepare-commit-msg-jira | ||
|
||
[![GoDoc](https://godoc.org/github.com/tarm/prepare-commit-msg-jira?status.svg)](http://godoc.org/github.com/tarm/prepare-commit-msg-jira) | ||
|
||
[![Build Status](https://travis-ci.org/tarm/prepare-commit-msg-jira.svg?branch=master)](https://travis-ci.org/tarm/prepare-commit-msg-jira) | ||
|
||
Prepares a git commit message from a Jira issue by fetching the | ||
summary and description and formatting in a way that is appropiate for | ||
a git commit message. It identifies the Jira ticket number from the | ||
name of the git branch that you are on. | ||
|
||
You should install it in your .git/hooks/ directory as 'prepare-commit-msg'. | ||
|
||
It uses the following git configuration items: | ||
|
||
|
||
- jira.url - this is the base url of the jira service. It should | ||
have a trailing '/' | ||
|
||
- jira.regexp - this is a regular expression that extracts the issue | ||
name from the git branch name. | ||
|
||
- jira.jsessionid - this is the value of the JSESSIONID cookie that | ||
jira sets after you login. Get this from your | ||
browser. | ||
|
||
You should set these git configuration items like this: | ||
|
||
|
||
git config --add jira.url <a href="https://jira.atlassian.com">https://jira.atlassian.com</a> | ||
|
||
If it cannot extract the ticket number from the branch or it cannot | ||
find the ticket number in Jira, then the default git commit message | ||
will be used. | ||
|
||
It only prepares a commit message for "normal" commits. It leaves the | ||
git default commit message for ammend, --C, merge, and -m"msg" style | ||
commits. | ||
|
||
It applies the following format for the git commit message: | ||
|
||
|
||
TICKET-12345: The summary line | ||
|
||
Descriptive text is wrapped at 76 characters. This is a really long | ||
line to get the point across. | ||
|
||
Text that is within the {noformat} directive is included without wrapping but is indented by 4 spaces | ||
|
||
Patches (with unit tests) are welcome to improve authentication, | ||
enhance the formatting, etc. | ||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
- - - | ||
Generated by [godoc2md](http://godoc.org/github.com/davecheney/godoc2md) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
/* | ||
Documentation: http://godoc.org/github.com/tarm/prepare-commit-msg-jira | ||
Travis Status: https://travis-ci.org/tarm/prepare-commit-msg-jira | ||
Prepares a git commit message from a Jira issue by fetching the | ||
summary and description and formatting in a way that is appropiate for | ||
a git commit message. It identifies the Jira ticket number from the | ||
name of the git branch that you are on. | ||
You should install it in your .git/hooks/ directory as 'prepare-commit-msg'. | ||
It uses the following git configuration items: | ||
- jira.url - this is the base url of the jira service. It should | ||
have a trailing '/' | ||
- jira.regexp - this is a regular expression that extracts the issue | ||
name from the git branch name. | ||
- jira.jsessionid - this is the value of the JSESSIONID cookie that | ||
jira sets after you login. Get this from your | ||
browser. | ||
You should set these git configuration items like this: | ||
git config --add jira.url https://jira.atlassian.com | ||
If it cannot extract the ticket number from the branch or it cannot | ||
find the ticket number in Jira, then the default git commit message | ||
will be used. | ||
It only prepares a commit message for "normal" commits. It leaves the | ||
git default commit message for ammend, --C, merge, and -m"msg" style | ||
commits. | ||
It applies the following format for the git commit message: | ||
TICKET-12345: The summary line | ||
Descriptive text is wrapped at 76 characters. This is a really long | ||
line to get the point across. | ||
Text that is within the {noformat} directive is included without wrapping but is indented by 4 spaces | ||
Patches (with unit tests) are welcome to improve authentication, | ||
enhance the formatting, etc. | ||
*/ | ||
package main | ||
|
||
//go:generate godoc2md -o README.md github.com/tarm/prepare-commit-msg-jira | ||
|
||
///////////////////////////////////////// | ||
// Fixup the readme to add the badges: // | ||
///////////////////////////////////////// | ||
//go:generate sed -i "s|Documentation: .*|[![GoDoc](https://godoc.org/github.com/tarm/prepare-commit-msg-jira?status.svg)](http://godoc.org/github.com/tarm/prepare-commit-msg-jira)|" README.md | ||
//go:generate sed -i "s|Travis Status: .*|[![Build Status](https://travis-ci.org/tarm/prepare-commit-msg-jira.svg?branch=master)](https://travis-ci.org/tarm/prepare-commit-msg-jira)|" README.md |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
package main | ||
|
||
import ( | ||
"encoding/hex" | ||
"testing" | ||
|
||
jira "github.com/andygrunwald/go-jira" | ||
) | ||
|
||
const expFormat = `EXAM-1234: This is an example summary | ||
Here is the description. It has some lines that are seperated by only a single \n. They will | ||
be combined together and wrapped. | ||
A double newline should be it's own paragraph | ||
A noformat section should be intented | ||
` | ||
|
||
func TestFormat(t *testing.T) { | ||
issue := &jira.Issue{ | ||
Key: "EXAM-1234", | ||
Fields: &jira.IssueFields{ | ||
Summary: "This is an example summary", | ||
Description: `Here is the description. | ||
It has some lines that are seperated by only a single \n. They will be combined together and wrapped. | ||
A double newline should be it's own paragraph | ||
{noformat} | ||
A noformat section should be intented | ||
{noformat} | ||
`, | ||
}, | ||
} | ||
|
||
out := formatForGit(issue) | ||
|
||
if string(out) != expFormat { | ||
t.Logf("%s\n", out) | ||
t.Fatalf("Bad formatting. Expected:\n\n%v\nGot\n\n%v", hex.Dump([]byte(expFormat)), hex.Dump(out)) | ||
} | ||
} | ||
|
||
func TestFetch(t *testing.T) { | ||
issue, err := fetchIssue("JRA-808", "9D8B6D83F4E00F3A83EC0A76304DE343.node1", "https://jira.atlassian.com") | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
if issue == nil { | ||
t.Fatal("Should not have nil issue") | ||
} | ||
if issue.Fields.Summary != "jsessionid trouble" { | ||
t.Fatalf("Unexpected summary %v", issue.Fields.Summary) | ||
} | ||
if len(issue.Fields.Description) != 1230 { | ||
t.Fatalf("Got bad description length %v", len(issue.Fields.Description)) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,176 @@ | ||
package main | ||
|
||
import ( | ||
"bytes" | ||
"fmt" | ||
"io/ioutil" | ||
"log" | ||
"net/http" | ||
"net/http/cookiejar" | ||
"net/url" | ||
"os" | ||
"os/exec" | ||
"regexp" | ||
"strings" | ||
|
||
jira "github.com/andygrunwald/go-jira" | ||
) | ||
|
||
func main() { | ||
// Don't modify if a pre-existing message exists | ||
if len(os.Args) > 2 { | ||
return | ||
} | ||
|
||
jsessionid, err := getGitConfig("jira.jsessionid") | ||
if err != nil { | ||
log.Fatal("Please set jira.jsessionid in you git config") | ||
} | ||
jurl, err := getGitConfig("jira.url") | ||
if err != nil { | ||
log.Fatal("Please set jira.url in your git config") | ||
} | ||
jregex, err := getGitConfig("jira.regexp") | ||
if err != nil { | ||
log.Fatal("Please set jira.regexp in your git config") | ||
} | ||
re, err := regexp.Compile(jregex) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
|
||
// Get the name from the branch | ||
out, err := exec.Command("git", "rev-parse", "--abbrev-ref", "HEAD").CombinedOutput() | ||
if err != nil { | ||
log.Fatal("Could not get branch name", err) | ||
} | ||
name := string(re.Find(out)) | ||
if name == "" { | ||
// We still want to allow regular committing | ||
fmt.Println("No matching branch found") | ||
return | ||
} | ||
|
||
issue, err := fetchIssue(name, jsessionid, jurl) | ||
if err != nil { | ||
// We still want to allow regular committing | ||
fmt.Println(err) | ||
return | ||
} | ||
|
||
err = ioutil.WriteFile(os.Args[1], formatForGit(issue), 0644) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
} | ||
|
||
func getGitConfig(key string) (string, error) { | ||
out, err := exec.Command("git", "config", "--get", key).CombinedOutput() | ||
return string(bytes.TrimSpace(out)), err | ||
} | ||
|
||
const lineLen = 76 | ||
|
||
// 1) Puts the summary at the top | ||
// 2) wraps long lines at 76 characters | ||
// 3) prettifies some jira formatting | ||
// - {noformat} gets indented by 4 spaces | ||
// - TODO more things like tables, quotes, and numbered lists | ||
func formatForGit(i *jira.Issue) []byte { | ||
var buf bytes.Buffer | ||
|
||
// Summary | ||
fmt.Fprintf(&buf, "%v: %v\n\n", i.Key, i.Fields.Summary) | ||
|
||
// Wrap some lines | ||
str := strings.Replace(i.Fields.Description, "\r", "", -1) | ||
pars := strings.Split(str, "\n") | ||
count := 0 | ||
noformat := false | ||
for i := range pars { | ||
if noformat { | ||
if pars[i] == "{noformat}" { | ||
noformat = false | ||
} else { | ||
fmt.Fprintf(&buf, " %v\n", pars[i]) | ||
} | ||
continue | ||
} | ||
if pars[i] == "{noformat}" { | ||
if count != 0 { | ||
buf.WriteString("\n\n") | ||
count = 0 | ||
} | ||
noformat = true | ||
continue | ||
} | ||
|
||
if len(pars[i]) == 0 { | ||
// Double newline | ||
if count != 0 { | ||
buf.WriteString("\n") | ||
count = 0 | ||
} | ||
buf.WriteString("\n") | ||
continue | ||
} | ||
firstChar := pars[i][0] | ||
switch { | ||
case firstChar >= 'a' && firstChar <= 'z': | ||
case firstChar >= 'A' && firstChar <= 'Z': | ||
case firstChar >= '0' && firstChar <= '9': | ||
default: | ||
if count != 0 { | ||
buf.WriteString("\n") | ||
} | ||
buf.WriteString(pars[i]) | ||
buf.WriteString("\n") | ||
count = 0 | ||
continue | ||
} | ||
words := strings.Fields(pars[i]) | ||
for _, word := range words { | ||
if count+len(word) > lineLen { | ||
buf.WriteString("\n") | ||
count = 0 | ||
} | ||
fmt.Fprintf(&buf, "%v ", word) | ||
count += len(word) | ||
} | ||
} | ||
|
||
return buf.Bytes() | ||
} | ||
|
||
func fetchIssue(name, jsessionid, jurl string) (*jira.Issue, error) { | ||
jar, err := cookiejar.New(nil) | ||
if err != nil { | ||
return nil, err | ||
} | ||
jurlp, err := url.Parse(jurl) | ||
if err != nil { | ||
return nil, err | ||
} | ||
jar.SetCookies(jurlp, []*http.Cookie{{ | ||
Name: "JSESSIONID", | ||
Value: jsessionid, | ||
}}) | ||
cl := &http.Client{ | ||
Jar: jar, | ||
} | ||
|
||
c, err := jira.NewClient(cl, jurl) | ||
if err != nil { | ||
return nil, err | ||
} | ||
issue, resp, err := c.Issue.Get(name) | ||
if err != nil { | ||
if resp != nil { | ||
body, _ := ioutil.ReadAll(resp.Body) | ||
err = fmt.Errorf("%v %v", err, string(body)) | ||
} | ||
return nil, err | ||
} | ||
|
||
return issue, nil | ||
} |