First commit >:]
This commit is contained in:
163
issuereader.go
Normal file
163
issuereader.go
Normal file
@@ -0,0 +1,163 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/andygrunwald/go-jira"
|
||||
)
|
||||
|
||||
const (
|
||||
JIRA_URL = "https://jirawms.mda.ca"
|
||||
)
|
||||
|
||||
type IssueReader struct {
|
||||
auth jira.BasicAuthTransport //auth data
|
||||
client *jira.Client //jira client
|
||||
score map[string]int //score information
|
||||
}
|
||||
|
||||
func NewIssueReader(user, pass string) *IssueReader {
|
||||
ir := &IssueReader{
|
||||
auth: jira.BasicAuthTransport{
|
||||
Username: strings.TrimSpace(user),
|
||||
Password: strings.TrimSpace(pass),
|
||||
},
|
||||
score: make(map[string]int),
|
||||
}
|
||||
|
||||
var err error
|
||||
ir.client, err = jira.NewClient(ir.auth.Client(), strings.TrimSpace(JIRA_URL))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
return ir
|
||||
}
|
||||
|
||||
func (i *IssueReader) GetScores() map[string]int {
|
||||
return i.score
|
||||
}
|
||||
|
||||
func (i *IssueReader) ZeroScores() {
|
||||
for k := range i.score {
|
||||
i.score[k] = 0
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (i *IssueReader) RefreshScores() map[string]int {
|
||||
|
||||
i.ZeroScores()
|
||||
|
||||
poIssues, er := i.GetAllIssues(i.client, GetBountyJQL())
|
||||
if er != nil {
|
||||
log.Fatal(er)
|
||||
}
|
||||
|
||||
//run through each to check if we've got bounty points to award
|
||||
for _, issue := range poIssues {
|
||||
teamId := i.ParseCustomTeamField(issue.Fields.Unknowns[CUSTOM_FIELD_TEAM])
|
||||
i.ExtractScoreFromComments(teamId, issue.Key)
|
||||
}
|
||||
|
||||
return i.GetScores()
|
||||
}
|
||||
|
||||
// the team field is one of type string after a non-intuitive map decomposition, assert on interface
|
||||
func (i *IssueReader) ParseCustomTeamField(teamField interface{}) string {
|
||||
var str string = ""
|
||||
if teamField != nil {
|
||||
str = teamField.([]interface{})[0].(map[string]interface{})["value"].(string)
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
// given a teamid and jira issue, validate potential PO bounty scores
|
||||
func (i *IssueReader) ExtractScoreFromComments(teamId string, key string) {
|
||||
if i.IsValidTeam(teamId) {
|
||||
is, _, err := i.client.Issue.Get(key, nil)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
comments := is.Fields.Comments.Comments
|
||||
for _, c := range comments {
|
||||
if i.CommentAuthorIsPO(c) {
|
||||
bp := i.ExtractBountyFromComment(c)
|
||||
i.score[teamId] = i.score[teamId] + bp
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check if s exists in Scrum Teams list
|
||||
func (i *IssueReader) IsValidTeam(s string) bool {
|
||||
for _, t := range GetTeamNames() {
|
||||
if strings.Compare(strings.ToLower(s), strings.ToLower(t)) == 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// given a jira.Comment, find and extract the associated PO Bounty points
|
||||
func (i *IssueReader) ExtractBountyFromComment(c *jira.Comment) int {
|
||||
result := 0
|
||||
re := regexp.MustCompile(`POB: (\d+)`)
|
||||
if c != nil {
|
||||
matches := re.FindStringSubmatch(c.Body)
|
||||
|
||||
//we're expecting exactly one principle match and one submatch (2 entries total)
|
||||
if len(matches) == 2 {
|
||||
//submatch must be an integer, or else we simply don't update the result
|
||||
a, err := strconv.Atoi(matches[1])
|
||||
if err == nil {
|
||||
result = a
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// given a specific jira.Comment, find if it was authored by someone int he POList
|
||||
func (i *IssueReader) CommentAuthorIsPO(c *jira.Comment) bool {
|
||||
if c != nil {
|
||||
for _, p := range GetPOList() {
|
||||
if c.Author.Name == p {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// retrieve all issues as per searchString JQL
|
||||
func (i *IssueReader) GetAllIssues(client *jira.Client, searchString string) ([]jira.Issue, error) {
|
||||
last := 0
|
||||
var issues []jira.Issue
|
||||
for {
|
||||
opt := &jira.SearchOptions{
|
||||
MaxResults: 1000, // Max results can go up to 1000
|
||||
StartAt: last,
|
||||
}
|
||||
|
||||
chunk, resp, err := client.Issue.Search(searchString, opt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
total := resp.Total
|
||||
if issues == nil {
|
||||
issues = make([]jira.Issue, 0, total)
|
||||
}
|
||||
issues = append(issues, chunk...)
|
||||
last = resp.StartAt + len(chunk)
|
||||
if last >= total {
|
||||
return issues, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user