mirror of
https://gitea.com/gitea/tea.git
synced 2026-10-26 11:01:25 +01:00
refactor(completion): name path arguments explicitly and share firstArg
The six commands that take a file or directory argument set their completer directly instead of a Use-line parser wrapping every command, the first-argument-only wrappers become one firstArg helper, and only the bash completion help keeps a custom text. Signed-off-by: bircni <bircni@icloud.com>
This commit is contained in:
22 files changed
+75
-212
No files matched your search
@@ -38,7 +38,7 @@ $ tea run jobs 34 --json id,conclusion --jq '.[] | select(.conclusion == "failur
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
pageFlags(cmd, &limit, &page)
|
pageFlags(cmd, &limit, &page)
|
||||||
cmd.ValidArgsFunction = a.completeRunArg()
|
cmd.ValidArgsFunction = firstArg(a.completeRuns())
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ $ tea run logs 34 --output logs.zip`,
|
|||||||
cmd.Flags().BoolVarP(&follow, "follow", "f", false, "Wait for jobs to start and print new lines until they complete")
|
cmd.Flags().BoolVarP(&follow, "follow", "f", false, "Wait for jobs to start and print new lines until they complete")
|
||||||
cmd.Flags().DurationVarP(&interval, "interval", "i", 5*time.Second, "Polling interval with --follow")
|
cmd.Flags().DurationVarP(&interval, "interval", "i", 5*time.Second, "Polling interval with --follow")
|
||||||
cmd.Flags().DurationVar(&timeout, "timeout", time.Hour, "Maximum time to follow")
|
cmd.Flags().DurationVar(&timeout, "timeout", time.Hour, "Maximum time to follow")
|
||||||
cmd.ValidArgsFunction = a.completeRunArg()
|
cmd.ValidArgsFunction = firstArg(a.completeRuns())
|
||||||
_ = cmd.RegisterFlagCompletionFunc("job", a.completeJobs())
|
_ = cmd.RegisterFlagCompletionFunc("job", a.completeJobs())
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -228,7 +228,7 @@ $ tea run view 34 --json jobs --jq '.jobs[] | {name, conclusion}'`,
|
|||||||
cmd.Flags().BoolVar(&noJobs, "no-jobs", false, "Leave out the jobs")
|
cmd.Flags().BoolVar(&noJobs, "no-jobs", false, "Leave out the jobs")
|
||||||
cmd.Flags().BoolVarP(&web, "web", "w", false, "Open the run in the browser")
|
cmd.Flags().BoolVarP(&web, "web", "w", false, "Open the run in the browser")
|
||||||
cmd.Flags().BoolVar(&log, "log", false, "Print the logs of every job instead, like tea run logs")
|
cmd.Flags().BoolVar(&log, "log", false, "Print the logs of every job instead, like tea run logs")
|
||||||
cmd.ValidArgsFunction = a.completeRunArg()
|
cmd.ValidArgsFunction = firstArg(a.completeRuns())
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -459,17 +459,6 @@ func (a *application) runPicker() (terminal.Chooser, bool) {
|
|||||||
return chooser, err == nil && a.policy(s).CanPrompt(a.deps.Streams)
|
return chooser, err == nil && a.policy(s).CanPrompt(a.deps.Streams)
|
||||||
}
|
}
|
||||||
|
|
||||||
// completeRunArg completes the run argument of a run command with recent runs.
|
|
||||||
func (a *application) completeRunArg() cobra.CompletionFunc {
|
|
||||||
runs := a.completeRuns()
|
|
||||||
return func(cmd *cobra.Command, args []string, toComplete string) ([]cobra.Completion, cobra.ShellCompDirective) {
|
|
||||||
if len(args) > 0 {
|
|
||||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
|
||||||
}
|
|
||||||
return runs(cmd, args, toComplete)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// accountNote reminds people who pass the global --user, which selects the account tea acts as,
|
// accountNote reminds people who pass the global --user, which selects the account tea acts as,
|
||||||
// of the flag they may have meant, as gh's --user means something else.
|
// of the flag they may have meant, as gh's --user means something else.
|
||||||
func (a *application) accountNote(cmd *cobra.Command, t target, hint string) {
|
func (a *application) accountNote(cmd *cobra.Command, t target, hint string) {
|
||||||
@@ -507,7 +496,7 @@ $ tea run watch 34 --timeout 10m && echo deployed`,
|
|||||||
}
|
}
|
||||||
cmd.Flags().DurationVarP(&interval, "interval", "i", 3*time.Second, "Refresh interval")
|
cmd.Flags().DurationVarP(&interval, "interval", "i", 3*time.Second, "Refresh interval")
|
||||||
cmd.Flags().DurationVar(&timeout, "timeout", time.Hour, "Maximum time to wait")
|
cmd.Flags().DurationVar(&timeout, "timeout", time.Hour, "Maximum time to wait")
|
||||||
cmd.ValidArgsFunction = a.completeRunArg()
|
cmd.ValidArgsFunction = firstArg(a.completeRuns())
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -622,7 +611,7 @@ $ tea run cancel 34 --force`,
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
cmd.Flags().BoolVar(&force, "force", false, "Cancel without waiting for the runner to acknowledge")
|
cmd.Flags().BoolVar(&force, "force", false, "Cancel without waiting for the runner to acknowledge")
|
||||||
cmd.ValidArgsFunction = a.completeRunArg()
|
cmd.ValidArgsFunction = firstArg(a.completeRuns())
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -681,7 +670,7 @@ $ tea run rerun 34 --job build`,
|
|||||||
}
|
}
|
||||||
cmd.Flags().BoolVar(&failed, "failed", false, "Rerun only the failed jobs")
|
cmd.Flags().BoolVar(&failed, "failed", false, "Rerun only the failed jobs")
|
||||||
cmd.Flags().StringVarP(&job, "job", "j", "", "Rerun only this job, by `name or ID`")
|
cmd.Flags().StringVarP(&job, "job", "j", "", "Rerun only this job, by `name or ID`")
|
||||||
cmd.ValidArgsFunction = a.completeRunArg()
|
cmd.ValidArgsFunction = firstArg(a.completeRuns())
|
||||||
_ = cmd.RegisterFlagCompletionFunc("job", a.completeJobs())
|
_ = cmd.RegisterFlagCompletionFunc("job", a.completeJobs())
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
@@ -736,7 +725,7 @@ $ tea run delete 34 --yes`,
|
|||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
cmd.ValidArgsFunction = a.completeRunArg()
|
cmd.ValidArgsFunction = firstArg(a.completeRuns())
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -433,10 +433,5 @@ func (a *application) completeActionValues(secret bool, scope *actionScopeFlags)
|
|||||||
if secret {
|
if secret {
|
||||||
names = a.completeSecrets(scope.scope)
|
names = a.completeSecrets(scope.scope)
|
||||||
}
|
}
|
||||||
return func(cmd *cobra.Command, args []string, toComplete string) ([]cobra.Completion, cobra.ShellCompDirective) {
|
return firstArg(names)
|
||||||
if len(args) > 0 {
|
|
||||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
|
||||||
}
|
|
||||||
return names(cmd, args, toComplete)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
+3
-14
@@ -128,7 +128,7 @@ $ tea workflow view ci --web`,
|
|||||||
cmd.Flags().BoolVar(&showYAML, "yaml", false, "Print the workflow file")
|
cmd.Flags().BoolVar(&showYAML, "yaml", false, "Print the workflow file")
|
||||||
cmd.Flags().StringVarP(&ref, "ref", "r", "", "Branch, tag or commit of the workflow file that --yaml prints (default: the default branch)")
|
cmd.Flags().StringVarP(&ref, "ref", "r", "", "Branch, tag or commit of the workflow file that --yaml prints (default: the default branch)")
|
||||||
cmd.Flags().BoolVarP(&web, "web", "w", false, "Open the workflow file in the browser")
|
cmd.Flags().BoolVarP(&web, "web", "w", false, "Open the workflow file in the browser")
|
||||||
cmd.ValidArgsFunction = a.completeWorkflowArg()
|
cmd.ValidArgsFunction = firstArg(a.completeWorkflows())
|
||||||
_ = cmd.RegisterFlagCompletionFunc("ref", a.completeBranches())
|
_ = cmd.RegisterFlagCompletionFunc("ref", a.completeBranches())
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
@@ -269,7 +269,7 @@ $ tea workflow run nightly --follow`,
|
|||||||
cmd.Flags().BoolVar(&follow, "follow", false, "Follow the logs of the run's jobs after dispatching it")
|
cmd.Flags().BoolVar(&follow, "follow", false, "Follow the logs of the run's jobs after dispatching it")
|
||||||
cmd.Flags().DurationVar(&interval, "interval", 2*time.Second, "Polling interval with --follow")
|
cmd.Flags().DurationVar(&interval, "interval", 2*time.Second, "Polling interval with --follow")
|
||||||
cmd.Flags().DurationVar(&timeout, "timeout", 30*time.Minute, "Maximum time to follow")
|
cmd.Flags().DurationVar(&timeout, "timeout", 30*time.Minute, "Maximum time to follow")
|
||||||
cmd.ValidArgsFunction = a.completeWorkflowArg()
|
cmd.ValidArgsFunction = firstArg(a.completeWorkflows())
|
||||||
_ = cmd.RegisterFlagCompletionFunc("ref", a.completeBranches())
|
_ = cmd.RegisterFlagCompletionFunc("ref", a.completeBranches())
|
||||||
_ = cmd.RegisterFlagCompletionFunc("field", a.completeWorkflowInputs())
|
_ = cmd.RegisterFlagCompletionFunc("field", a.completeWorkflowInputs())
|
||||||
_ = cmd.RegisterFlagCompletionFunc("input", a.completeWorkflowInputs())
|
_ = cmd.RegisterFlagCompletionFunc("input", a.completeWorkflowInputs())
|
||||||
@@ -445,7 +445,7 @@ func (a *application) workflowStateCommand(enable bool) *cobra.Command {
|
|||||||
$ tea workflow %s Nightly`, verb, verb),
|
$ tea workflow %s Nightly`, verb, verb),
|
||||||
Args: argsExact(1),
|
Args: argsExact(1),
|
||||||
Annotations: map[string]string{"tea.arguments": workflowArguments},
|
Annotations: map[string]string{"tea.arguments": workflowArguments},
|
||||||
ValidArgsFunction: a.completeWorkflowArg(),
|
ValidArgsFunction: firstArg(a.completeWorkflows()),
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
t, err := a.resolve(cmd.Context(), true)
|
t, err := a.resolve(cmd.Context(), true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -472,17 +472,6 @@ $ tea workflow %s Nightly`, verb, verb),
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// completeWorkflowArg completes the workflow argument with workflow files.
|
|
||||||
func (a *application) completeWorkflowArg() cobra.CompletionFunc {
|
|
||||||
workflows := a.completeWorkflows()
|
|
||||||
return func(cmd *cobra.Command, args []string, toComplete string) ([]cobra.Completion, cobra.ShellCompDirective) {
|
|
||||||
if len(args) > 0 {
|
|
||||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
|
||||||
}
|
|
||||||
return workflows(cmd, args, toComplete)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// completeWorkflowInputs completes the inputs of the workflow given as the first argument as
|
// completeWorkflowInputs completes the inputs of the workflow given as the first argument as
|
||||||
// name=, then the values of a choice or boolean input.
|
// name=, then the values of a choice or boolean input.
|
||||||
func (a *application) completeWorkflowInputs() cobra.CompletionFunc {
|
func (a *application) completeWorkflowInputs() cobra.CompletionFunc {
|
||||||
|
|||||||
@@ -124,6 +124,8 @@ func TestCompletionOffersPathsOnlyWherePathsAreExpected(t *testing.T) {
|
|||||||
"release asset upload v1 a.txt ": cobra.ShellCompDirectiveDefault,
|
"release asset upload v1 a.txt ": cobra.ShellCompDirectiveDefault,
|
||||||
"repo clone alice/project ": cobra.ShellCompDirectiveFilterDirs,
|
"repo clone alice/project ": cobra.ShellCompDirectiveFilterDirs,
|
||||||
"repo clone alice/project dir ": cobra.ShellCompDirectiveNoFileComp,
|
"repo clone alice/project dir ": cobra.ShellCompDirectiveNoFileComp,
|
||||||
|
"issue attachment upload 5 ": cobra.ShellCompDirectiveDefault,
|
||||||
|
"release create v1 ": cobra.ShellCompDirectiveDefault,
|
||||||
"--cwd ": cobra.ShellCompDirectiveFilterDirs,
|
"--cwd ": cobra.ShellCompDirectiveFilterDirs,
|
||||||
"--jq ": cobra.ShellCompDirectiveNoFileComp,
|
"--jq ": cobra.ShellCompDirectiveNoFileComp,
|
||||||
} {
|
} {
|
||||||
@@ -136,9 +138,9 @@ func TestCompletionOffersPathsOnlyWherePathsAreExpected(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
path := strings.Fields(cmd.CommandPath())[1:]
|
path := strings.Fields(cmd.CommandPath())[1:]
|
||||||
slots := argSlots(cmd.Use)
|
|
||||||
_, directive := complete(t, deps, out, append(path, "")...)
|
_, directive := complete(t, deps, out, append(path, "")...)
|
||||||
require.Equal(t, len(slots) > 0 && slots[0].kind == "file", directive == cobra.ShellCompDirectiveDefault, "%s <TAB>: %d", cmd.CommandPath(), directive)
|
takesFile := cmd.CommandPath() == "tea label import" || cmd.CommandPath() == "tea ssh-key create"
|
||||||
|
require.Equal(t, takesFile, directive == cobra.ShellCompDirectiveDefault, "%s <TAB>: %d", cmd.CommandPath(), directive)
|
||||||
for _, flags := range []*pflag.FlagSet{cmd.LocalNonPersistentFlags(), cmd.PersistentFlags()} {
|
for _, flags := range []*pflag.FlagSet{cmd.LocalNonPersistentFlags(), cmd.PersistentFlags()} {
|
||||||
flags.VisitAll(func(flag *pflag.Flag) {
|
flags.VisitAll(func(flag *pflag.Flag) {
|
||||||
if flag.NoOptDefVal != "" || flag.Hidden {
|
if flag.NoOptDefVal != "" || flag.Hidden {
|
||||||
@@ -152,21 +154,6 @@ func TestCompletionOffersPathsOnlyWherePathsAreExpected(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestArgSlots(t *testing.T) {
|
|
||||||
for use, want := range map[string][]argSlot{
|
|
||||||
"list": {},
|
|
||||||
"view <number>": {{}},
|
|
||||||
"upload <tag> <file>...": {{}, {kind: "file", variadic: true}},
|
|
||||||
"clone <repository> [directory]": {{}, {kind: "directory"}},
|
|
||||||
"create <public-key-file>": {{kind: "file"}},
|
|
||||||
"review [<number> | <url> | <branch>]": {{}},
|
|
||||||
"man [command...]": {{variadic: true}},
|
|
||||||
"set <key> <value>": {{}, {}},
|
|
||||||
} {
|
|
||||||
require.Equal(t, want, append([]argSlot{}, argSlots(use)...), use)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestOfflineCompletions(t *testing.T) {
|
func TestOfflineCompletions(t *testing.T) {
|
||||||
deps, out, _ := testDeps(t)
|
deps, out, _ := testDeps(t)
|
||||||
deps.Git = &fakeGit{results: map[string]string{
|
deps.Git = &fakeGit{results: map[string]string{
|
||||||
@@ -338,15 +325,6 @@ func TestInstanceCompletions(t *testing.T) {
|
|||||||
|
|
||||||
func TestCompletionInstallHelp(t *testing.T) {
|
func TestCompletionInstallHelp(t *testing.T) {
|
||||||
deps, out, _ := testDeps(t)
|
deps, out, _ := testDeps(t)
|
||||||
for shell, want := range map[string]string{
|
require.NoError(t, Execute(context.Background(), deps, []string{"completion", "bash", "--help"}))
|
||||||
"bash": "$ eval \"$(tea completion bash)\"\n",
|
require.Contains(t, out.String(), "$ eval \"$(tea completion bash)\"\n")
|
||||||
"zsh": "$ autoload -U compinit && compinit\n",
|
|
||||||
"fish": "$ tea completion fish > ~/.config/fish/completions/tea.fish\n",
|
|
||||||
"powershell": "$ tea completion powershell | Out-String | Invoke-Expression\n",
|
|
||||||
} {
|
|
||||||
out.Reset()
|
|
||||||
require.NoError(t, Execute(context.Background(), deps, []string{"completion", shell, "--help"}))
|
|
||||||
require.Contains(t, out.String(), want, shell)
|
|
||||||
require.NotContains(t, out.String(), "source <(tea completion bash)\n", shell)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -50,7 +50,7 @@ $ tea run artifact list 34`,
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
pageFlags(list, &limit, &page)
|
pageFlags(list, &limit, &page)
|
||||||
list.ValidArgsFunction = a.completeRunArg()
|
list.ValidArgsFunction = firstArg(a.completeRuns())
|
||||||
group.AddCommand(list)
|
group.AddCommand(list)
|
||||||
|
|
||||||
return group
|
return group
|
||||||
@@ -148,7 +148,7 @@ $ tea run download 34 --zip`,
|
|||||||
destination.register(cmd)
|
destination.register(cmd)
|
||||||
cmd.Flags().StringSliceVarP(&names, "name", "n", nil, "Only download the artifacts with these names")
|
cmd.Flags().StringSliceVarP(&names, "name", "n", nil, "Only download the artifacts with these names")
|
||||||
cmd.Flags().BoolVar(&asZip, "zip", false, "Save each artifact as a ZIP archive instead of extracting it")
|
cmd.Flags().BoolVar(&asZip, "zip", false, "Save each artifact as a ZIP archive instead of extracting it")
|
||||||
cmd.ValidArgsFunction = a.completeRunArg()
|
cmd.ValidArgsFunction = firstArg(a.completeRuns())
|
||||||
_ = cmd.RegisterFlagCompletionFunc("name", commaSeparated(a.completeArtifactNames()))
|
_ = cmd.RegisterFlagCompletionFunc("name", commaSeparated(a.completeArtifactNames()))
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -426,13 +426,7 @@ func article(noun string) string {
|
|||||||
// completeDiscussions completes the open issues or pull requests that a command of kind takes.
|
// completeDiscussions completes the open issues or pull requests that a command of kind takes.
|
||||||
func (a *application) completeDiscussions(kind refKind) cobra.CompletionFunc {
|
func (a *application) completeDiscussions(kind refKind) cobra.CompletionFunc {
|
||||||
if kind == pullRef {
|
if kind == pullRef {
|
||||||
complete := a.completePulls("open")
|
return firstArg(a.completePulls("open"))
|
||||||
return func(cmd *cobra.Command, args []string, toComplete string) ([]cobra.Completion, cobra.ShellCompDirective) {
|
|
||||||
if len(args) > 0 {
|
|
||||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
|
||||||
}
|
|
||||||
return complete(cmd, args, toComplete)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return a.completeIssueArgs("open", false)
|
return firstArg(a.completeIssues("open"))
|
||||||
}
|
}
|
||||||
+36
-89
@@ -519,9 +519,9 @@ func actionScope(scope func() services.ActionScope, t target) services.ActionSco
|
|||||||
// pathFlags take local file paths, like every flag whose name ends in -file.
|
// pathFlags take local file paths, like every flag whose name ends in -file.
|
||||||
var pathFlags = []string{"asset", "attachment", "file", "input", "ssh-key"}
|
var pathFlags = []string{"asset", "attachment", "file", "input", "ssh-key"}
|
||||||
|
|
||||||
// completeDefaults completes paths only where a command takes them: path flags, flags marked with
|
// completeDefaults completes paths only where a command takes them: path flags and flags marked
|
||||||
// MarkFlagFilename, and positional arguments named file or directory in Use. Everything else without a
|
// with MarkFlagFilename. Everything else without a completer completes nothing, by the root's
|
||||||
// completer completes nothing, by the root's default directive, rather than file names.
|
// default directive, rather than file names.
|
||||||
func completeDefaults(cmd *cobra.Command) {
|
func completeDefaults(cmd *cobra.Command) {
|
||||||
for _, flags := range []*pflag.FlagSet{cmd.Flags(), cmd.PersistentFlags()} {
|
for _, flags := range []*pflag.FlagSet{cmd.Flags(), cmd.PersistentFlags()} {
|
||||||
flags.VisitAll(func(flag *pflag.Flag) {
|
flags.VisitAll(func(flag *pflag.Flag) {
|
||||||
@@ -536,23 +536,6 @@ func completeDefaults(cmd *cobra.Command) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if slots := argSlots(cmd.Use); len(slots) > 0 {
|
|
||||||
complete := cmd.ValidArgsFunction
|
|
||||||
cmd.ValidArgsFunction = func(c *cobra.Command, args []string, toComplete string) ([]cobra.Completion, cobra.ShellCompDirective) {
|
|
||||||
slot := slots[min(len(args), len(slots)-1)]
|
|
||||||
switch {
|
|
||||||
case len(args) >= len(slots) && !slot.variadic:
|
|
||||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
|
||||||
case slot.kind == "file":
|
|
||||||
return completeFiles(c, args, toComplete)
|
|
||||||
case slot.kind == "directory":
|
|
||||||
return completeDirectories(c, args, toComplete)
|
|
||||||
case complete != nil:
|
|
||||||
return complete(c, args, toComplete)
|
|
||||||
}
|
|
||||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, child := range cmd.Commands() {
|
for _, child := range cmd.Commands() {
|
||||||
completeDefaults(child)
|
completeDefaults(child)
|
||||||
}
|
}
|
||||||
@@ -568,89 +551,53 @@ func completeDirectories(*cobra.Command, []string, string) ([]cobra.Completion,
|
|||||||
return nil, cobra.ShellCompDirectiveFilterDirs
|
return nil, cobra.ShellCompDirectiveFilterDirs
|
||||||
}
|
}
|
||||||
|
|
||||||
// argSlot is one positional argument that a Use line declares, such as <number>, [directory] or
|
// firstArg completes only the first argument with complete.
|
||||||
// <file>...; kind is "file" or "directory" for path arguments.
|
func firstArg(complete cobra.CompletionFunc) cobra.CompletionFunc {
|
||||||
type argSlot struct {
|
return func(cmd *cobra.Command, args []string, toComplete string) ([]cobra.Completion, cobra.ShellCompDirective) {
|
||||||
kind string
|
if len(args) > 0 {
|
||||||
variadic bool
|
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||||
}
|
|
||||||
|
|
||||||
// argSlots parses the positional arguments of a Use line.
|
|
||||||
func argSlots(use string) []argSlot {
|
|
||||||
_, rest, _ := strings.Cut(use, " ")
|
|
||||||
var slots []argSlot
|
|
||||||
depth, start := 0, 0
|
|
||||||
for i, r := range rest {
|
|
||||||
switch r {
|
|
||||||
case '<', '[', '{':
|
|
||||||
if depth == 0 {
|
|
||||||
start = i
|
|
||||||
}
|
|
||||||
depth++
|
|
||||||
case '>', ']', '}':
|
|
||||||
if depth--; depth != 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
slot := argSlot{variadic: strings.HasPrefix(rest[i+1:], "...") || strings.HasSuffix(rest[start:i], "...")}
|
|
||||||
for name := range strings.FieldsFuncSeq(rest[start:i+1], func(r rune) bool { return strings.ContainsRune("<>[]|. ", r) }) {
|
|
||||||
switch {
|
|
||||||
case name == "file" || strings.HasSuffix(name, "-file"):
|
|
||||||
slot.kind = "file"
|
|
||||||
case name == "directory" || name == "dir":
|
|
||||||
slot.kind = "directory"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
slots = append(slots, slot)
|
|
||||||
}
|
}
|
||||||
|
return complete(cmd, args, toComplete)
|
||||||
}
|
}
|
||||||
return slots
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// completionInstallHelp explains how to load the completion scripts, including with macOS's bash 3.2
|
// pathArgs completes the arguments before position n with complete, and paths with path from
|
||||||
// and in zsh without compinit.
|
// position n on: every later argument when variadic, else only the one at n.
|
||||||
|
func pathArgs(n int, variadic bool, path, complete cobra.CompletionFunc) cobra.CompletionFunc {
|
||||||
|
return func(cmd *cobra.Command, args []string, toComplete string) ([]cobra.Completion, cobra.ShellCompDirective) {
|
||||||
|
switch {
|
||||||
|
case len(args) < n:
|
||||||
|
return complete(cmd, args, toComplete)
|
||||||
|
case len(args) == n || variadic:
|
||||||
|
return path(cmd, args, toComplete)
|
||||||
|
}
|
||||||
|
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// completionInstallHelp explains how to load the bash script with macOS's bash 3.2, which cannot
|
||||||
|
// source <(tea completion bash); cobra's help covers the other shells.
|
||||||
func completionInstallHelp(root *cobra.Command) {
|
func completionInstallHelp(root *cobra.Command) {
|
||||||
completion, _, err := root.Find([]string{"completion"})
|
completion, _, err := root.Find([]string{"completion"})
|
||||||
if err != nil || completion == root {
|
if err != nil || completion == root {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
completion.Short = "Generate shell completion scripts"
|
completion.Short = "Generate shell completion scripts"
|
||||||
completion.Long = `Generate shell completion scripts for tea.
|
examples := map[string]string{
|
||||||
|
"bash": `$ eval "$(tea completion bash)"`,
|
||||||
Completion offers commands, flags, flag values such as --state or --json fields, and values
|
"zsh": `$ source <(tea completion zsh)`,
|
||||||
from the selected instance, such as repositories, issue numbers and labels. See
|
"fish": `$ tea completion fish > ~/.config/fish/completions/tea.fish`,
|
||||||
tea completion <shell> --help for how to load the script in your shell.`
|
"powershell": `$ tea completion powershell | Out-String | Invoke-Expression`,
|
||||||
help := map[string][2]string{
|
|
||||||
"bash": {`Generate the completion script for bash.
|
|
||||||
|
|
||||||
The script needs the bash-completion package. On macOS, install bash-completion with
|
|
||||||
Homebrew for the system bash 3.2, or bash-completion@2 for a Homebrew bash, and load it
|
|
||||||
as its install notes say.
|
|
||||||
|
|
||||||
To load completions in every new shell, add the eval line below to ~/.bashrc (on macOS,
|
|
||||||
~/.bash_profile). Use eval: bash 3.2, the default on macOS, cannot source <(tea completion bash).`, `# Load completions in this shell, or in every shell from ~/.bashrc
|
|
||||||
$ eval "$(tea completion bash)"
|
|
||||||
# Or install the script for every user (Linux, then macOS)
|
|
||||||
$ tea completion bash > /etc/bash_completion.d/tea
|
|
||||||
$ tea completion bash > "$(brew --prefix)/etc/bash_completion.d/tea"`},
|
|
||||||
"zsh": {`Generate the completion script for zsh.
|
|
||||||
|
|
||||||
Completion must be initialized before the script loads: add these lines to ~/.zshrc,
|
|
||||||
keeping an existing compinit call instead of the first line. Without compinit, zsh
|
|
||||||
reports "command not found: compdef".`, `$ autoload -U compinit && compinit
|
|
||||||
$ source <(tea completion zsh)
|
|
||||||
# Or install the script into a directory of your fpath once
|
|
||||||
$ tea completion zsh > "${fpath[1]}/_tea"`},
|
|
||||||
"fish": {`Generate the completion script for fish.
|
|
||||||
|
|
||||||
To load completions in every new shell, install the script once.`, `$ tea completion fish > ~/.config/fish/completions/tea.fish`},
|
|
||||||
"powershell": {`Generate the completion script for PowerShell.
|
|
||||||
|
|
||||||
To load completions in every new shell, add this line to your PowerShell profile.`, `$ tea completion powershell | Out-String | Invoke-Expression`},
|
|
||||||
}
|
}
|
||||||
for _, shell := range completion.Commands() {
|
for _, shell := range completion.Commands() {
|
||||||
shell.Long, shell.Example = help[shell.Name()][0], help[shell.Name()][1]
|
shell.Example = examples[shell.Name()]
|
||||||
if flag := shell.Flags().Lookup("no-descriptions"); flag != nil {
|
if flag := shell.Flags().Lookup("no-descriptions"); flag != nil {
|
||||||
flag.Usage = "Disable completion descriptions"
|
flag.Usage = "Disable completion descriptions"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
bash, _, _ := completion.Find([]string{"bash"})
|
||||||
|
bash.Long = `Generate the completion script for bash. It needs the bash-completion package.
|
||||||
|
|
||||||
|
To load completions in every new shell, add the eval line below to ~/.bashrc (on macOS,
|
||||||
|
~/.bash_profile); bash 3.2, the default on macOS, cannot source <(tea completion bash).`
|
||||||
}
|
}
|
||||||
@@ -90,7 +90,7 @@ are addressed by the %s number and the attachment ID that attachment list shows.
|
|||||||
|
|
||||||
var uploadName string
|
var uploadName string
|
||||||
upload := &cobra.Command{Use: "upload {<number> | <url>} <file>", Short: "Attach a file", Example: fmt.Sprintf(`$ tea %[1]s attachment upload %[2]s crash.log
|
upload := &cobra.Command{Use: "upload {<number> | <url>} <file>", Short: "Attach a file", Example: fmt.Sprintf(`$ tea %[1]s attachment upload %[2]s crash.log
|
||||||
$ tea %[1]s attachment upload %[2]s screenshot.png --name before.png`, words.group, words.example), Annotations: annotations, Args: argsExact(2), ValidArgsFunction: completeFirst, RunE: func(cmd *cobra.Command, args []string) error {
|
$ tea %[1]s attachment upload %[2]s screenshot.png --name before.png`, words.group, words.example), Annotations: annotations, Args: argsExact(2), ValidArgsFunction: pathArgs(1, false, completeFiles, completeFirst), RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
name := uploadName
|
name := uploadName
|
||||||
if cmd.Flags().Changed("name") && strings.TrimSpace(name) == "" {
|
if cmd.Flags().Changed("name") && strings.TrimSpace(name) == "" {
|
||||||
return clierr.Wrap(clierr.Usage, errors.New("--name cannot be empty"))
|
return clierr.Wrap(clierr.Usage, errors.New("--name cannot be empty"))
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ $ tea issue edit 12 --body-file notes.md`, Annotations: map[string]string{"tea.a
|
|||||||
a.completeMetadataFlags(cmd)
|
a.completeMetadataFlags(cmd)
|
||||||
_ = cmd.RegisterFlagCompletionFunc("milestone", a.completeMilestones())
|
_ = cmd.RegisterFlagCompletionFunc("milestone", a.completeMilestones())
|
||||||
_ = cmd.RegisterFlagCompletionFunc("ref", a.completeBranches())
|
_ = cmd.RegisterFlagCompletionFunc("ref", a.completeBranches())
|
||||||
cmd.ValidArgsFunction = a.completeIssueArgs("open", true)
|
cmd.ValidArgsFunction = a.completeIssues("open")
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-14
@@ -187,22 +187,10 @@ $ tea issue view https://gitea.com/OWNER/REPO/issues/12 --web`, Annotations: map
|
|||||||
}}
|
}}
|
||||||
cmd.Flags().BoolVarP(&web, "web", "w", false, "Open the issue in the browser")
|
cmd.Flags().BoolVarP(&web, "web", "w", false, "Open the issue in the browser")
|
||||||
cmd.Flags().BoolVarP(&comments, "comments", "c", false, "View issue comments")
|
cmd.Flags().BoolVarP(&comments, "comments", "c", false, "View issue comments")
|
||||||
cmd.ValidArgsFunction = a.completeIssueArgs("open", false)
|
cmd.ValidArgsFunction = firstArg(a.completeIssues("open"))
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
// completeIssueArgs completes issue numbers in state for the first argument, or for every
|
|
||||||
// argument when variadic.
|
|
||||||
func (a *application) completeIssueArgs(state string, variadic bool) cobra.CompletionFunc {
|
|
||||||
complete := a.completeIssues(state)
|
|
||||||
return func(cmd *cobra.Command, args []string, toComplete string) ([]cobra.Completion, cobra.ShellCompDirective) {
|
|
||||||
if len(args) > 0 && !variadic {
|
|
||||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
|
||||||
}
|
|
||||||
return complete(cmd, args, toComplete)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *application) issueCreateCommand() *cobra.Command {
|
func (a *application) issueCreateCommand() *cobra.Command {
|
||||||
var title, body, bodyFile, deadline, templateName, ref, milestone string
|
var title, body, bodyFile, deadline, templateName, ref, milestone string
|
||||||
var useEditor, web bool
|
var useEditor, web bool
|
||||||
@@ -446,7 +434,7 @@ $ tea issue %[1]s 12 13 --comment "Done in #14"`, verb), Annotations: map[string
|
|||||||
return errors.Join(append(failures, writeBatchJSON(a, cmd, len(numbers), results))...)
|
return errors.Join(append(failures, writeBatchJSON(a, cmd, len(numbers), results))...)
|
||||||
}}
|
}}
|
||||||
cmd.Flags().StringVarP(&comment, "comment", "c", "", "Leave a comment before the issue is "+state)
|
cmd.Flags().StringVarP(&comment, "comment", "c", "", "Leave a comment before the issue is "+state)
|
||||||
cmd.ValidArgsFunction = a.completeIssueArgs(completeState, true)
|
cmd.ValidArgsFunction = a.completeIssues(completeState)
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -302,7 +302,7 @@ func (a *application) labelImportCommand(scope labelScope) *cobra.Command {
|
|||||||
" ;description" and " ;exclusive", " ;archived" or both. tea label export writes this
|
" ;description" and " ;exclusive", " ;archived" or both. tea label export writes this
|
||||||
format, and Gitea's label templates use it. Existing labels are refused unless --force
|
format, and Gitea's label templates use it. Existing labels are refused unless --force
|
||||||
updates them.`, Example: `$ tea label import labels.txt
|
updates them.`, Example: `$ tea label import labels.txt
|
||||||
$ tea label export --repo alice/old | tea label import - --repo alice/new`, Args: argsExact(1), RunE: func(cmd *cobra.Command, args []string) error {
|
$ tea label export --repo alice/old | tea label import - --repo alice/new`, Args: argsExact(1), ValidArgsFunction: completeFiles, RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
return a.importLabels(cmd, scope, args[0], force)
|
return a.importLabels(cmd, scope, args[0], force)
|
||||||
}}
|
}}
|
||||||
cmd.Flags().BoolVarP(&force, "force", "f", false, "Update labels that exist already")
|
cmd.Flags().BoolVarP(&force, "force", "f", false, "Update labels that exist already")
|
||||||
|
|||||||
@@ -161,7 +161,7 @@ $ tea milestone view 3 --web`, Annotations: map[string]string{"tea.arguments": m
|
|||||||
}}
|
}}
|
||||||
cmd.Flags().BoolVar(&byName, "by-name", false, "Match a numeric argument as a milestone title rather than an ID")
|
cmd.Flags().BoolVar(&byName, "by-name", false, "Match a numeric argument as a milestone title rather than an ID")
|
||||||
cmd.Flags().BoolVarP(&web, "web", "w", false, "Open the milestone in the browser")
|
cmd.Flags().BoolVarP(&web, "web", "w", false, "Open the milestone in the browser")
|
||||||
cmd.ValidArgsFunction = a.completeMilestoneArgs(false)
|
cmd.ValidArgsFunction = firstArg(a.completeMilestones())
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -340,7 +340,7 @@ $ tea milestone edit 3 --editor`, Annotations: map[string]string{"tea.arguments"
|
|||||||
}}
|
}}
|
||||||
fields.register(cmd)
|
fields.register(cmd)
|
||||||
cmd.Flags().BoolVar(&byName, "by-name", false, "Match a numeric argument as a milestone title rather than an ID")
|
cmd.Flags().BoolVar(&byName, "by-name", false, "Match a numeric argument as a milestone title rather than an ID")
|
||||||
cmd.ValidArgsFunction = a.completeMilestoneArgs(false)
|
cmd.ValidArgsFunction = firstArg(a.completeMilestones())
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -367,7 +367,7 @@ $ tea milestone delete 7 --yes`, Annotations: map[string]string{"tea.confirm": "
|
|||||||
return a.jsonResult(cmd, item)
|
return a.jsonResult(cmd, item)
|
||||||
}}
|
}}
|
||||||
cmd.Flags().BoolVar(&byName, "by-name", false, "Match a numeric argument as a milestone title rather than an ID")
|
cmd.Flags().BoolVar(&byName, "by-name", false, "Match a numeric argument as a milestone title rather than an ID")
|
||||||
cmd.ValidArgsFunction = a.completeMilestoneArgs(false)
|
cmd.ValidArgsFunction = firstArg(a.completeMilestones())
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -378,15 +378,3 @@ func findMilestone(cmd *cobra.Command, s services.Milestones, raw string, byName
|
|||||||
}
|
}
|
||||||
return s.FindOne(cmd.Context(), raw, byName)
|
return s.FindOne(cmd.Context(), raw, byName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// completeMilestoneArgs completes milestone titles for the first argument, or for every argument
|
|
||||||
// when variadic.
|
|
||||||
func (a *application) completeMilestoneArgs(variadic bool) cobra.CompletionFunc {
|
|
||||||
complete := a.completeMilestones()
|
|
||||||
return func(cmd *cobra.Command, args []string, toComplete string) ([]cobra.Completion, cobra.ShellCompDirective) {
|
|
||||||
if len(args) > 0 && !variadic {
|
|
||||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
|
||||||
}
|
|
||||||
return complete(cmd, args, toComplete)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -40,7 +40,7 @@ $ tea milestone issue list v1.0 --state all --kind issues`, Annotations: map[str
|
|||||||
enumFlag(list, &opts.State, "state", "s", "open", "Filter by state", "open", "closed", "all")
|
enumFlag(list, &opts.State, "state", "s", "open", "Filter by state", "open", "closed", "all")
|
||||||
enumFlag(list, &opts.Kind, "kind", "", "all", "List issues, pull requests or both", "issues", "pulls", "all")
|
enumFlag(list, &opts.Kind, "kind", "", "all", "List issues, pull requests or both", "issues", "pulls", "all")
|
||||||
list.Flags().BoolVar(&byName, "by-name", false, "Match a numeric argument as a milestone title rather than an ID")
|
list.Flags().BoolVar(&byName, "by-name", false, "Match a numeric argument as a milestone title rather than an ID")
|
||||||
list.ValidArgsFunction = a.completeMilestoneArgs(false)
|
list.ValidArgsFunction = firstArg(a.completeMilestones())
|
||||||
group.AddCommand(list)
|
group.AddCommand(list)
|
||||||
for _, verb := range []string{"add", "remove"} {
|
for _, verb := range []string{"add", "remove"} {
|
||||||
var byName bool
|
var byName bool
|
||||||
|
|||||||
@@ -54,6 +54,6 @@ $ tea milestone %[1]s v1.0 v1.1`, verb), Annotations: map[string]string{"tea.arg
|
|||||||
return errors.Join(append(failures, writeBatchJSON(a, cmd, len(selected), results))...)
|
return errors.Join(append(failures, writeBatchJSON(a, cmd, len(selected), results))...)
|
||||||
}}
|
}}
|
||||||
cmd.Flags().BoolVar(&byName, "by-name", false, "Match numeric arguments as milestone titles rather than IDs")
|
cmd.Flags().BoolVar(&byName, "by-name", false, "Match numeric arguments as milestone titles rather than IDs")
|
||||||
cmd.ValidArgsFunction = a.completeMilestoneArgs(true)
|
cmd.ValidArgsFunction = a.completeMilestones()
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
@@ -154,7 +154,7 @@ $ tea release upload v1.0.0 dist/tea-linux --clobber`,
|
|||||||
}
|
}
|
||||||
command.Flags().StringVar(&name, "name", "", "Asset name (default: the file's name)")
|
command.Flags().StringVar(&name, "name", "", "Asset name (default: the file's name)")
|
||||||
command.Flags().BoolVar(&clobber, "clobber", false, "Replace assets with the same name")
|
command.Flags().BoolVar(&clobber, "clobber", false, "Replace assets with the same name")
|
||||||
command.ValidArgsFunction = a.completeReleases()
|
command.ValidArgsFunction = pathArgs(1, true, completeFiles, a.completeReleases())
|
||||||
return command
|
return command
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -307,7 +307,7 @@ $ tea release create v1.1.0-rc1 --target release/1.1 --draft --prerelease --titl
|
|||||||
command.Flags().StringVar(&fields.tag, "tag", "", "Release tag")
|
command.Flags().StringVar(&fields.tag, "tag", "", "Release tag")
|
||||||
_ = command.Flags().MarkHidden("tag")
|
_ = command.Flags().MarkHidden("tag")
|
||||||
command.Flags().StringSliceVar(&assets, "asset", nil, "File to upload as an asset (repeatable)")
|
command.Flags().StringSliceVar(&assets, "asset", nil, "File to upload as an asset (repeatable)")
|
||||||
command.ValidArgsFunction = a.completeTags()
|
command.ValidArgsFunction = pathArgs(1, true, completeFiles, a.completeTags())
|
||||||
return command
|
return command
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -284,7 +284,7 @@ $ tea repo clone alice/project -- --branch develop --recurse-submodules`,
|
|||||||
command.Flags().IntVarP(&opts.depth, "depth", "d", 0, "Number of commits to fetch (0: full history)")
|
command.Flags().IntVarP(&opts.depth, "depth", "d", 0, "Number of commits to fetch (0: full history)")
|
||||||
command.Flags().StringVarP(&opts.upstream, "upstream-remote-name", "u", "upstream", "Remote name for the parent of a fork")
|
command.Flags().StringVarP(&opts.upstream, "upstream-remote-name", "u", "upstream", "Remote name for the parent of a fork")
|
||||||
command.Flags().BoolVar(&noUpstream, "no-upstream", false, "Do not add a remote for the parent of a fork")
|
command.Flags().BoolVar(&noUpstream, "no-upstream", false, "Do not add a remote for the parent of a fork")
|
||||||
command.ValidArgsFunction = a.completeRepos()
|
command.ValidArgsFunction = pathArgs(1, false, completeDirectories, a.completeRepos())
|
||||||
return command
|
return command
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ func sshKeySource(source string) string {
|
|||||||
func (a *application) sshKeyCreateCommand() *cobra.Command {
|
func (a *application) sshKeyCreateCommand() *cobra.Command {
|
||||||
var title string
|
var title string
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "create [<file>]", Aliases: []string{"add"}, Short: "Add an SSH public key from a file or stdin", Args: usageArgs(cobra.MaximumNArgs(1)),
|
Use: "create [<file>]", Aliases: []string{"add"}, Short: "Add an SSH public key from a file or stdin", Args: usageArgs(cobra.MaximumNArgs(1)), ValidArgsFunction: completeFiles,
|
||||||
Long: `Add an SSH public key to your account. Without a file, or with -, the key is read from stdin.
|
Long: `Add an SSH public key to your account. Without a file, or with -, the key is read from stdin.
|
||||||
|
|
||||||
The title defaults to the key's comment, such as alice@laptop, or else to this computer's name.`,
|
The title defaults to the key's comment, such as alice@laptop, or else to this computer's name.`,
|
||||||
|
|||||||
@@ -339,12 +339,7 @@ to set single units instead, or to override some of them.`,
|
|||||||
$ tea team create acme/reviewers --unit repo.code=read,repo.pulls=write
|
$ tea team create acme/reviewers --unit repo.code=read,repo.pulls=write
|
||||||
# give the team access to every repository of the organization
|
# give the team access to every repository of the organization
|
||||||
$ tea team create acme ops --permission admin --all-repositories`,
|
$ tea team create acme ops --permission admin --all-repositories`,
|
||||||
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]cobra.Completion, cobra.ShellCompDirective) {
|
ValidArgsFunction: firstArg(a.completeOrgs()),
|
||||||
if len(args) > 0 {
|
|
||||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
|
||||||
}
|
|
||||||
return a.completeOrgs()(cmd, args, toComplete)
|
|
||||||
},
|
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
org, name, scoped := strings.Cut(args[0], "/")
|
org, name, scoped := strings.Cut(args[0], "/")
|
||||||
names := 0
|
names := 0
|
||||||
|
|||||||
@@ -161,7 +161,7 @@ func (a *application) timeCreateCommand() *cobra.Command {
|
|||||||
return &cobra.Command{Use: "create {<number> | <url>} <duration>", Aliases: []string{"add", "log"}, Short: "Log time spent on an issue", Long: `Log time spent on an issue or pull request. The duration uses h, m and s units, such as
|
return &cobra.Command{Use: "create {<number> | <url>} <duration>", Aliases: []string{"add", "log"}, Short: "Log time spent on an issue", Long: `Log time spent on an issue or pull request. The duration uses h, m and s units, such as
|
||||||
1h25m or "1h 25m".`, Example: `$ tea time create 12 1h25m
|
1h25m or "1h 25m".`, Example: `$ tea time create 12 1h25m
|
||||||
$ tea time add 12 "1h 30m"
|
$ tea time add 12 "1h 30m"
|
||||||
$ tea time log https://gitea.com/OWNER/REPO/issues/12 45m`, Annotations: map[string]string{"tea.arguments": issueArguments}, Args: argsExact(2), ValidArgsFunction: a.completeIssueArgs("open", false), RunE: func(cmd *cobra.Command, args []string) error {
|
$ tea time log https://gitea.com/OWNER/REPO/issues/12 45m`, Annotations: map[string]string{"tea.arguments": issueArguments}, Args: argsExact(2), ValidArgsFunction: firstArg(a.completeIssues("open")), RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
seconds, err := parseSpent(args[1])
|
seconds, err := parseSpent(args[1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -181,7 +181,7 @@ $ tea time log https://gitea.com/OWNER/REPO/issues/12 45m`, Annotations: map[str
|
|||||||
|
|
||||||
func (a *application) timeDeleteCommand() *cobra.Command {
|
func (a *application) timeDeleteCommand() *cobra.Command {
|
||||||
return &cobra.Command{Use: "delete {<number> | <url>} <time-id>", Short: "Delete a time record", Example: `# Find the record with tea time list --issue 12
|
return &cobra.Command{Use: "delete {<number> | <url>} <time-id>", Short: "Delete a time record", Example: `# Find the record with tea time list --issue 12
|
||||||
$ tea time delete 12 8`, Annotations: map[string]string{"tea.text": "time delete does not return a resource", "tea.confirm": "true", "tea.arguments": issueArguments}, Args: argsExact(2), ValidArgsFunction: a.completeIssueArgs("all", false), RunE: func(cmd *cobra.Command, args []string) error {
|
$ tea time delete 12 8`, Annotations: map[string]string{"tea.text": "time delete does not return a resource", "tea.confirm": "true", "tea.arguments": issueArguments}, Args: argsExact(2), ValidArgsFunction: firstArg(a.completeIssues("all")), RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
id, err := number(args[1])
|
id, err := number(args[1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -201,7 +201,7 @@ $ tea time delete 12 8`, Annotations: map[string]string{"tea.text": "time delete
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *application) timeResetCommand() *cobra.Command {
|
func (a *application) timeResetCommand() *cobra.Command {
|
||||||
return &cobra.Command{Use: "reset {<number> | <url>}", Short: "Delete all time logged on an issue", Example: "$ tea time reset 12 --yes", Annotations: map[string]string{"tea.text": "time reset does not return a resource", "tea.confirm": "true", "tea.arguments": issueArguments}, Args: argsExact(1), ValidArgsFunction: a.completeIssueArgs("all", false), RunE: func(cmd *cobra.Command, args []string) error {
|
return &cobra.Command{Use: "reset {<number> | <url>}", Short: "Delete all time logged on an issue", Example: "$ tea time reset 12 --yes", Annotations: map[string]string{"tea.text": "time reset does not return a resource", "tea.confirm": "true", "tea.arguments": issueArguments}, Args: argsExact(1), ValidArgsFunction: firstArg(a.completeIssues("all")), RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
target, n, err := a.resolveRef(cmd, args[0], issueRef)
|
target, n, err := a.resolveRef(cmd, args[0], issueRef)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
Reference in new issue
Block a user