Skip to content

Commit f836842

Browse files
committed
fix
1 parent b0b3230 commit f836842

File tree

5 files changed

+80
-45
lines changed

5 files changed

+80
-45
lines changed

tools/flakeguard/.flaky_test_db.json

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,13 @@
33
"test_package": "github.com/smartcontractkit/chainlink/deployment/environment/crib",
44
"test_name": "TestShouldProvideEnvironmentConfig",
55
"jira_ticket": "DX-291",
6-
"is_skipped": true,
7-
"skipped_at": "2025-03-24T15:39:48.839992Z"
6+
"skipped_at": "0001-01-01T00:00:00Z"
87
},
98
"github.com/smartcontractkit/chainlink/integration-tests/smoke/ccip::TestRMN_DifferentRmnNodesForDifferentChains": {
109
"test_package": "github.com/smartcontractkit/chainlink/integration-tests/smoke/ccip",
1110
"test_name": "TestRMN_DifferentRmnNodesForDifferentChains",
1211
"jira_ticket": "DX-202",
13-
"is_skipped": true,
14-
"skipped_at": "2025-03-24T15:44:09.201139Z"
12+
"skipped_at": "0001-01-01T00:00:00Z"
1513
},
1614
"github.com/smartcontractkit/chainlink/integration-tests/smoke/ccip::TestRMN_GlobalCurseTwoMessagesOnTwoLanes": {
1715
"test_package": "github.com/smartcontractkit/chainlink/integration-tests/smoke/ccip",
@@ -23,14 +21,13 @@
2321
"test_package": "github.com/smartcontractkit/chainlink/integration-tests/smoke/ccip",
2422
"test_name": "TestRMN_MultipleMessagesOnOneLaneNoWaitForExec",
2523
"jira_ticket": "DX-201",
26-
"is_skipped": true,
27-
"skipped_at": "2025-03-24T15:48:41.042284Z"
24+
"skipped_at": "0001-01-01T00:00:00Z"
2825
},
2926
"github.com/smartcontractkit/chainlink/integration-tests/smoke/ccip::TestRMN_NotEnoughObservers": {
3027
"test_package": "github.com/smartcontractkit/chainlink/integration-tests/smoke/ccip",
3128
"test_name": "TestRMN_NotEnoughObservers",
3229
"jira_ticket": "DX-295",
33-
"skipped_at": "0001-01-01T00:00:00Z"
30+
"skipped_at": "2025-03-24T16:05:20.79639Z"
3431
},
3532
"github.com/smartcontractkit/chainlink/integration-tests/smoke/ccip::TestRMN_NotEnoughSigners": {
3633
"test_package": "github.com/smartcontractkit/chainlink/integration-tests/smoke/ccip",
@@ -54,15 +51,13 @@
5451
"test_package": "github.com/smartcontractkit/chainlink/integration-tests/smoke/ccip",
5552
"test_name": "TestRMN_TwoMessagesOneSourceChainCursed",
5653
"jira_ticket": "DX-297",
57-
"is_skipped": true,
58-
"skipped_at": "2025-03-24T15:45:52.058582Z"
54+
"skipped_at": "0001-01-01T00:00:00Z"
5955
},
6056
"github.com/smartcontractkit/chainlink/integration-tests/smoke/ccip::TestV1_5_Message_RMNRemote_Curse_Uncurse": {
6157
"test_package": "github.com/smartcontractkit/chainlink/integration-tests/smoke/ccip",
6258
"test_name": "TestV1_5_Message_RMNRemote_Curse_Uncurse",
6359
"jira_ticket": "DX-293",
64-
"is_skipped": true,
65-
"skipped_at": "2025-03-24T15:45:59.557336Z"
60+
"skipped_at": "2025-03-24T16:06:00.975793Z"
6661
},
6762
"github.com/smartcontractkit/chainlink/v2::TestScripts/health/default": {
6863
"test_package": "github.com/smartcontractkit/chainlink/v2",

tools/flakeguard/cmd/tickets.go

Lines changed: 62 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ var TicketsCmd = &cobra.Command{
3030
3131
Actions:
3232
[s] mark as skipped (and optionally post a comment to the Jira ticket)
33+
[u] unskip a ticket
3334
[p] previous ticket
3435
[n] next ticket
3536
[q] quit
@@ -50,14 +51,13 @@ You can later extend this command to support additional actions.`,
5051
return nil
5152
}
5253

53-
// Convert entries to model.FlakyTicket
54+
// Convert entries to model.FlakyTicket (using SkippedAt only).
5455
tickets := make([]model.FlakyTicket, len(entries))
5556
for i, entry := range entries {
5657
tickets[i] = model.FlakyTicket{
5758
TestPackage: entry.TestPackage,
5859
TestName: entry.TestName,
5960
ExistingJiraKey: entry.JiraTicket,
60-
IsSkipped: entry.IsSkipped,
6161
SkippedAt: entry.SkippedAt,
6262
}
6363
}
@@ -74,7 +74,7 @@ You can later extend this command to support additional actions.`,
7474
m.JiraClient = jiraClient
7575
m.LocalDB = db
7676
m.JiraComment = jiraComment
77-
m.DryRun = dryRun
77+
m.DryRun = ticketsDryRun
7878

7979
// 5) Run the TUI.
8080
finalModel, err := tea.NewProgram(m).Run()
@@ -111,6 +111,7 @@ type ticketModel struct {
111111
JiraComment bool
112112
DryRun bool
113113
quitting bool
114+
infoMessage string // new field for showing info to the user
114115
}
115116

116117
// initialTicketsModel creates an initial model.
@@ -143,45 +144,67 @@ func (m ticketModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
143144
if m.index > 0 {
144145
m.index--
145146
}
147+
// Clear info message on navigation.
148+
m.infoMessage = ""
146149
return m, nil
147150
case "n":
148151
if m.index < len(m.tickets)-1 {
149152
m.index++
150153
}
154+
// Clear info message on navigation.
155+
m.infoMessage = ""
151156
return m, nil
152157
}
153158

154159
// Action: mark as skipped.
155160
if msg.String() == "s" {
156161
t := m.tickets[m.index]
157-
// Only mark if not already skipped.
158-
if !t.IsSkipped {
159-
t.IsSkipped = true
162+
// Only mark as skipped if not already skipped.
163+
if t.SkippedAt.IsZero() {
164+
t.SkippedAt = time.Now()
160165
// Optionally, post a comment to the Jira ticket if not in dry-run.
161166
if !m.DryRun && m.JiraClient != nil && t.ExistingJiraKey != "" && m.JiraComment {
162167
comment := fmt.Sprintf("Test marked as skipped on %s.", time.Now().Format(time.RFC822))
163168
err := jirautils.PostCommentToTicket(m.JiraClient, t.ExistingJiraKey, comment)
164169
if err != nil {
165170
log.Error().Err(err).Msgf("Failed to post comment to Jira ticket %s", t.ExistingJiraKey)
171+
m.infoMessage = fmt.Sprintf("Failed to post comment to Jira ticket %s", t.ExistingJiraKey)
172+
} else {
173+
// Use the Jira link to display the comment location.
174+
m.infoMessage = fmt.Sprintf("Skip comment posted to Jira ticket: %s", jirautils.GetJiraLink(t.ExistingJiraKey))
166175
}
167176
}
168177
// Update local DB state with the current time.
169178
m.tickets[m.index] = t
170-
m.LocalDB.UpdateTicketStatus(t.TestPackage, t.TestName, t.IsSkipped, time.Now())
179+
m.LocalDB.UpdateTicketStatus(t.TestPackage, t.TestName, t.SkippedAt)
171180
}
172181
return m, nil
173182
}
174-
}
175-
return m, nil
176-
}
177183

178-
// getJiraLink returns the full Jira URL for a given ticket key if JIRA_DOMAIN is set.
179-
func getJiraLink(ticketKey string) string {
180-
domain := os.Getenv("JIRA_DOMAIN")
181-
if domain != "" {
182-
return fmt.Sprintf("https://%s/browse/%s", domain, ticketKey)
184+
// Action: unskip a ticket.
185+
if msg.String() == "u" {
186+
t := m.tickets[m.index]
187+
// Only unskip if the ticket is currently marked as skipped.
188+
if !t.SkippedAt.IsZero() {
189+
t.SkippedAt = time.Time{} // reset to zero value
190+
// Optionally, post a comment to the Jira ticket if not in dry-run.
191+
if !m.DryRun && m.JiraClient != nil && t.ExistingJiraKey != "" && m.JiraComment {
192+
comment := fmt.Sprintf("Test unskipped on %s.", time.Now().Format(time.RFC822))
193+
err := jirautils.PostCommentToTicket(m.JiraClient, t.ExistingJiraKey, comment)
194+
if err != nil {
195+
log.Error().Err(err).Msgf("Failed to post unskip comment to Jira ticket %s", t.ExistingJiraKey)
196+
m.infoMessage = fmt.Sprintf("Failed to post unskip comment to Jira ticket %s", t.ExistingJiraKey)
197+
} else {
198+
m.infoMessage = fmt.Sprintf("Unskip comment posted to Jira ticket: %s", jirautils.GetJiraLink(t.ExistingJiraKey))
199+
}
200+
}
201+
m.tickets[m.index] = t
202+
m.LocalDB.UpdateTicketStatus(t.TestPackage, t.TestName, t.SkippedAt)
203+
}
204+
return m, nil
205+
}
183206
}
184-
return ticketKey
207+
return m, nil
185208
}
186209

187210
// View renders the current ticket and available actions.
@@ -194,23 +217,37 @@ func (m ticketModel) View() string {
194217
// Define styles.
195218
headerStyle := lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("205"))
196219
infoStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("10"))
197-
faintStyle := lipgloss.NewStyle().Faint(true)
220+
labelStyle := lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("69"))
221+
dryRunStyle := lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("208"))
222+
actionStyle := lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("205"))
223+
224+
var view string
225+
226+
// Show a dry-run indicator at the top.
227+
if m.DryRun {
228+
view += dryRunStyle.Render("DRY RUN MODE") + "\n\n"
229+
}
198230

