Skip to content
This repository was archived by the owner on Apr 5, 2023. It is now read-only.

Commit 15e1237

Browse files
committed
Init
Signed-off-by: Nico Schieder <[email protected]>
0 parents  commit 15e1237

File tree

4 files changed

+222
-0
lines changed

4 files changed

+222
-0
lines changed

config.yaml

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
title: LP SRE Weekly Status Update
2+
reports:
3+
- title: APAC
4+
label: mtsre+cssre-apac
5+
- title: EMEA
6+
label: mtsre+cssre-emea
7+
- title: NASA
8+
label: mtsre+cssre-nasa

go.mod

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
module github.com/thetechnick/jira-wrangler
2+
3+
go 1.19
4+
5+
require (
6+
github.com/andygrunwald/go-jira/v2 v2.0.0-20221123211055-094697715517
7+
sigs.k8s.io/yaml v1.3.0
8+
)
9+
10+
require (
11+
github.com/fatih/structs v1.1.0 // indirect
12+
github.com/golang-jwt/jwt/v4 v4.4.2 // indirect
13+
github.com/google/go-querystring v1.1.0 // indirect
14+
github.com/trivago/tgo v1.0.7 // indirect
15+
gopkg.in/yaml.v2 v2.4.0 // indirect
16+
)

go.sum

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
github.com/andygrunwald/go-jira/v2 v2.0.0-20221123211055-094697715517 h1:Ad9ZdMo5iKMaVVOhuCdCl2FFZNKA/YeeK+nP9DU9vyU=
2+
github.com/andygrunwald/go-jira/v2 v2.0.0-20221123211055-094697715517/go.mod h1:8Wg9ZhNoktGf4TO0Bu7PdA25uWIHvkyG1qette1FKz8=
3+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
4+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
5+
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
6+
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
7+
github.com/golang-jwt/jwt/v4 v4.4.2 h1:rcc4lwaZgFMCZ5jxF9ABolDcIHdBytAFgqFPbSJQAYs=
8+
github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
9+
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
10+
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
11+
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
12+
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
13+
github.com/trivago/tgo v1.0.7 h1:uaWH/XIy9aWYWpjm2CU3RpcqZXmX2ysQ9/Go+d9gyrM=
14+
github.com/trivago/tgo v1.0.7/go.mod h1:w4dpD+3tzNIIiIfkWWa85w5/B77tlvdZckQ+6PkFnhc=
15+
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
16+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
17+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
18+
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
19+
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
20+
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
21+
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=

main.go

