Initial commit
This commit is contained in:
commit
3899291e15
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
.idea
|
||||||
|
jirashell
|
136
actions.go
Normal file
136
actions.go
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/andygrunwald/go-jira"
|
||||||
|
"github.com/fatih/color"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
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 := jiraClient.Project.GetList()
|
||||||
|
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) {
|
||||||
|
if len(args) != 1 {
|
||||||
|
printError("Need a project ID", nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
project, _, err := jiraClient.Project.Get(args[0])
|
||||||
|
if err != nil {
|
||||||
|
printError("Failed to get project", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Printf("Using project %s (%s)\n", project.Name, project.Key)
|
||||||
|
viper.Set("project.id", project.ID)
|
||||||
|
viper.Set("project.key", project.Key)
|
||||||
|
SaveConfig()
|
||||||
|
UpdatePrompt()
|
||||||
|
}
|
||||||
|
|
||||||
|
func ActionListBoards(_ []string) {
|
||||||
|
project := GetProjectId()
|
||||||
|
if project == "" {
|
||||||
|
printError("Please select a project first", nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
list, _, err := jiraClient.Board.GetAllBoards(&jira.BoardListOptions{ProjectKeyOrID: project})
|
||||||
|
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 len(args) != 1 {
|
||||||
|
printError("Need a board ID", nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
boardId, err := strconv.ParseInt(args[0], 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
printError("Invalid board ID", nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
board, _, err := jiraClient.Board.GetBoardConfiguration(int(boardId))
|
||||||
|
if err != nil {
|
||||||
|
printError("Failed to get project", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Printf("Using board %s (%d)\n", board.Name, board.ID)
|
||||||
|
viper.Set("board.id", board.ID)
|
||||||
|
viper.Set("board.name", board.Name)
|
||||||
|
SaveConfig()
|
||||||
|
UpdatePrompt()
|
||||||
|
}
|
||||||
|
|
||||||
|
func ActionUseCurrentSprint(_ []string) {
|
||||||
|
boardId := viper.GetInt("board.id")
|
||||||
|
list, _, err := jiraClient.Board.GetAllSprintsWithOptions(boardId, &jira.GetAllSprintsOptions{
|
||||||
|
State: "active",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
printError("Failed to get current board", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(list.Values) != 1 {
|
||||||
|
printError("There should be only one sprint at a time", nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
sprint := list.Values[0]
|
||||||
|
fmt.Printf("Using sprint %s (%d)\n", sprint.Name, sprint.ID)
|
||||||
|
viper.Set("sprint.id", sprint.ID)
|
||||||
|
viper.Set("sprint.name", sprint.Name)
|
||||||
|
SaveConfig()
|
||||||
|
UpdatePrompt()
|
||||||
|
}
|
||||||
|
|
||||||
|
func ActionListIssues(_ []string) {
|
||||||
|
sprintId := GetSprintId()
|
||||||
|
if sprintId == 0 {
|
||||||
|
printError("No sprint selected", nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
issues, _, err := jiraClient.Sprint.GetIssuesForSprint(sprintId)
|
||||||
|
if err != nil {
|
||||||
|
printError("Failed to list issues", err)
|
||||||
|
}
|
||||||
|
for _, issue := range issues {
|
||||||
|
red := color.New(color.FgRed).SprintFunc()
|
||||||
|
yellow := color.New(color.FgYellow).SprintFunc()
|
||||||
|
fmt.Printf("%s - %s (%s)\n", red(issue.Key), issue.Fields.Summary, yellow(issue.Fields.Status.Name))
|
||||||
|
}
|
||||||
|
}
|
109
commands.go
Normal file
109
commands.go
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/elk-language/go-prompt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Action func(args []string)
|
||||||
|
|
||||||
|
type CommandArg struct {
|
||||||
|
Name string
|
||||||
|
Action Action
|
||||||
|
Help string
|
||||||
|
Children []CommandArg
|
||||||
|
}
|
||||||
|
|
||||||
|
var commandIssues = CommandArg{Name: "issues"}
|
||||||
|
|
||||||
|
func option(name string, children ...CommandArg) CommandArg {
|
||||||
|
return command(name, nil, children...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func command(name string, action Action, children ...CommandArg) CommandArg {
|
||||||
|
return CommandArg{
|
||||||
|
Name: name,
|
||||||
|
Action: action,
|
||||||
|
Children: children,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (arg CommandArg) WithHelp(help string) CommandArg {
|
||||||
|
arg.Help = help
|
||||||
|
return arg
|
||||||
|
}
|
||||||
|
|
||||||
|
var CommandTree = []CommandArg{
|
||||||
|
option("list",
|
||||||
|
command("issues", ActionListIssues).WithHelp("List all issues in the current sprint"),
|
||||||
|
command("boards", ActionListBoards).WithHelp("List all boards in the current project"),
|
||||||
|
//command("sprints", ActionListIssues).WithHelp("List all issues in the current sprint"),
|
||||||
|
//option("open", option("issues")),
|
||||||
|
//option("closed", option("issues")),
|
||||||
|
command("projects", ActionListProjects).WithHelp("List all projects"),
|
||||||
|
).WithHelp("List things"),
|
||||||
|
option("use",
|
||||||
|
command("project", ActionUseProject).WithHelp("Use project [project key]"),
|
||||||
|
command("board", ActionUseBoard).WithHelp("Use board [board id]"),
|
||||||
|
option("current", command("sprint", ActionUseCurrentSprint).WithHelp("Use the current sprint")),
|
||||||
|
).WithHelp("Select something for further commands"),
|
||||||
|
//option("view",
|
||||||
|
// option("issue"),
|
||||||
|
// option("sprint"),
|
||||||
|
//),
|
||||||
|
command("exit", ActionExit).WithHelp("Exit jirashell"),
|
||||||
|
command("logout", ActionLogout).WithHelp("Logout from Jira"),
|
||||||
|
}
|
||||||
|
|
||||||
|
func getCommandFor(parts []string, tree []CommandArg) (*CommandArg, []string) {
|
||||||
|
for _, arg := range tree {
|
||||||
|
if arg.Name == parts[0] {
|
||||||
|
if len(parts) == 1 {
|
||||||
|
return &arg, []string{}
|
||||||
|
} else {
|
||||||
|
result, args := getCommandFor(parts[1:], arg.Children)
|
||||||
|
if result != nil {
|
||||||
|
return result, args
|
||||||
|
} else {
|
||||||
|
return &arg, parts[1:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetCommand(cmdline string) (*CommandArg, []string) {
|
||||||
|
commandParts := strings.Split(cmdline, " ")
|
||||||
|
command, args := getCommandFor(commandParts, CommandTree)
|
||||||
|
if command == nil || command.Action == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return command, args
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetSuggestionsForPart(parts []string, tree []CommandArg, suggests []prompt.Suggest) []prompt.Suggest {
|
||||||
|
for _, option := range tree {
|
||||||
|
if len(parts) == 0 {
|
||||||
|
suggests = append(suggests, prompt.Suggest{
|
||||||
|
Text: option.Name,
|
||||||
|
Description: option.Help,
|
||||||
|
})
|
||||||
|
} else if option.Name == parts[0] {
|
||||||
|
suggests = GetSuggestionsForPart(parts[1:], option.Children, suggests)
|
||||||
|
} else if len(parts) == 1 {
|
||||||
|
if strings.HasPrefix(option.Name, parts[0]) {
|
||||||
|
suggests = append(suggests, prompt.Suggest{
|
||||||
|
Text: option.Name,
|
||||||
|
Description: option.Help,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return suggests
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetSuggestionsFor(command string) []prompt.Suggest {
|
||||||
|
commandParts := strings.Split(command, " ")
|
||||||
|
return GetSuggestionsForPart(commandParts, CommandTree, []prompt.Suggest{})
|
||||||
|
}
|
27
commands_test.go
Normal file
27
commands_test.go
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSuggestionsOneLetter(t *testing.T) {
|
||||||
|
suggestions := GetSuggestionsFor("l")
|
||||||
|
require.Len(t, suggestions, 2)
|
||||||
|
require.Equal(t, "list", suggestions[0].Text)
|
||||||
|
require.Equal(t, "logout", suggestions[1].Text)
|
||||||
|
}
|
||||||
|
|
||||||
|
//func TestSuggestionsRoot(t *testing.T) {
|
||||||
|
// suggestions := GetSuggestionsFor("")
|
||||||
|
// require.Len(t, suggestions, 2)
|
||||||
|
// require.Equal(t, "list", suggestions[0].Text)
|
||||||
|
// require.Equal(t, "logout", suggestions[1].Text)
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//func TestSuggestionsFullPart(t *testing.T) {
|
||||||
|
// suggestions := GetSuggestionsFor("list")
|
||||||
|
// require.Len(t, suggestions, 2)
|
||||||
|
// require.Equal(t, "issues", suggestions[0].Text)
|
||||||
|
// require.Equal(t, "projects", suggestions[1].Text)
|
||||||
|
//}
|
51
go.mod
Normal file
51
go.mod
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
module gitea.seeseepuff.com/seeseemelk/jirashell/v2
|
||||||
|
|
||||||
|
go 1.23.2
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/abiosoft/ishell/v2 v2.0.2
|
||||||
|
github.com/adrg/xdg v0.5.0
|
||||||
|
github.com/andygrunwald/go-jira v1.16.0
|
||||||
|
github.com/elk-language/go-prompt v1.1.5
|
||||||
|
github.com/pkg/errors v0.9.1
|
||||||
|
github.com/spf13/viper v1.19.0
|
||||||
|
github.com/stretchr/testify v1.9.0
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/abiosoft/ishell v2.0.0+incompatible // indirect
|
||||||
|
github.com/abiosoft/readline v0.0.0-20180607040430-155bce2042db // indirect
|
||||||
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||||
|
github.com/fatih/color v1.14.1 // indirect
|
||||||
|
github.com/fatih/structs v1.1.0 // indirect
|
||||||
|
github.com/flynn-archive/go-shlex v0.0.0-20150515145356-3f9db97f8568 // indirect
|
||||||
|
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||||
|
github.com/golang-jwt/jwt/v4 v4.4.2 // indirect
|
||||||
|
github.com/google/go-querystring v1.1.0 // indirect
|
||||||
|
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||||
|
github.com/magiconair/properties v1.8.7 // indirect
|
||||||
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
|
github.com/mattn/go-isatty v0.0.17 // indirect
|
||||||
|
github.com/mattn/go-runewidth v0.0.9 // indirect
|
||||||
|
github.com/mattn/go-tty v0.0.3 // indirect
|
||||||
|
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||||
|
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
||||||
|
github.com/pkg/term v1.2.0-beta.2 // indirect
|
||||||
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||||
|
github.com/rivo/uniseg v0.4.4 // indirect
|
||||||
|
github.com/sagikazarmark/locafero v0.4.0 // indirect
|
||||||
|
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
||||||
|
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||||
|
github.com/spf13/afero v1.11.0 // indirect
|
||||||
|
github.com/spf13/cast v1.6.0 // indirect
|
||||||
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
|
github.com/subosito/gotenv v1.6.0 // indirect
|
||||||
|
github.com/trivago/tgo v1.0.7 // indirect
|
||||||
|
go.uber.org/atomic v1.9.0 // indirect
|
||||||
|
go.uber.org/multierr v1.9.0 // indirect
|
||||||
|
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
|
||||||
|
golang.org/x/sys v0.22.0 // indirect
|
||||||
|
golang.org/x/text v0.14.0 // indirect
|
||||||
|
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
)
|
136
go.sum
Normal file
136
go.sum
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
github.com/abiosoft/ishell v2.0.0+incompatible h1:zpwIuEHc37EzrsIYah3cpevrIc8Oma7oZPxr03tlmmw=
|
||||||
|
github.com/abiosoft/ishell v2.0.0+incompatible/go.mod h1:HQR9AqF2R3P4XXpMpI0NAzgHf/aS6+zVXRj14cVk9qg=
|
||||||
|
github.com/abiosoft/ishell/v2 v2.0.2 h1:5qVfGiQISaYM8TkbBl7RFO6MddABoXpATrsFbVI+SNo=
|
||||||
|
github.com/abiosoft/ishell/v2 v2.0.2/go.mod h1:E4oTCXfo6QjoCart0QYa5m9w4S+deXs/P/9jA77A9Bs=
|
||||||
|
github.com/abiosoft/readline v0.0.0-20180607040430-155bce2042db h1:CjPUSXOiYptLbTdr1RceuZgSFDQ7U15ITERUGrUORx8=
|
||||||
|
github.com/abiosoft/readline v0.0.0-20180607040430-155bce2042db/go.mod h1:rB3B4rKii8V21ydCbIzH5hZiCQE7f5E9SzUb/ZZx530=
|
||||||
|
github.com/adrg/xdg v0.5.0 h1:dDaZvhMXatArP1NPHhnfaQUqWBLBsmx1h1HXQdMoFCY=
|
||||||
|
github.com/adrg/xdg v0.5.0/go.mod h1:dDdY4M4DF9Rjy4kHPeNL+ilVF+p2lK8IdM9/rTSGcI4=
|
||||||
|
github.com/andygrunwald/go-jira v1.16.0 h1:PU7C7Fkk5L96JvPc6vDVIrd99vdPnYudHu4ju2c2ikQ=
|
||||||
|
github.com/andygrunwald/go-jira v1.16.0/go.mod h1:UQH4IBVxIYWbgagc0LF/k9FRs9xjIiQ8hIcC6HfLwFU=
|
||||||
|
github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE=
|
||||||
|
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||||
|
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8=
|
||||||
|
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||||
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/elk-language/go-prompt v1.1.5 h1:/pGHSmEICQbaJltkFYZtcQlm0fQ8WO3CgISkUnYXxYY=
|
||||||
|
github.com/elk-language/go-prompt v1.1.5/go.mod h1:iEK3nFtQZuRxpoUVZk7Tie27TyWL+RMLkv4wA39XkWc=
|
||||||
|
github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
|
||||||
|
github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w=
|
||||||
|
github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg=
|
||||||
|
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
|
||||||
|
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
|
||||||
|
github.com/flynn-archive/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BMXYYRWTLOJKlh+lOBt6nUQgXAfB7oVIQt5cNreqSLI=
|
||||||
|
github.com/flynn-archive/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:rZfgFAXFS/z/lEd6LJmf9HVZ1LkgYiHx5pHhV5DR16M=
|
||||||
|
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||||
|
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||||
|
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||||
|
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||||
|
github.com/golang-jwt/jwt/v4 v4.4.2 h1:rcc4lwaZgFMCZ5jxF9ABolDcIHdBytAFgqFPbSJQAYs=
|
||||||
|
github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||||
|
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
|
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||||
|
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
|
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
||||||
|
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
||||||
|
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||||
|
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||||
|
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
|
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||||
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
|
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
||||||
|
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||||
|
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||||
|
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||||
|
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||||
|
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||||
|
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||||
|
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
||||||
|
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||||
|
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||||
|
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
|
||||||
|
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||||
|
github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||||
|
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
|
||||||
|
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||||
|
github.com/mattn/go-tty v0.0.3 h1:5OfyWorkyO7xP52Mq7tB36ajHDG5OHrmBGIS/DtakQI=
|
||||||
|
github.com/mattn/go-tty v0.0.3/go.mod h1:ihxohKRERHTVzN+aSVRwACLCeqIoZAWpoICkkvrWyR0=
|
||||||
|
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||||
|
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||||
|
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
|
||||||
|
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
|
||||||
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pkg/term v1.2.0-beta.2 h1:L3y/h2jkuBVFdWiJvNfYfKmzcCnILw7mJWm2JQuMppw=
|
||||||
|
github.com/pkg/term v1.2.0-beta.2/go.mod h1:E25nymQcrSllhX42Ok8MRm1+hyBdHY0dCeiKZ9jpNGw=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||||
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
|
||||||
|
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||||
|
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||||
|
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||||
|
github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
|
||||||
|
github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
|
||||||
|
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
|
||||||
|
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
|
||||||
|
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
|
||||||
|
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
|
||||||
|
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
|
||||||
|
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
|
||||||
|
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
|
||||||
|
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||||
|
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||||
|
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
|
github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
|
||||||
|
github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
|
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||||
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
|
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||||
|
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
|
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||||
|
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||||
|
github.com/trivago/tgo v1.0.7 h1:uaWH/XIy9aWYWpjm2CU3RpcqZXmX2ysQ9/Go+d9gyrM=
|
||||||
|
github.com/trivago/tgo v1.0.7/go.mod h1:w4dpD+3tzNIIiIfkWWa85w5/B77tlvdZckQ+6PkFnhc=
|
||||||
|
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
|
||||||
|
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||||
|
go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
|
||||||
|
go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
|
||||||
|
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
|
||||||
|
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
|
||||||
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20220330033206-e17cdc41300f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
||||||
|
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
|
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||||
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||||
|
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
168
main.go
Normal file
168
main.go
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/abiosoft/ishell/v2"
|
||||||
|
"github.com/adrg/xdg"
|
||||||
|
"github.com/andygrunwald/go-jira"
|
||||||
|
prompt "github.com/elk-language/go-prompt"
|
||||||
|
pstrings "github.com/elk-language/go-prompt/strings"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
var configPath string
|
||||||
|
var shell *ishell.Shell
|
||||||
|
var jiraClient *jira.Client
|
||||||
|
var promptRunner *prompt.Prompt
|
||||||
|
var prefix = "> "
|
||||||
|
|
||||||
|
func loadConfig() {
|
||||||
|
err := viper.ReadInConfig()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func SaveConfig() {
|
||||||
|
err := viper.WriteConfig()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetProjectId() string {
|
||||||
|
return viper.GetString("project.id")
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetSprintId() int {
|
||||||
|
return viper.GetInt("sprint.id")
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdatePrompt() {
|
||||||
|
prefix = ""
|
||||||
|
project := viper.GetString("project.key")
|
||||||
|
if project != "" {
|
||||||
|
prefix = prefix + "p:" + project + " "
|
||||||
|
}
|
||||||
|
board := viper.GetString("board.name")
|
||||||
|
if board != "" {
|
||||||
|
prefix = prefix + "b:" + board + " "
|
||||||
|
}
|
||||||
|
sprint := viper.GetString("sprint.name")
|
||||||
|
if sprint != "" {
|
||||||
|
prefix = prefix + "s:" + sprint + " "
|
||||||
|
}
|
||||||
|
prefix = prefix[0:len(prefix)-1] + "> "
|
||||||
|
}
|
||||||
|
|
||||||
|
func executor(in string) {
|
||||||
|
command, args := GetCommand(in)
|
||||||
|
if command == nil {
|
||||||
|
println("Invalid command", in)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
command.Action(args)
|
||||||
|
}
|
||||||
|
|
||||||
|
func completer(d prompt.Document) ([]prompt.Suggest, pstrings.RuneNumber, pstrings.RuneNumber) {
|
||||||
|
endIndex := d.CurrentRuneIndex()
|
||||||
|
w := d.GetWordBeforeCursor()
|
||||||
|
startIndex := endIndex - pstrings.RuneCount([]byte(w))
|
||||||
|
s := GetSuggestionsFor(d.TextBeforeCursor())
|
||||||
|
return prompt.FilterHasPrefix(s, w, true), startIndex, endIndex
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// Open config file
|
||||||
|
configPath, err := xdg.ConfigFile("jirashell/config.toml")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
viper.SetConfigFile(configPath)
|
||||||
|
|
||||||
|
_, err = os.Stat(configPath)
|
||||||
|
if err != nil && !errors.Is(err, os.ErrNotExist) {
|
||||||
|
log.Fatal(err)
|
||||||
|
} else if err == nil {
|
||||||
|
loadConfig()
|
||||||
|
}
|
||||||
|
|
||||||
|
ensureLoggedIn()
|
||||||
|
UpdatePrompt()
|
||||||
|
|
||||||
|
promptRunner = prompt.New(
|
||||||
|
executor,
|
||||||
|
prompt.WithCompleter(completer),
|
||||||
|
prompt.WithTitle("jirashell"),
|
||||||
|
prompt.WithPrefixCallback(func() string { return prefix }),
|
||||||
|
)
|
||||||
|
promptRunner.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func ensureLoggedIn() {
|
||||||
|
for {
|
||||||
|
username := viper.GetString("username")
|
||||||
|
host := viper.GetString("host")
|
||||||
|
token := viper.GetString("token")
|
||||||
|
|
||||||
|
if host != "" && token != "" && username != "" {
|
||||||
|
println("Logging in...")
|
||||||
|
err := login(host, username, token)
|
||||||
|
if err != nil {
|
||||||
|
println("Could not log in:", err)
|
||||||
|
} else {
|
||||||
|
println("Logged in!")
|
||||||
|
SaveConfig()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
println()
|
||||||
|
println("A host name is required.")
|
||||||
|
host = prompt.Input(prompt.WithPrefix("Host: "), prompt.WithInitialText(host))
|
||||||
|
if host == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
viper.Set("host", host)
|
||||||
|
|
||||||
|
println()
|
||||||
|
println("A username is required.")
|
||||||
|
username = prompt.Input(prompt.WithPrefix("Username: "), prompt.WithInitialText(username))
|
||||||
|
if username == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
viper.Set("username", username)
|
||||||
|
|
||||||
|
println()
|
||||||
|
println("A token is required.")
|
||||||
|
token = prompt.Input(prompt.WithPrefix("Token: "), prompt.WithInitialText(token))
|
||||||
|
if token == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
viper.Set("token", token)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func login(host, username, token string) error {
|
||||||
|
var err error
|
||||||
|
tp := jira.BasicAuthTransport{
|
||||||
|
Username: username,
|
||||||
|
Password: token,
|
||||||
|
}
|
||||||
|
jiraClient, err = jira.NewClient(tp.Client(), host)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, _, err = jiraClient.User.GetSelf()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func noSuggestions(doc prompt.Document) []prompt.Suggest {
|
||||||
|
return make([]prompt.Suggest, 0)
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user