Skip to content

Commit 05e380a

Browse files
wallee94Walther Lee
and
Walther Lee
authored
Render Jira project template when searching for existing issues (#4291)
* render jira project when searching existing issues Signed-off-by: Walther Lee <[email protected]> * golangci-lint run --fix Signed-off-by: Walther Lee <[email protected]> --------- Signed-off-by: Walther Lee <[email protected]> Co-authored-by: Walther Lee <[email protected]>
1 parent b04a0c4 commit 05e380a

File tree

2 files changed

+105
-3
lines changed

2 files changed

+105
-3
lines changed

Diff for: notify/jira/jira.go

+7-3
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ func (n *Notifier) Notify(ctx context.Context, as ...*types.Alert) (bool, error)
8787
method = http.MethodPost
8888
)
8989

90-
existingIssue, shouldRetry, err := n.searchExistingIssue(ctx, logger, key.Hash(), alerts.HasFiring())
90+
existingIssue, shouldRetry, err := n.searchExistingIssue(ctx, logger, key.Hash(), alerts.HasFiring(), tmplTextFunc)
9191
if err != nil {
9292
return shouldRetry, fmt.Errorf("failed to look up existing issues: %w", err)
9393
}
@@ -194,7 +194,7 @@ func (n *Notifier) prepareIssueRequestBody(ctx context.Context, logger *slog.Log
194194
return requestBody, nil
195195
}
196196

197-
func (n *Notifier) searchExistingIssue(ctx context.Context, logger *slog.Logger, groupID string, firing bool) (*issue, bool, error) {
197+
func (n *Notifier) searchExistingIssue(ctx context.Context, logger *slog.Logger, groupID string, firing bool, tmplTextFunc templateFunc) (*issue, bool, error) {
198198
jql := strings.Builder{}
199199

200200
if n.conf.WontFixResolution != "" {
@@ -214,7 +214,11 @@ func (n *Notifier) searchExistingIssue(ctx context.Context, logger *slog.Logger,
214214
}
215215

216216
alertLabel := fmt.Sprintf("ALERT{%s}", groupID)
217-
jql.WriteString(fmt.Sprintf(`project=%q and labels=%q order by status ASC,resolutiondate DESC`, n.conf.Project, alertLabel))
217+
project, err := tmplTextFunc(n.conf.Project)
218+
if err != nil {
219+
return nil, false, fmt.Errorf("invalid project template or value: %w", err)
220+
}
221+
jql.WriteString(fmt.Sprintf(`project=%q and labels=%q order by status ASC,resolutiondate DESC`, project, alertLabel))
218222

219223
requestBody := issueSearch{
220224
JQL: jql.String(),

Diff for: notify/jira/jira_test.go

+98
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,104 @@ func TestJiraRetry(t *testing.T) {
6262
}
6363
}
6464

65+
func TestSearchExistingIssue(t *testing.T) {
66+
expectedJQL := ""
67+
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
68+
switch r.URL.Path {
69+
case "/search":
70+
body, err := io.ReadAll(r.Body)
71+
if err != nil {
72+
http.Error(w, "Error reading request body", http.StatusBadRequest)
73+
return
74+
}
75+
defer r.Body.Close()
76+
77+
// Unmarshal the JSON data into the struct
78+
var data issueSearch
79+
err = json.Unmarshal(body, &data)
80+
if err != nil {
81+
http.Error(w, "Error unmarshaling JSON", http.StatusBadRequest)
82+
return
83+
}
84+
require.Equal(t, expectedJQL, data.JQL)
85+
w.Write([]byte(`{"total": 0, "issues": []}`))
86+
return
87+
default:
88+
dec := json.NewDecoder(r.Body)
89+
out := make(map[string]any)
90+
err := dec.Decode(&out)
91+
if err != nil {
92+
panic(err)
93+
}
94+
}
95+
}))
96+
97+
defer srv.Close()
98+
u, _ := url.Parse(srv.URL)
99+
100+
for _, tc := range []struct {
101+
title string
102+
cfg *config.JiraConfig
103+
groupKey string
104+
expectedJQL string
105+
expectedIssue *issue
106+
expectedErr bool
107+
expectedRetry bool
108+
}{
109+
{
110+
title: "search existing issue with project template",
111+
cfg: &config.JiraConfig{
112+
Summary: `{{ template "jira.default.summary" . }}`,
113+
Description: `{{ template "jira.default.description" . }}`,
114+
Project: `{{ .CommonLabels.project }}`,
115+
},
116+
groupKey: "1",
117+
expectedJQL: `statusCategory != Done and project="PROJ" and labels="ALERT{1}" order by status ASC,resolutiondate DESC`,
118+
},
119+
} {
120+
tc := tc
121+
t.Run(tc.title, func(t *testing.T) {
122+
expectedJQL = tc.expectedJQL
123+
tc.cfg.APIURL = &config.URL{URL: u}
124+
tc.cfg.HTTPConfig = &commoncfg.HTTPClientConfig{}
125+
126+
as := []*types.Alert{
127+
{
128+
Alert: model.Alert{
129+
Labels: model.LabelSet{
130+
"project": "PROJ",
131+
},
132+
StartsAt: time.Now(),
133+
EndsAt: time.Now().Add(time.Hour),
134+
},
135+
},
136+
}
137+
138+
pd, err := New(tc.cfg, test.CreateTmpl(t), promslog.NewNopLogger())
139+
require.NoError(t, err)
140+
logger := pd.logger.With("group_key", tc.groupKey)
141+
142+
ctx := notify.WithGroupKey(context.Background(), tc.groupKey)
143+
data := notify.GetTemplateData(ctx, pd.tmpl, as, logger)
144+
145+
var tmplTextErr error
146+
tmplText := notify.TmplText(pd.tmpl, data, &tmplTextErr)
147+
tmplTextFunc := func(tmpl string) (string, error) {
148+
return tmplText(tmpl), tmplTextErr
149+
}
150+
151+
issue, retry, err := pd.searchExistingIssue(ctx, logger, tc.groupKey, true, tmplTextFunc)
152+
if tc.expectedErr {
153+
require.Error(t, err)
154+
} else {
155+
require.NoError(t, err)
156+
}
157+
require.EqualValues(t, tc.expectedIssue, issue)
158+
require.Equal(t, tc.expectedRetry, retry)
159+
})
160+
}
161+
}
162+
65163
func TestJiraTemplating(t *testing.T) {
66164
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
67165
switch r.URL.Path {

0 commit comments

Comments
 (0)