Skip to content

Commit eb81053

Browse files
committed
fix(jira): correctly handle issues with null resolution (Fixes #4295)
Signed-off-by: hyunuk <[email protected]>
1 parent e060127 commit eb81053

File tree

2 files changed

+60
-1
lines changed

2 files changed

+60
-1
lines changed

notify/jira/jira.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,9 @@ func (n *Notifier) searchExistingIssue(ctx context.Context, logger *slog.Logger,
198198
jql := strings.Builder{}
199199

200200
if n.conf.WontFixResolution != "" {
201-
jql.WriteString(fmt.Sprintf(`resolution != %q and `, n.conf.WontFixResolution))
201+
// Ensure unresolved issues are included by adding `resolution is EMPTY` condition.
202+
// This avoids excluding issues without a resolution when using `resolution != <value>`.
203+
jql.WriteString(fmt.Sprintf(`(resolution is EMPTY or resolution != %q) and `, n.conf.WontFixResolution))
202204
}
203205

204206
// If the group is firing, do not search for closed issues unless a reopen transition is defined.

notify/jira/jira_test.go

+57
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,19 @@ func TestSearchExistingIssue(t *testing.T) {
8181
return
8282
}
8383
require.Equal(t, expectedJQL, data.JQL)
84+
85+
// Return different responses based on the request
86+
if strings.Contains(data.JQL, `ALERT{2}`) {
87+
// Unresolved issue exists (resolution is EMPTY)
88+
w.Write([]byte(`{"total": 1, "issues": [{"key": "CRM-999", "fields": {"status": {"name": "To Do"}}}]}`))
89+
return
90+
}
91+
if strings.Contains(data.JQL, `ALERT{3}`) {
92+
// Resolved issue exists (resolution is Done)
93+
w.Write([]byte(`{"total": 1, "issues": [{"key": "CRM-998", "fields": {"status": {"name": "Done"}}}]}`))
94+
return
95+
}
96+
// Default: No matching issues found().Add(time.Hour),
8497
w.Write([]byte(`{"total": 0, "issues": []}`))
8598
return
8699
default:
@@ -115,6 +128,50 @@ func TestSearchExistingIssue(t *testing.T) {
115128
groupKey: "1",
116129
expectedJQL: `statusCategory != Done and project="PROJ" and labels="ALERT{1}" order by status ASC,resolutiondate DESC`,
117130
},
131+
{
132+
title: "existing unresolved issue (resolution is EMPTY)",
133+
cfg: &config.JiraConfig{
134+
Summary: `{{ template "jira.default.summary" . }}`,
135+
Description: `{{ template "jira.default.description" . }}`,
136+
Project: `{{ .CommonLabels.project }}`,
137+
WontFixResolution: "Won't Fix",
138+
},
139+
groupKey: "2",
140+
expectedJQL: `(resolution is EMPTY or resolution != "Won't Fix") and statusCategory != Done and project="PROJ" and labels="ALERT{2}" order by status ASC,resolutiondate DESC`,
141+
expectedIssue: &issue{
142+
Key: "CRM-999",
143+
Fields: &issueFields{
144+
Status: &issueStatus{
145+
Name: "To Do",
146+
StatusCategory: struct {
147+
Key string `json:"key"`
148+
}{Key: ""},
149+
},
150+
},
151+
},
152+
},
153+
{
154+
title: "existing resolved issue (resolution Done)",
155+
cfg: &config.JiraConfig{
156+
Summary: `{{ template "jira.default.summary" . }}`,
157+
Description: `{{ template "jira.default.description" . }}`,
158+
Project: `{{ .CommonLabels.project }}`,
159+
WontFixResolution: "Won't Fix",
160+
},
161+
groupKey: "3",
162+
expectedJQL: `(resolution is EMPTY or resolution != "Won't Fix") and statusCategory != Done and project="PROJ" and labels="ALERT{3}" order by status ASC,resolutiondate DESC`,
163+
expectedIssue: &issue{
164+
Key: "CRM-998",
165+
Fields: &issueFields{
166+
Status: &issueStatus{
167+
Name: "Done",
168+
StatusCategory: struct {
169+
Key string `json:"key"`
170+
}{Key: ""},
171+
},
172+
},
173+
},
174+
},
118175
} {
119176
tc := tc
120177
t.Run(tc.title, func(t *testing.T) {

0 commit comments

Comments
 (0)