@@ -12,6 +12,7 @@ import (
1212 tea "github.com/charmbracelet/bubbletea"
1313 "github.com/charmbracelet/lipgloss"
1414 "github.com/rs/zerolog/log"
15+ "github.com/smartcontractkit/chainlink-testing-framework/tools/flakeguard/jirautils"
1516 "github.com/smartcontractkit/chainlink-testing-framework/tools/flakeguard/localdb"
1617 "github.com/spf13/cobra"
1718)
@@ -97,7 +98,7 @@ ticket in a text-based UI. Press 'y' to confirm creation, 'n' to skip,
9798 if ft .Valid {
9899 if ticketID , found := db .Get (ft .TestPackage , ft .TestName ); found {
99100 ft .ExistingJiraKey = ticketID
100- ft .ExistingTicketSource = "localdb" // <--- mark source as localdb
101+ ft .ExistingTicketSource = "localdb"
101102 }
102103 }
103104 tickets = append (tickets , ft )
@@ -108,7 +109,7 @@ ticket in a text-based UI. Press 'y' to confirm creation, 'n' to skip,
108109 }
109110
110111 // 5) Attempt Jira client creation
111- client , clientErr := getJiraClient ()
112+ client , clientErr := jirautils . GetJiraClient ()
112113 if clientErr != nil {
113114 log .Warn ().Msgf ("No valid Jira client: %v\n Will skip searching or creating tickets in Jira." , clientErr )
114115 client = nil
@@ -118,14 +119,13 @@ ticket in a text-based UI. Press 'y' to confirm creation, 'n' to skip,
118119 if client != nil {
119120 for i := range tickets {
120121 t := & tickets [i ]
121- // if valid, no local db ticket, let's see if Jira has one
122122 if t .Valid && t .ExistingJiraKey == "" {
123123 key , err := findExistingTicket (client , jiraSearchLabel , * t )
124124 if err != nil {
125125 log .Warn ().Msgf ("Search failed for %q: %v" , t .Summary , err )
126126 } else if key != "" {
127127 t .ExistingJiraKey = key
128- t .ExistingTicketSource = "jira" // <--- mark source as jira
128+ t .ExistingTicketSource = "jira"
129129 db .Set (t .TestPackage , t .TestName , key )
130130 }
131131 }
@@ -346,28 +346,33 @@ func updateNormalMode(m model, msg tea.KeyMsg) (tea.Model, tea.Cmd) {
346346 return updateQuit (m )
347347 }
348348 t := m .tickets [m .index ]
349+
350+ switch msg .String () {
351+ case "q" , "esc" , "ctrl+c" :
352+ return updateQuit (m )
353+ }
354+
355+ // If invalid, we cannot create a new ticket, so no 'y' prompt:
349356 if ! t .Valid {
350- // invalid ticket => skip or quit
357+ // Let user skip or do other actions
351358 switch msg .String () {
352- case "q" , "esc" , "ctrl+c" :
353- return updateQuit (m )
359+ // user might press anything => skip
354360 default :
355361 return updateSkip (m )
356362 }
357363 }
358364
365+ // If valid, handle normal flow
359366 switch msg .String () {
360367 case "y" :
361368 return updateConfirm (m )
362369 case "n" :
363370 return updateSkip (m )
364371 case "e" :
365- // <--- Always prompt for a known ticket ID (even if one exists).
372+ // always prompt to enter or overwrite
366373 m .mode = "promptExisting"
367374 m .inputValue = ""
368375 return m , nil
369- case "q" , "esc" , "ctrl+c" :
370- return updateQuit (m )
371376 }
372377 return m , nil
373378}
@@ -384,7 +389,7 @@ func updatePromptExisting(m model, msg tea.KeyMsg) (tea.Model, tea.Cmd) {
384389 // store the typed string
385390 t := m .tickets [m .index ]
386391 t .ExistingJiraKey = m .inputValue
387- t .ExistingTicketSource = "localdb" // user manually provided => treat like local db
392+ t .ExistingTicketSource = "localdb" // user- provided
388393 m .tickets [m .index ] = t
389394
390395 // update local DB
@@ -393,7 +398,7 @@ func updatePromptExisting(m model, msg tea.KeyMsg) (tea.Model, tea.Cmd) {
393398 // back to normal mode
394399 m .mode = "normal"
395400 m .inputValue = ""
396- // we can skip rewriting this row since it already has a known ticket
401+ // skip from CSV if there's now a known ticket
397402 return updateSkip (m )
398403 case tea .KeyEsc :
399404 // Cancel
@@ -409,7 +414,7 @@ func updateConfirm(m model) (tea.Model, tea.Cmd) {
409414
410415 // Attempt Jira creation if not dry-run and we have a client
411416 if ! m .DryRun && m .JiraClient != nil {
412- issueKey , err := createTicketInJira (m .JiraClient , t .Summary , t .Description , m .JiraProject , m .JiraIssueType )
417+ issueKey , err := jirautils . CreateTicketInJira (m .JiraClient , t .Summary , t .Description , m .JiraProject , m .JiraIssueType )
413418 if err != nil {
414419 log .Error ().Err (err ).Msgf ("Failed to create Jira ticket: %s" , t .Summary )
415420 } else {
@@ -449,6 +454,7 @@ func updateQuit(m model) (tea.Model, tea.Cmd) {
449454 return m , tea .Quit
450455}
451456
457+ // View logic to handle your new requirements
452458func (m model ) View () string {
453459 if m .quitting || m .index >= len (m .tickets ) {
454460 return finalView (m )
@@ -467,41 +473,31 @@ func (m model) View() string {
467473 summaryStyle := lipgloss .NewStyle ().Bold (true ).Foreground (lipgloss .Color ("10" ))
468474 descHeaderStyle := lipgloss .NewStyle ().Bold (true ).Foreground (lipgloss .Color ("10" ))
469475 descBodyStyle := lipgloss .NewStyle ().Foreground (lipgloss .Color ("7" ))
470- helpStyle := lipgloss .NewStyle ().Faint (true )
476+ faintStyle := lipgloss .NewStyle ().Faint (true )
471477 errorStyle := lipgloss .NewStyle ().Bold (true ).Foreground (lipgloss .Color ("9" ))
472478 existingStyle := lipgloss .NewStyle ().Foreground (lipgloss .Color ("11" ))
473479
474480 t := m .tickets [m .index ]
475- if ! t .Valid {
476- header := headerStyle .Render (
477- fmt .Sprintf ("Ticket #%d of %d (Invalid)" , m .index + 1 , len (m .tickets )),
478- )
479- errMsg := errorStyle .Render ("Cannot create ticket: " + t .InvalidReason )
480481
481- sum := summaryStyle .Render ("\n Summary:\n " ) + t .Summary
482- descHeader := descHeaderStyle .Render ("\n Description:\n " )
483- descBody := descBodyStyle .Render (t .Description )
484-
485- hint := helpStyle .Render ("\n Press any key to skip, or [q] to quit.\n " )
486-
487- return fmt .Sprintf ("%s\n \n %s\n %s\n %s\n \n %s\n " ,
488- header ,
489- errMsg ,
490- sum ,
491- descHeader + descBody ,
492- hint ,
482+ // 1) Header line
483+ header := ""
484+ if t .Valid {
485+ header = headerStyle .Render (
486+ fmt .Sprintf ("Proposed Ticket #%d of %d" , m .index + 1 , len (m .tickets )),
487+ )
488+ } else {
489+ header = headerStyle .Render (
490+ fmt .Sprintf ("Ticket #%d of %d (Invalid)" , m .index + 1 , len (m .tickets )),
493491 )
494492 }
495493
496- header := headerStyle .Render (
497- fmt .Sprintf ("Proposed Ticket #%d of %d" , m .index + 1 , len (m .tickets )),
498- )
494+ // 2) Summary & Description
499495 sum := summaryStyle .Render ("Summary:\n " ) + t .Summary
500496 descHeader := descHeaderStyle .Render ("\n Description:\n " )
501497 descBody := descBodyStyle .Render (t .Description )
502498
503- // Build existing line AFTER the description
504- var existingLine string
499+ // 3) Existing ticket line
500+ existingLine := ""
505501 if t .ExistingJiraKey != "" {
506502 prefix := "Existing ticket found"
507503 switch t .ExistingTicketSource {
@@ -513,31 +509,60 @@ func (m model) View() string {
513509 domain := os .Getenv ("JIRA_DOMAIN" )
514510 link := t .ExistingJiraKey
515511 if domain != "" {
516- // Turn "DX-204 " into a link if we have a domain
512+ // Turn "DX-203 " into a link
517513 link = fmt .Sprintf ("https://%s/browse/%s" , domain , t .ExistingJiraKey )
518514 }
519- existingLine = existingStyle .Render (
520- fmt .Sprintf ("\n %s: %s" , prefix , link ),
515+ existingLine = existingStyle .Render (fmt .Sprintf ("\n %s: %s" , prefix , link ))
516+ }
517+
518+ // 4) If invalid + missing required fields => show that after existing line
519+ // or if there's no existing ticket, show it anyway
520+ invalidLine := ""
521+ if ! t .Valid {
522+ invalidLine = errorStyle .Render (
523+ fmt .Sprintf ("\n Cannot create ticket: %s" , t .InvalidReason ),
521524 )
522525 }
523526
524- dryRunLabel := ""
525- if m .DryRun || m .JiraClient == nil {
526- dryRunLabel = " (DRY RUN)"
527+ // 5) Help line
528+ helpLine := ""
529+ // Cases:
530+ // A) If invalid:
531+ // - If there's an existing ticket => [n] to next, [e] to update existing ticket ID, [q] to quit.
532+ // - Else => "Press any key to skip, or [q] to quit."
533+ // B) If valid & there's an existing ticket => [n] to next, [e] to update existing ticket ID, [q] to quit.
534+ // C) If valid & no existing => [y] to confirm, [n] to skip, [e] to enter existing ticket, [q] to quit (with DRY RUN text if needed).
535+ if ! t .Valid {
536+ if t .ExistingJiraKey != "" {
537+ helpLine = faintStyle .Render ("\n [n] to next, [e] to update existing ticket ID, [q] to quit." )
538+ } else {
539+ helpLine = faintStyle .Render ("\n Press any key to skip, or [q] to quit." )
540+ }
541+ } else {
542+ if t .ExistingJiraKey != "" {
543+ helpLine = faintStyle .Render ("\n [n] to next, [e] to update existing ticket ID, [q] to quit." )
544+ } else {
545+ // if no existing ticket, the normal prompt
546+ dryRunLabel := ""
547+ if m .DryRun || m .JiraClient == nil {
548+ dryRunLabel = " (DRY RUN)"
549+ }
550+ helpLine = faintStyle .Render (
551+ fmt .Sprintf ("\n Press [y] to confirm%s, [n] to skip, [e] to enter existing ticket, [q] to quit." ,
552+ dryRunLabel ),
553+ )
554+ }
527555 }
528- help := helpStyle .Render (
529- fmt .Sprintf ("\n Press [y] to confirm%s, [n] to skip, [e] to enter existing ticket, [q] to quit." , dryRunLabel ),
530- )
531556
532- // Show summary, description, then existing line at the bottom, then help text
533557 return fmt .Sprintf (
534- "%s\n \n %s\n %s%s\n %s \n %s\n " ,
558+ "%s\n \n %s\n %s%s%s%s %s\n " ,
535559 header ,
536560 sum ,
537561 descHeader ,
538562 descBody ,
539- existingLine ,
540- help ,
563+ existingLine , // e.g. "Existing ticket found in jira: https://..."
564+ invalidLine , // e.g. "Cannot create ticket: Missing required..."
565+ helpLine , // e.g. "[n] to next, [e]... or "[y] to confirm..."
541566 )
542567}
543568
@@ -549,48 +574,6 @@ func finalView(m model) string {
549574 ))
550575}
551576
552- // -------------------------------------------------------------------------------------
553- // Jira Client Helpers
554- // -------------------------------------------------------------------------------------
555-
556- func getJiraClient () (* jira.Client , error ) {
557- domain := os .Getenv ("JIRA_DOMAIN" )
558- if domain == "" {
559- return nil , fmt .Errorf ("JIRA_DOMAIN env var is not set" )
560- }
561- email := os .Getenv ("JIRA_EMAIL" )
562- if email == "" {
563- return nil , fmt .Errorf ("JIRA_EMAIL env var is not set" )
564- }
565- apiKey := os .Getenv ("JIRA_API_KEY" )
566- if apiKey == "" {
567- return nil , fmt .Errorf ("JIRA_API_KEY env var is not set" )
568- }
569-
570- tp := jira.BasicAuthTransport {
571- Username : email ,
572- Password : apiKey ,
573- }
574- return jira .NewClient (tp .Client (), fmt .Sprintf ("https://%s" , domain ))
575- }
576-
577- func createTicketInJira (client * jira.Client , summary , description , projectKey , issueType string ) (string , error ) {
578- issue := & jira.Issue {
579- Fields : & jira.IssueFields {
580- Project : jira.Project {Key : projectKey },
581- Summary : summary ,
582- Description : description ,
583- Type : jira.IssueType {Name : issueType },
584- Labels : []string {"flaky_test" },
585- },
586- }
587- newIssue , resp , err := client .Issue .CreateWithContext (context .Background (), issue )
588- if err != nil {
589- return "" , fmt .Errorf ("error creating Jira issue: %w (resp: %v)" , err , resp )
590- }
591- return newIssue .Key , nil
592- }
593-
594577// -------------------------------------------------------------------------------------
595578// CSV Reading / Writing
596579// -------------------------------------------------------------------------------------
0 commit comments