Skip to content

Commit b0b3230

Browse files
committed
Add "tickets" cmd to review tickets in local db and mark them as skipped
1 parent 3ef19c1 commit b0b3230

File tree

7 files changed

+337
-51
lines changed

7 files changed

+337
-51
lines changed

tools/flakeguard/.flaky_test_db.json

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,56 +2,72 @@
22
"github.com/smartcontractkit/chainlink/deployment/environment/crib::TestShouldProvideEnvironmentConfig": {
33
"test_package": "github.com/smartcontractkit/chainlink/deployment/environment/crib",
44
"test_name": "TestShouldProvideEnvironmentConfig",
5-
"jira_ticket": "DX-291"
5+
"jira_ticket": "DX-291",
6+
"is_skipped": true,
7+
"skipped_at": "2025-03-24T15:39:48.839992Z"
68
},
79
"github.com/smartcontractkit/chainlink/integration-tests/smoke/ccip::TestRMN_DifferentRmnNodesForDifferentChains": {
810
"test_package": "github.com/smartcontractkit/chainlink/integration-tests/smoke/ccip",
911
"test_name": "TestRMN_DifferentRmnNodesForDifferentChains",
10-
"jira_ticket": "DX-202"
12+
"jira_ticket": "DX-202",
13+
"is_skipped": true,
14+
"skipped_at": "2025-03-24T15:44:09.201139Z"
1115
},
1216
"github.com/smartcontractkit/chainlink/integration-tests/smoke/ccip::TestRMN_GlobalCurseTwoMessagesOnTwoLanes": {
1317
"test_package": "github.com/smartcontractkit/chainlink/integration-tests/smoke/ccip",
1418
"test_name": "TestRMN_GlobalCurseTwoMessagesOnTwoLanes",
15-
"jira_ticket": "DX-294"
19+
"jira_ticket": "DX-294",
20+
"skipped_at": "0001-01-01T00:00:00Z"
1621
},
1722
"github.com/smartcontractkit/chainlink/integration-tests/smoke/ccip::TestRMN_MultipleMessagesOnOneLaneNoWaitForExec": {
1823
"test_package": "github.com/smartcontractkit/chainlink/integration-tests/smoke/ccip",
1924
"test_name": "TestRMN_MultipleMessagesOnOneLaneNoWaitForExec",
20-
"jira_ticket": "DX-201"
25+
"jira_ticket": "DX-201",
26+
"is_skipped": true,
27+
"skipped_at": "2025-03-24T15:48:41.042284Z"
2128
},
2229
"github.com/smartcontractkit/chainlink/integration-tests/smoke/ccip::TestRMN_NotEnoughObservers": {
2330
"test_package": "github.com/smartcontractkit/chainlink/integration-tests/smoke/ccip",
2431
"test_name": "TestRMN_NotEnoughObservers",
25-
"jira_ticket": "DX-295"
32+
"jira_ticket": "DX-295",
33+
"skipped_at": "0001-01-01T00:00:00Z"
2634
},
2735
"github.com/smartcontractkit/chainlink/integration-tests/smoke/ccip::TestRMN_NotEnoughSigners": {
2836
"test_package": "github.com/smartcontractkit/chainlink/integration-tests/smoke/ccip",
2937
"test_name": "TestRMN_NotEnoughSigners",
30-
"jira_ticket": "DX-296"
38+
"jira_ticket": "DX-296",
39+
"skipped_at": "0001-01-01T00:00:00Z"
3140
},
3241
"github.com/smartcontractkit/chainlink/integration-tests/smoke/ccip::TestRMN_TwoMessagesOnTwoLanesIncludingBatching": {
3342
"test_package": "github.com/smartcontractkit/chainlink/integration-tests/smoke/ccip",
3443
"test_name": "TestRMN_TwoMessagesOnTwoLanesIncludingBatching",
35-
"jira_ticket": "DX-199"
44+
"jira_ticket": "DX-199",
45+
"skipped_at": "0001-01-01T00:00:00Z"
3646
},
3747
"github.com/smartcontractkit/chainlink/integration-tests/smoke/ccip::TestRMN_TwoMessagesOnTwoLanesIncludingBatchingWithTemporaryPause": {
3848
"test_package": "github.com/smartcontractkit/chainlink/integration-tests/smoke/ccip",
3949
"test_name": "TestRMN_TwoMessagesOnTwoLanesIncludingBatchingWithTemporaryPause",
40-
"jira_ticket": "DX-123"
50+
"jira_ticket": "DX-123",
51+
"skipped_at": "0001-01-01T00:00:00Z"
4152
},
4253
"github.com/smartcontractkit/chainlink/integration-tests/smoke/ccip::TestRMN_TwoMessagesOneSourceChainCursed": {
4354
"test_package": "github.com/smartcontractkit/chainlink/integration-tests/smoke/ccip",
4455
"test_name": "TestRMN_TwoMessagesOneSourceChainCursed",
45-
"jira_ticket": "DX-297"
56+
"jira_ticket": "DX-297",
57+
"is_skipped": true,
58+
"skipped_at": "2025-03-24T15:45:52.058582Z"
4659
},
4760
"github.com/smartcontractkit/chainlink/integration-tests/smoke/ccip::TestV1_5_Message_RMNRemote_Curse_Uncurse": {
4861
"test_package": "github.com/smartcontractkit/chainlink/integration-tests/smoke/ccip",
4962
"test_name": "TestV1_5_Message_RMNRemote_Curse_Uncurse",
50-
"jira_ticket": "DX-293"
63+
"jira_ticket": "DX-293",
64+
"is_skipped": true,
65+
"skipped_at": "2025-03-24T15:45:59.557336Z"
5166
},
5267
"github.com/smartcontractkit/chainlink/v2::TestScripts/health/default": {
5368
"test_package": "github.com/smartcontractkit/chainlink/v2",
5469
"test_name": "TestScripts/health/default",
55-
"jira_ticket": "DX-109"
70+
"jira_ticket": "DX-109",
71+
"skipped_at": "0001-01-01T00:00:00Z"
5672
}
5773
}