+177
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"flag"
6+
"fmt"
7+
"os"
8+
"strings"
9+
"time"
10+
11+
jira "github.com/andygrunwald/go-jira/v2/onpremise"
12+
"sigs.k8s.io/yaml"
13+
)
14+
15+
const (
16+
colorCustomFieldID = "customfield_12320845"
17+
targetEndDateCustomFieldID = "customfield_12313942"
18+
reportCommentPrefix = "[report]"
19+
)
20+
21+
var (
22+
colorRank = []string{"Red", "Yellow", "Green"}
23+
)
24+
25+
type Config struct {
26+
Title string `json:"title"`
27+
Reports []ReportConfig `json:"reports"`
28+
}
29+
30+
type ReportConfig struct {
31+
Title string `json:"title"`
32+
Label string `json:"label"`
33+
}
34+
35+
func main() {
36+
var (
37+
jiraToken string
38+
jiraURL string
39+
configFile string
40+
)
41+
flag.StringVar(&jiraToken, "jira-token", "", "JIRA Personal Access Token")
42+
flag.StringVar(&jiraURL, "jira-url", "", "JIRA Server URL")
43+
flag.StringVar(&configFile, "config-file", "config.yaml", "Config file location")
44+
45+
if len(configFile) == 0 {
46+
configFile = "config.yaml"
47+
}
48+
49+
flag.Parse()
50+
51+
tp := jira.BearerAuthTransport{
52+
Token: jiraToken,
53+
}
54+
client, err := jira.NewClient(jiraURL, tp.Client())
55+
if err != nil {
56+
panic(err)
57+
}
58+
59+
var config Config
60+
configFileContent, err := os.ReadFile(configFile)
61+
if err != nil {
62+
panic(err)
63+
}
64+
if err := yaml.Unmarshal(configFileContent, &config); err != nil {
65+
panic(err)
66+
}
67+
68+
now := time.Now().UTC()
69+
fmt.Println(config.Title)
70+
_, week := now.ISOWeek()
71+
fmt.Printf("Week %d - %s\n", week, now.Format(time.RFC822))
72+
fmt.Println()
73+
74+
ctx := context.Background()
75+
for _, report := range config.Reports {
76+
fmt.Println(report.Title)
77+
if err := generateReport(ctx, report, client); err != nil {
78+
panic(err)
79+
}
80+
fmt.Println()
81+
}
82+
}
83+
84+
func generateReport(ctx context.Context, config ReportConfig, client *jira.Client) error {
85+
jql := fmt.Sprintf(
86+
`project = "SDE" AND labels = %q AND Status in ("To Do","In Progress") ORDER BY priority DESC`,
87+
config.Label,
88+
)
89+
issues, _, err := client.Issue.Search(ctx, jql, &jira.SearchOptions{})
90+
if err != nil {
91+
return err
92+
}
93+
94+
issuesByColor := groupIssuesByColor(issues)
95+
for _, issues := range issuesByColor {
96+
for _, i := range issues {
97+
issue, _, err := client.Issue.Get(ctx, i.Key, &jira.GetQueryOptions{})
98+
if err != nil {
99+
return err
100+
}
101+
102+
printIssue(issue)
103+
}
104+
}
105+
return nil
106+
}
107+
108+
func printIssue(issue *jira.Issue) {
109+
fmt.Printf("- [%s] %s\n", issue.Key, issue.Fields.Summary)
110+
fmt.Printf(" Status:\t %s\n", issue.Fields.Status.Name)
111+
color := getColor(issue)
112+
if len(color) > 0 {
113+
fmt.Printf(" Color:\t %s\n", getColor(issue))
114+
}
115+
targedEnd := getCustomField(issue, targetEndDateCustomFieldID)
116+
if len(targedEnd) > 0 {
117+
fmt.Printf(" Target end:\t %s\n", getCustomField(issue, targetEndDateCustomFieldID))
118+
}
119+
comment := statusComment(issue)
120+
if len(comment) > 0 {
121+
fmt.Printf(" Comment:\t %s\n", comment)
122+
}
123+
}
124+
125+
func getColor(issue *jira.Issue) string {
126+
colorField := issue.Fields.Unknowns[colorCustomFieldID]
127+
var c string
128+
if colorFieldMap, ok := colorField.(map[string]interface{}); ok {
129+
c = colorFieldMap["value"].(string)
130+
}
131+
if c == "Not Selected" {
132+
return ""
133+
}
134+
return c
135+
}
136+
137+
func getCustomField(issue *jira.Issue, customFieldID string) string {
138+
field := issue.Fields.Unknowns[customFieldID]
139+
if field == nil {
140+
return ""
141+
}
142+
return fmt.Sprintf("%s", field)
143+
}
144+
145+
func statusComment(issue *jira.Issue) string {
146+
if issue.Fields.Comments == nil {
147+
return ""
148+
}
149+
var latestReportComment string
150+
for _, c := range issue.Fields.Comments.Comments {
151+
trimmedBody := strings.TrimSpace(c.Body)
152+
if strings.HasPrefix(trimmedBody, reportCommentPrefix) {
153+
latestReportComment = strings.TrimSpace(trimmedBody[len(reportCommentPrefix):])
154+
}
155+
}
156+
latestReportComment = strings.ReplaceAll(latestReportComment, "\n", "")
157+
return strings.ReplaceAll(latestReportComment, "\r", "")
158+
}
159+
160+
func groupIssuesByColor(issues []jira.Issue) [][]jira.Issue {
161+
issuesByColor := make([][]jira.Issue, len(colorRank)+1)
162+
colorIndex := map[string]int{}
163+
for i, color := range colorRank {
164+
colorIndex[color] = i
165+
}
166+
for _, issue := range issues {
167+
color := getColor(&issue)
168+
169+
i := len(issuesByColor) - 1
170+
if colorIndex, ok := colorIndex[color]; ok {
171+
i = colorIndex
172+
}
173+
issuesByColor[i] = append(issuesByColor[i], issue)
174+
}
175+
176+
return issuesByColor
177+
}

0 commit comments

Comments
 (0)