199231
// Build header and ticket details.
200-
view := headerStyle.Render(fmt.Sprintf("Ticket [%d/%d]", m.index+1, len(m.tickets))) + "\n"
201-
view += fmt.Sprintf("Test: %s\n", t.TestName)
202-
view += fmt.Sprintf("Package: %s\n", t.TestPackage)
232+
view += headerStyle.Render(fmt.Sprintf("Ticket [%d/%d]\n", m.index+1, len(m.tickets))) + "\n"
233+
view += fmt.Sprintf("%s %s\n", labelStyle.Render("Test:"), t.TestName)
234+
view += fmt.Sprintf("%s %s\n", labelStyle.Render("Package:"), t.TestPackage)
203235
if t.ExistingJiraKey != "" {
204-
view += fmt.Sprintf("Jira: %s\n", getJiraLink(t.ExistingJiraKey))
236+
view += fmt.Sprintf("%s %s\n", labelStyle.Render("Jira:"), jirautils.GetJiraLink(t.ExistingJiraKey))
205237
}
206238

207239
// Show status with color.
208-
if t.IsSkipped {
209-
view += fmt.Sprintf("Status: %s\n", fmt.Sprintf("Skipped At: %s\n", faintStyle.Render(t.SkippedAt.UTC().Format(time.RFC822))))
240+
if !t.SkippedAt.IsZero() {
241+
view += fmt.Sprintf("%s %s\n", labelStyle.Render("Status:"), fmt.Sprintf("skipped at: %s", t.SkippedAt.UTC().Format(time.RFC822)))
210242
} else {
211-
view += fmt.Sprintf("Status: %s\n", infoStyle.Render("Not Skipped"))
243+
view += fmt.Sprintf("%s %s\n", labelStyle.Render("Status:"), infoStyle.Render("not skipped"))
244+
}
245+
246+
// Display any info message.
247+
if m.infoMessage != "" {
248+
view += "\n" + infoStyle.Render(m.infoMessage) + "\n"
212249
}
213250

214-
view += "\nActions: [s] mark as skipped, [p] previous, [n] next, [q] quit"
251+
view += "\n" + actionStyle.Render("Actions:") + " [s] mark as skipped, [u] unskip, [p] previous, [n] next, [q] quit"
215252
return view
216253
}