tools/flakeguard/cmd/create_jira_tickets.go

Lines changed: 24 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"github.com/rs/zerolog/log"
1919
"github.com/smartcontractkit/chainlink-testing-framework/tools/flakeguard/jirautils"
2020
"github.com/smartcontractkit/chainlink-testing-framework/tools/flakeguard/localdb"
21+
"github.com/smartcontractkit/chainlink-testing-framework/tools/flakeguard/model"
2122
"github.com/spf13/cobra"
2223
)
2324

@@ -27,7 +28,7 @@ var (
2728
jiraProject string
2829
jiraIssueType string
2930
jiraSearchLabel string // defaults to "flaky_test" if empty
30-
flakyTestJSONDBPath string
31+
testDBPath string
3132
assigneeMappingPath string
3233
skipExisting bool
3334
)
@@ -74,7 +75,7 @@ ticket in a text-based UI. Press 'y' to confirm creation, 'n' to skip,
7475
}
7576

7677
// 2) Load local DB (test -> known Jira ticket)
77-
db, err := localdb.LoadDBWithPath(flakyTestJSONDBPath)
78+
db, err := localdb.LoadDBWithPath(testDBPath)
7879
if err != nil {
7980
log.Warn().Err(err).Msg("Failed to load local DB; continuing with empty DB.")
8081
db = localdb.NewDB()
@@ -99,7 +100,7 @@ ticket in a text-based UI. Press 'y' to confirm creation, 'n' to skip,
99100
dataRows := records[1:] // skip the header row
100101

101102
// 4) Convert CSV rows -> FlakyTicket objects
102-
var tickets []FlakyTicket
103+
var tickets []model.FlakyTicket
103104
for i, row := range dataRows {
104105
if len(row) < 10 {
105106
log.Warn().Msgf("Skipping row %d (not enough columns)", i+1)
@@ -198,7 +199,7 @@ ticket in a text-based UI. Press 'y' to confirm creation, 'n' to skip,
198199
log.Error().Err(err).Msg("Error running Bubble Tea program")
199200
os.Exit(1)
200201
}
201-
fm := finalModel.(model)
202+
fm := finalModel.(tmodel)
202203

203204
// 9) Save local DB with any new knowledge
204205
if err := fm.LocalDB.Save(); err != nil {
@@ -217,7 +218,7 @@ func init() {
217218
CreateTicketsCmd.Flags().StringVar(&jiraProject, "jira-project", "", "Jira project key (or env JIRA_PROJECT_KEY)")
218219
CreateTicketsCmd.Flags().StringVar(&jiraIssueType, "jira-issue-type", "Task", "Type of Jira issue (Task, Bug, etc.)")
219220
CreateTicketsCmd.Flags().StringVar(&jiraSearchLabel, "jira-search-label", "", "Jira label to filter existing tickets (default: flaky_test)")
220-
CreateTicketsCmd.Flags().StringVar(&flakyTestJSONDBPath, "flaky-test-json-db-path", "", "Path to the flaky test JSON database (default: ~/.flaky_tes_db.json)")
221+
CreateTicketsCmd.Flags().StringVar(&testDBPath, "test-db-path", "", "Path to the flaky test JSON database (default: ~/.flaky_tes_db.json)")
221222
CreateTicketsCmd.Flags().StringVar(&assigneeMappingPath, "assignee-mapping", "", "Path to JSON file with assignee mapping (supports regex)")
222223
CreateTicketsCmd.Flags().BoolVar(&skipExisting, "skip-existing", false, "Skip processing tickets that already have a Jira ticket ID")
223224
}
@@ -226,22 +227,8 @@ func init() {
226227
// FlakyTicket Data Model
227228
// -------------------------------------------------------------------------------------
228229

229-
type FlakyTicket struct {
230-
RowIndex int
231-
Confirmed bool
232-
Valid bool
233-
InvalidReason string
234-
TestName string
235-
TestPackage string
236-
Summary string
237-
Description string
238-
ExistingJiraKey string
239-
ExistingTicketSource string // "localdb" or "jira" (if found)
240-
Assignee string
241-
}
242-
243230
// rowToFlakyTicket: build a ticket from one CSV row (index assumptions: pkg=0, testName=2, flakeRate=7, logs=9).
244-
func rowToFlakyTicket(row []string) FlakyTicket {
231+
func rowToFlakyTicket(row []string) model.FlakyTicket {
245232
pkg := strings.TrimSpace(row[0])
246233
testName := strings.TrimSpace(row[2])
247234
flakeRate := strings.TrimSpace(row[7])
@@ -294,7 +281,7 @@ h3. Action Items:
294281
logSection,
295282
)
296283

297-
t := FlakyTicket{
284+
t := model.FlakyTicket{
298285
TestPackage: pkg,
299286
TestName: testName,
300287
Summary: summary,
@@ -328,7 +315,7 @@ h3. Action Items:
328315
// Jira Search
329316
// -------------------------------------------------------------------------------------
330317

331-
func findExistingTicket(client *jira.Client, label string, ticket FlakyTicket) (string, error) {
318+
func findExistingTicket(client *jira.Client, label string, ticket model.FlakyTicket) (string, error) {
332319
jql := fmt.Sprintf(`labels = "%s" AND summary ~ "%s" order by created DESC`, label, ticket.TestName)
333320
issues, resp, err := client.Issue.SearchWithContext(context.Background(), jql, &jira.SearchOptions{MaxResults: 1})
334321
if err != nil {
@@ -344,8 +331,8 @@ func findExistingTicket(client *jira.Client, label string, ticket FlakyTicket) (
344331
// Bubble Tea Model
345332
// -------------------------------------------------------------------------------------
346333

347-
type model struct {
348-
tickets []FlakyTicket
334+
type tmodel struct {
335+
tickets []model.FlakyTicket
349336
index int
350337
confirmed int
351338
skipped int
@@ -362,19 +349,19 @@ type model struct {
362349
inputValue string // user-typed input for existing ticket
363350
}
364351

365-
func initialModel(tickets []FlakyTicket) model {
366-
return model{
352+
func initialModel(tickets []model.FlakyTicket) tmodel {
353+
return tmodel{
367354
tickets: tickets,
368355
index: 0,
369356
mode: "normal",
370357
}
371358
}
372359

373-
func (m model) Init() tea.Cmd {
360+
func (m tmodel) Init() tea.Cmd {
374361
return nil
375362
}
376363

377-
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
364+
func (m tmodel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
378365
switch msg := msg.(type) {
379366
case tea.KeyMsg:
380367
if m.mode == "promptExisting" {
@@ -389,7 +376,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
389376
}
390377
}
391378

392-
func updateNormalMode(m model, msg tea.KeyMsg) (tea.Model, tea.Cmd) {
379+
func updateNormalMode(m tmodel, msg tea.KeyMsg) (tea.Model, tea.Cmd) {
393380
if m.quitting || m.index >= len(m.tickets) {
394381
return updateQuit(m)
395382
}
@@ -434,7 +421,7 @@ func updateNormalMode(m model, msg tea.KeyMsg) (tea.Model, tea.Cmd) {
434421
return updateSkip(m)
435422
}
436423

437-
func updatePromptExisting(m model, msg tea.KeyMsg) (tea.Model, tea.Cmd) {
424+
func updatePromptExisting(m tmodel, msg tea.KeyMsg) (tea.Model, tea.Cmd) {
438425
switch msg.Type {
439426
case tea.KeyRunes:
440427
m.inputValue += string(msg.Runes)
@@ -458,7 +445,7 @@ func updatePromptExisting(m model, msg tea.KeyMsg) (tea.Model, tea.Cmd) {
458445
return m, nil
459446
}
460447

461-
func updateConfirm(m model) (tea.Model, tea.Cmd) {
448+
func updateConfirm(m tmodel) (tea.Model, tea.Cmd) {
462449
i := m.index
463450
t := m.tickets[i]
464451

@@ -485,7 +472,7 @@ func updateConfirm(m model) (tea.Model, tea.Cmd) {
485472
return m, nil
486473
}
487474

488-
func updateTicketCreated(m model, msg tea.KeyMsg) (tea.Model, tea.Cmd) {
475+
func updateTicketCreated(m tmodel, msg tea.KeyMsg) (tea.Model, tea.Cmd) {
489476
switch msg.String() {
490477
case "n":
491478
m.mode = "normal"
@@ -504,7 +491,7 @@ func updateTicketCreated(m model, msg tea.KeyMsg) (tea.Model, tea.Cmd) {
504491
return m, nil
505492
}
506493

507-
func updateSkip(m model) (tea.Model, tea.Cmd) {
494+
func updateSkip(m tmodel) (tea.Model, tea.Cmd) {
508495
m.skipped++
509496
m.index++
510497
if m.index >= len(m.tickets) {
@@ -513,13 +500,13 @@ func updateSkip(m model) (tea.Model, tea.Cmd) {
513500
return m, nil
514501
}
515502

516-
func updateQuit(m model) (tea.Model, tea.Cmd) {
503+
func updateQuit(m tmodel) (tea.Model, tea.Cmd) {
517504
m.quitting = true
518505
return m, tea.Quit
519506
}
520507

521508
// View logic
522-
func (m model) View() string {
509+
func (m tmodel) View() string {
523510
if m.quitting || m.index >= len(m.tickets) {
524511
return finalView(m)
525512
}
@@ -635,7 +622,7 @@ func (m model) View() string {
635622
)
636623
}
637624

638-
func finalView(m model) string {
625+
func finalView(m tmodel) string {
639626
doneStyle := lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("6"))
640627
return doneStyle.Render(fmt.Sprintf(
641628
"Done! Confirmed %d tickets, skipped %d. Exiting...\n",
@@ -657,7 +644,7 @@ func readFlakyTestsCSV(path string) ([][]string, error) {
657644
return r.ReadAll()
658645
}
659646

660-
func writeRemainingTicketsCSV(newPath string, m model) error {
647+
func writeRemainingTicketsCSV(newPath string, m tmodel) error {
661648
confirmedRows := make(map[int]bool)
662649
for _, t := range m.tickets {
663650
if t.Confirmed || t.ExistingJiraKey != "" {

0 commit comments

Comments
 (0)