Skip to content

Commit c7a6647

Browse files
committed
refactor
1 parent 485de06 commit c7a6647

File tree

2 files changed

+126
-91
lines changed

2 files changed

+126
-91
lines changed

tools/flakeguard/cmd/create_jira_tickets.go

Lines changed: 74 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -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\nWill 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
452458
func (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("\nSummary:\n") + t.Summary
482-
descHeader := descHeaderStyle.Render("\nDescription:\n")
483-
descBody := descBodyStyle.Render(t.Description)
484-
485-
hint := helpStyle.Render("\nPress 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("\nDescription:\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("\nCannot 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("\nPress 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("\nPress [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("\nPress [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
// -------------------------------------------------------------------------------------

tools/flakeguard/jirautils/jira.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package jirautils
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"os"
7+
8+
"github.com/andygrunwald/go-jira"
9+
)
10+
11+
// GetJiraClient creates and returns a Jira client using env vars.
12+
func GetJiraClient() (*jira.Client, error) {
13+
domain := os.Getenv("JIRA_DOMAIN")
14+
if domain == "" {
15+
return nil, fmt.Errorf("JIRA_DOMAIN env var is not set")
16+
}
17+
email := os.Getenv("JIRA_EMAIL")
18+
if email == "" {
19+
return nil, fmt.Errorf("JIRA_EMAIL env var is not set")
20+
}
21+
apiKey := os.Getenv("JIRA_API_KEY")
22+
if apiKey == "" {
23+
return nil, fmt.Errorf("JIRA_API_KEY env var is not set")
24+
}
25+
26+
tp := jira.BasicAuthTransport{
27+
Username: email,
28+
Password: apiKey,
29+
}
30+
return jira.NewClient(tp.Client(), fmt.Sprintf("https://%s", domain))
31+
}
32+
33+
// CreateTicketInJira creates a new Jira ticket and returns its issue key.
34+
func CreateTicketInJira(
35+
client *jira.Client,
36+
summary, description, projectKey, issueType string,
37+
) (string, error) {
38+
issue := &jira.Issue{
39+
Fields: &jira.IssueFields{
40+
Project: jira.Project{Key: projectKey},
41+
Summary: summary,
42+
Description: description,
43+
Type: jira.IssueType{Name: issueType},
44+
Labels: []string{"flaky_test"},
45+
},
46+
}
47+
newIssue, resp, err := client.Issue.CreateWithContext(context.Background(), issue)
48+
if err != nil {
49+
return "", fmt.Errorf("error creating Jira issue: %w (resp: %v)", err, resp)
50+
}
51+
return newIssue.Key, nil
52+
}

0 commit comments

Comments
 (0)