tools/flakeguard/jirautils/jira.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,3 +73,12 @@ func PostCommentToTicket(client *jira.Client, ticketKey, comment string) error {
7373
}
7474
return nil
7575
}
76+
77+
// getJiraLink returns the full Jira URL for a given ticket key if JIRA_DOMAIN is set.
78+
func GetJiraLink(ticketKey string) string {
79+
domain := os.Getenv("JIRA_DOMAIN")
80+
if domain != "" {
81+
return fmt.Sprintf("https://%s/browse/%s", domain, ticketKey)
82+
}
83+
return ticketKey
84+
}

tools/flakeguard/localdb/localdb.go

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,8 @@ func (db *DB) Set(testPackage, testName, jiraTicket string) {
120120

121121
// UpdateTicketStatus updates or inserts the ticket status for (testPackage, testName).
122122
// It accepts a boolean for whether the ticket is skipped and a timestamp in UTC.
123-
func (db *DB) UpdateTicketStatus(testPackage, testName string, isSkipped bool, skippedAt time.Time) {
123+
// UpdateTicketStatus updates the ticket's skipped status using the SkippedAt timestamp.
124+
func (db *DB) UpdateTicketStatus(testPackage, testName string, skippedAt time.Time) {
124125
key := makeKey(testPackage, testName)
125126
entry, exists := db.data[key]
126127
if !exists {
@@ -129,13 +130,7 @@ func (db *DB) UpdateTicketStatus(testPackage, testName string, isSkipped bool, s
129130
TestName: testName,
130131
}
131132
}
132-
entry.IsSkipped = isSkipped
133-
if isSkipped {
134-
entry.SkippedAt = skippedAt.UTC() // Ensure the timestamp is saved as UTC.
135-
} else {
136-
// If not skipped, clear the timestamp.
137-
entry.SkippedAt = time.Time{}
138-
}
133+
entry.SkippedAt = skippedAt.UTC()
139134
db.data[key] = entry
140135
}
141136

tools/flakeguard/model/ticket.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,5 @@ type FlakyTicket struct {
1515
ExistingJiraKey string
1616
ExistingTicketSource string // "localdb" or "jira"
1717
Assignee string
18-
IsSkipped bool
1918
SkippedAt time.Time // timestamp when the ticket was marked as skipped
2019
}

0 commit comments

Comments
 (0)