333 lines
7.5 KiB
Go
333 lines
7.5 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
jira "github.com/andygrunwald/go-jira/v2/cloud"
|
|
"github.com/charmbracelet/huh"
|
|
"github.com/fatih/color"
|
|
"github.com/spf13/viper"
|
|
"os"
|
|
"strconv"
|
|
)
|
|
|
|
var red = color.New(color.FgRed).SprintFunc()
|
|
var yellow = color.New(color.FgYellow).SprintFunc()
|
|
var blue = color.New(color.FgBlue).SprintFunc()
|
|
var green = color.New(color.FgGreen).SprintFunc()
|
|
|
|
func printError(msg string, err error) {
|
|
if err == nil {
|
|
fmt.Printf("Error: %s\n", msg)
|
|
} else {
|
|
fmt.Printf("Error: %s: %v\n", msg, err)
|
|
}
|
|
}
|
|
|
|
func ActionExit(_ []string) {
|
|
promptRunner.Close()
|
|
os.Exit(0)
|
|
}
|
|
|
|
func ActionLogout(_ []string) {
|
|
viper.Set("token", nil)
|
|
err := viper.WriteConfig()
|
|
if err != nil {
|
|
printError("Failed to write config", err)
|
|
}
|
|
ensureLoggedIn()
|
|
}
|
|
|
|
func ActionListProjects(_ []string) {
|
|
projects, err := GetAllProjects()
|
|
if err != nil {
|
|
printError("Failed to list projects", err)
|
|
return
|
|
}
|
|
for _, project := range *projects {
|
|
fmt.Printf(" - %s: %s\n", project.Key, project.Name)
|
|
}
|
|
}
|
|
|
|
func ActionUseProject(args []string) {
|
|
var projectId string
|
|
if len(args) == 0 {
|
|
println("Fetching projects...")
|
|
projects, err := GetAllProjects()
|
|
if err != nil {
|
|
printError("Failed to list projects", err)
|
|
return
|
|
}
|
|
|
|
options := []huh.Option[string]{}
|
|
for _, p := range *projects {
|
|
name := fmt.Sprintf("%s - %s", red(p.Key), p.Name)
|
|
options = append(options, huh.NewOption(name, p.ID))
|
|
}
|
|
|
|
err = huh.NewSelect[string]().
|
|
Title("Choose a project").
|
|
Options(options...).
|
|
Value(&projectId).
|
|
Run()
|
|
if err != nil {
|
|
printError("Failed to choose project", err)
|
|
return
|
|
}
|
|
} else if len(args) == 1 {
|
|
projectId = args[0]
|
|
} else {
|
|
printError("Need a project ID", nil)
|
|
return
|
|
}
|
|
project, _, err := jiraClient.Project.Get(context.Background(), projectId)
|
|
if err != nil {
|
|
printError("Failed to get project", err)
|
|
return
|
|
}
|
|
fmt.Printf("Using project %s (%s)\n", project.Name, project.Key)
|
|
SetProject(project)
|
|
SaveConfig()
|
|
UpdatePrompt()
|
|
}
|
|
|
|
func ActionListBoards(_ []string) {
|
|
if !HasProject() {
|
|
printError("Please select a project first", nil)
|
|
return
|
|
}
|
|
list, err := GetAllBoardsForProject(GetProjectId())
|
|
if err != nil {
|
|
printError("Failed to list boards", err)
|
|
return
|
|
}
|
|
for _, board := range list.Values {
|
|
fmt.Printf(" - %s (%d)\n", board.Name, board.ID)
|
|
}
|
|
}
|
|
|
|
func ActionUseBoard(args []string) {
|
|
if !HasIssue() {
|
|
printError("Please select a project first", nil)
|
|
return
|
|
}
|
|
var boardId int64
|
|
var err error
|
|
if len(args) == 0 {
|
|
println("Fetching boards...")
|
|
boards, err := GetAllBoardsForProject(GetProjectId())
|
|
if err != nil {
|
|
printError("Failed to list boards", err)
|
|
return
|
|
}
|
|
|
|
options := []huh.Option[int64]{}
|
|
for _, board := range boards.Values {
|
|
name := fmt.Sprintf("%s (%s)", board.Name, board.Type)
|
|
options = append(options, huh.NewOption(name, int64(board.ID)))
|
|
}
|
|
|
|
err = huh.NewSelect[int64]().
|
|
Title("Choose a board").
|
|
Options(options...).
|
|
Value(&boardId).
|
|
Run()
|
|
if err != nil {
|
|
printError("Failed to choose a board", err)
|
|
return
|
|
}
|
|
} else if len(args) == 1 {
|
|
boardId, err = strconv.ParseInt(args[0], 10, 64)
|
|
if err != nil {
|
|
printError("Invalid board ID", nil)
|
|
return
|
|
}
|
|
} else {
|
|
printError("Invalid number of arguments", nil)
|
|
}
|
|
board, err := GetBoardConfiguration(int(boardId))
|
|
if err != nil {
|
|
printError("Failed to get project", err)
|
|
return
|
|
}
|
|
fmt.Printf("Using board %s (%d)\n", board.Name, board.ID)
|
|
SetBoard(board.ID, board.Name)
|
|
SaveConfig()
|
|
UpdatePrompt()
|
|
}
|
|
|
|
func ActionUseCurrentSprint(_ []string) {
|
|
boardId := GetBoardId()
|
|
sprint, err := GetCurrentSprint(boardId)
|
|
if err != nil {
|
|
printError("Failed to get current sprint", err)
|
|
return
|
|
}
|
|
fmt.Printf("Using sprint %s (%d)\n", sprint.Name, sprint.ID)
|
|
SetSprint(sprint)
|
|
SaveConfig()
|
|
UpdatePrompt()
|
|
}
|
|
|
|
func ActionUseIssue(args []string) {
|
|
actionUseIssueWithFilter(args, func(_ *jira.Issue) bool {
|
|
return true
|
|
})
|
|
}
|
|
|
|
func ActionUseMyIssue(args []string) {
|
|
actionUseIssueWithFilter(args, func(issue *jira.Issue) bool {
|
|
assignee := issue.Fields.Assignee
|
|
if assignee == nil {
|
|
return false
|
|
}
|
|
return assignee.AccountID == jiraUser.AccountID
|
|
})
|
|
}
|
|
|
|
func actionUseIssueWithFilter(args []string, allowIssue func(issue *jira.Issue) bool) {
|
|
if !HasSprint() {
|
|
printError("No sprint selected", nil)
|
|
return
|
|
}
|
|
sprintId := GetSprintId()
|
|
|
|
var issueKey string
|
|
var err error
|
|
if len(args) == 0 {
|
|
issues, err := GetIssuesForSprint(sprintId)
|
|
if err != nil {
|
|
printError("Failed to fetch issues", err)
|
|
return
|
|
}
|
|
|
|
options := []huh.Option[string]{}
|
|
for _, issue := range issues {
|
|
if allowIssue(&issue) {
|
|
key := issue.Key
|
|
summary := issue.Fields.Summary
|
|
status := issue.Fields.Status.Name
|
|
assignee := "Unassigned"
|
|
if issue.Fields.Assignee != nil {
|
|
if issue.Fields.Assignee.AccountID == jiraUser.AccountID {
|
|
assignee = green(issue.Fields.Assignee.DisplayName)
|
|
} else {
|
|
assignee = yellow(issue.Fields.Assignee.DisplayName)
|
|
}
|
|
}
|
|
name := fmt.Sprintf("%s - %s (%s, %s)", red(key), summary, blue(status), assignee)
|
|
options = append(options, huh.NewOption(name, issue.Key))
|
|
}
|
|
}
|
|
|
|
err = huh.NewSelect[string]().
|
|
Title("Choose an issue").
|
|
Options(options...).
|
|
Value(&issueKey).
|
|
Run()
|
|
if err != nil {
|
|
printError("Failed to choose an issue", err)
|
|
return
|
|
}
|
|
} else if len(args) == 1 {
|
|
issueKey = args[0]
|
|
} else {
|
|
printError("Invalid number of arguments", nil)
|
|
}
|
|
issue, err := GetIssue(issueKey)
|
|
if err != nil {
|
|
printError("Failed to get issue", err)
|
|
return
|
|
}
|
|
fmt.Printf("Using issue %s - %s\n", issue.Key, issue.Fields.Summary)
|
|
SetIssue(issue.Key)
|
|
SaveConfig()
|
|
UpdatePrompt()
|
|
}
|
|
|
|
func ActionListIssues(_ []string) {
|
|
sprintId := GetSprintId()
|
|
if sprintId == 0 {
|
|
printError("No sprint selected", nil)
|
|
return
|
|
}
|
|
issues, err := GetIssuesForSprint(sprintId)
|
|
if err != nil {
|
|
printError("Failed to list issues", err)
|
|
}
|
|
description := ""
|
|
for _, issue := range issues {
|
|
description += fmt.Sprintf("%s - %s (%s)\n", red(issue.Key), issue.Fields.Summary, yellow(issue.Fields.Status.Name))
|
|
}
|
|
}
|
|
|
|
func ActionBack(_ []string) {
|
|
if HasIssue() {
|
|
UnsetIssue()
|
|
} else if HasSprint() {
|
|
UnsetSprint()
|
|
} else if HasBoard() {
|
|
UnsetBoard()
|
|
} else if HasProject() {
|
|
UnsetProject()
|
|
}
|
|
SaveConfig()
|
|
UpdatePrompt()
|
|
}
|
|
|
|
func ActionViewCard(_ []string) {
|
|
if !HasIssue() {
|
|
printError("No issue selected", nil)
|
|
return
|
|
}
|
|
issue, err := GetIssue(GetIssueKey())
|
|
if err != nil {
|
|
printError("Failed to get issue", err)
|
|
return
|
|
}
|
|
fmt.Printf("Key: %s\n", issue.Key)
|
|
fmt.Printf("Summary: %s\n", issue.Fields.Summary)
|
|
fmt.Printf("Type: %s\n", issue.Fields.Type.Name)
|
|
fmt.Printf("Status: %s\n", issue.Fields.Status.Name)
|
|
if issue.Fields.Assignee != nil {
|
|
fmt.Printf("Assignee: %s\n", issue.Fields.Assignee.DisplayName)
|
|
} else {
|
|
fmt.Printf("Assignee: Unassigned\n")
|
|
}
|
|
}
|
|
|
|
func ActionViewDescription(_ []string) {
|
|
if !HasIssue() {
|
|
printError("No issue selected", nil)
|
|
return
|
|
}
|
|
issue, err := GetIssue(GetIssueKey())
|
|
if err != nil {
|
|
printError("Failed to get issue", err)
|
|
return
|
|
}
|
|
println(issue.Fields.Description)
|
|
}
|
|
|
|
func ActionSetStatus(_ []string) {
|
|
if !HasIssue() {
|
|
printError("No issue selected", nil)
|
|
return
|
|
}
|
|
|
|
issueTypes, err := GetAllStatuses(GetProjectId())
|
|
if err != nil {
|
|
printError("Failed to get sprint statuses", err)
|
|
return
|
|
}
|
|
options := []huh.Option[string]{}
|
|
for _, status := range (*issueTypes)[0].Statuses {
|
|
name := fmt.Sprintf("%s (%s)", status.Name, status.ID)
|
|
options = append(options, huh.Option[string]{Key: name, Value: status.ID})
|
|
}
|
|
huh.NewSelect[string]().
|
|
Title("Select Option").
|
|
Options(options...).
|
|
Run()
|
|
}
|