mirror of
https://github.com/sourcegraph/sourcegraph.git
synced 2026-02-06 11:01:44 +00:00
sg: improve positional completions (#58569)
Improves positional completions added for `sg msp` in #58538 by checking for partial flag input (`-` and `--`), which now complete flags correctly, and also improving the way we build positional argument completions with a more robust helper, `completions.CompletePositionalArgs`.
This commit is contained in:
parent
9d8ed353aa
commit
b28b962fba
4
deps.bzl
4
deps.bzl
@ -1418,8 +1418,8 @@ def go_dependencies():
|
||||
name = "com_github_cpuguy83_go_md2man_v2",
|
||||
build_file_proto_mode = "disable_global",
|
||||
importpath = "github.com/cpuguy83/go-md2man/v2",
|
||||
sum = "h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=",
|
||||
version = "v2.0.2",
|
||||
sum = "h1:qMCsGGgs+MAzDFyp9LpAe1Lqy/fY/qCovCm0qnXZOBM=",
|
||||
version = "v2.0.3",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_creack_pty",
|
||||
|
||||
@ -318,7 +318,7 @@ sg ci build docker-images-patch-notest prometheus
|
||||
# Publish all images without testing
|
||||
sg ci build docker-images-candidates-notest
|
||||
`,
|
||||
BashComplete: completions.CompleteOptions(getAllowedBuildTypeArgs),
|
||||
BashComplete: completions.CompleteArgs(getAllowedBuildTypeArgs),
|
||||
Flags: []cli.Flag{
|
||||
&ciPipelineFlag,
|
||||
&cli.StringFlag{
|
||||
|
||||
@ -73,25 +73,21 @@ func ServicesAndEnvironmentsCompletion() cli.BashCompleteFunc {
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return func(c *cli.Context) {
|
||||
switch c.Args().Len() {
|
||||
case 0: // service not yet provided, try to complete service
|
||||
completions.CompleteOptions(func() (options []string) {
|
||||
return completions.CompletePositionalArgs(
|
||||
func(args cli.Args) (options []string) {
|
||||
services, _ := listServicesFromRoot(repoRoot)
|
||||
return services
|
||||
},
|
||||
func(args cli.Args) (options []string) {
|
||||
svc, err := spec.Open(filepath.Join(repoRoot, ServiceYAMLPath(args.First())))
|
||||
if err != nil {
|
||||
// try to complete services as a fallback
|
||||
services, _ := listServicesFromRoot(repoRoot)
|
||||
return services
|
||||
})(c)
|
||||
case 1: // service already provided, try to complete environment
|
||||
completions.CompleteOptionsOnly(func() (options []string) {
|
||||
svc, err := spec.Open(filepath.Join(repoRoot, ServiceYAMLPath(c.Args().First())))
|
||||
if err != nil {
|
||||
// try to complete services as a fallback
|
||||
services, _ := listServicesFromRoot(repoRoot)
|
||||
return services
|
||||
}
|
||||
return svc.ListEnvironmentIDs()
|
||||
})(c)
|
||||
}
|
||||
}
|
||||
}
|
||||
return svc.ListEnvironmentIDs()
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func ServiceYAMLPath(serviceID string) string {
|
||||
|
||||
@ -48,9 +48,9 @@ func init() {
|
||||
// All 'sg msp ...' subcommands
|
||||
Command.Subcommands = []*cli.Command{
|
||||
{
|
||||
Name: "init",
|
||||
ArgsUsage: "<service ID>",
|
||||
Description: "Initialize a template Managed Services Platform service spec",
|
||||
Name: "init",
|
||||
ArgsUsage: "<service ID>",
|
||||
Usage: "Initialize a template Managed Services Platform service spec",
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "kind",
|
||||
@ -186,11 +186,11 @@ func init() {
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "generate",
|
||||
Aliases: []string{"gen"},
|
||||
ArgsUsage: "<service ID>",
|
||||
Description: "Generate Terraform assets for a Managed Services Platform service spec.",
|
||||
Usage: `Optionally use '-all' to sync all environments for a service.
|
||||
Name: "generate",
|
||||
Aliases: []string{"gen"},
|
||||
ArgsUsage: "<service ID>",
|
||||
Usage: "Generate Terraform assets for a Managed Services Platform service spec.",
|
||||
Description: `Optionally use '-all' to sync all environments for a service.
|
||||
|
||||
Supports completions on services and environments.`,
|
||||
UsageText: `
|
||||
@ -267,15 +267,15 @@ sg msp generate -all <service>
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "terraform-cloud",
|
||||
Aliases: []string{"tfc"},
|
||||
Description: "Manage Terraform Cloud workspaces for a service",
|
||||
Before: msprepo.UseManagedServicesRepo,
|
||||
Name: "terraform-cloud",
|
||||
Aliases: []string{"tfc"},
|
||||
Usage: "Manage Terraform Cloud workspaces for a service",
|
||||
Before: msprepo.UseManagedServicesRepo,
|
||||
Subcommands: []*cli.Command{
|
||||
{
|
||||
Name: "sync",
|
||||
Description: "Create or update all required Terraform Cloud workspaces for an environment",
|
||||
Usage: `Optionally use '-all' to sync all environments for a service.
|
||||
Name: "sync",
|
||||
Usage: "Create or update all required Terraform Cloud workspaces for an environment",
|
||||
Description: `Optionally use '-all' to sync all environments for a service.
|
||||
|
||||
Supports completions on services and environments.`,
|
||||
ArgsUsage: "<service ID> [environment ID]",
|
||||
@ -366,8 +366,8 @@ Supports completions on services and environments.`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "schema",
|
||||
Description: "Generate JSON schema definition for service specification",
|
||||
Name: "schema",
|
||||
Usage: "Generate JSON schema definition for service specification",
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "output",
|
||||
|
||||
@ -114,7 +114,7 @@ func (gt generateTargets) Commands() (cmds []*cli.Command) {
|
||||
for _, c := range gt {
|
||||
var complete cli.BashCompleteFunc
|
||||
if c.Completer != nil {
|
||||
complete = completions.CompleteOptions(c.Completer)
|
||||
complete = completions.CompleteArgs(c.Completer)
|
||||
}
|
||||
cmds = append(cmds, &cli.Command{
|
||||
Name: c.Name,
|
||||
|
||||
@ -174,7 +174,7 @@ func (lt lintTargets) Commands() (cmds []*cli.Command) {
|
||||
return runner.Check(cmd.Context, repoState)
|
||||
},
|
||||
// Completions to chain multiple commands
|
||||
BashComplete: completions.CompleteOptions(func() (options []string) {
|
||||
BashComplete: completions.CompleteArgs(func() (options []string) {
|
||||
for _, c := range lt {
|
||||
options = append(options, c.Name)
|
||||
}
|
||||
|
||||
@ -45,7 +45,7 @@ sg live -n 50 s2
|
||||
Usage: "Number of commits to check for live version",
|
||||
},
|
||||
},
|
||||
BashComplete: completions.CompleteOptions(func() (options []string) {
|
||||
BashComplete: completions.CompleteArgs(func() (options []string) {
|
||||
return append(environmentNames(), `https\://...`)
|
||||
}),
|
||||
}
|
||||
|
||||
@ -67,7 +67,7 @@ sg run -describe jaeger
|
||||
},
|
||||
},
|
||||
Action: runExec,
|
||||
BashComplete: completions.CompleteOptions(func() (options []string) {
|
||||
BashComplete: completions.CompleteArgs(func() (options []string) {
|
||||
config, _ := getConfig()
|
||||
if config == nil {
|
||||
return
|
||||
|
||||
@ -35,7 +35,7 @@ sg secret reset buildkite
|
||||
ArgsUsage: "<...key>",
|
||||
Usage: "Remove a specific secret from secrets file",
|
||||
Action: resetSecretExec,
|
||||
BashComplete: completions.CompleteOptions(bashCompleteSecrets),
|
||||
BashComplete: completions.CompleteArgs(bashCompleteSecrets),
|
||||
},
|
||||
{
|
||||
Name: "list",
|
||||
|
||||
@ -132,7 +132,7 @@ sg start -describe single-program
|
||||
Destination: &onlyServices,
|
||||
},
|
||||
},
|
||||
BashComplete: completions.CompleteOptions(func() (options []string) {
|
||||
BashComplete: completions.CompleteArgs(func() (options []string) {
|
||||
config, _ := getConfig()
|
||||
if config == nil {
|
||||
return
|
||||
|
||||
@ -40,7 +40,7 @@ sg test -help
|
||||
sg test backend-integration -run TestSearch
|
||||
`,
|
||||
Category: category.Dev,
|
||||
BashComplete: completions.CompleteOptions(func() (options []string) {
|
||||
BashComplete: completions.CompleteArgs(func() (options []string) {
|
||||
config, _ := getConfig()
|
||||
if config == nil {
|
||||
return
|
||||
|
||||
2
go.mod
2
go.mod
@ -437,7 +437,7 @@ require (
|
||||
github.com/cockroachdb/redact v1.1.5
|
||||
github.com/containerd/typeurl v1.0.2 // indirect
|
||||
github.com/coreos/go-iptables v0.6.0
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect
|
||||
github.com/dave/jennifer v1.6.1 // indirect
|
||||
github.com/di-wu/xsd-datetime v1.0.0
|
||||
github.com/djherbis/buffer v1.2.0 // indirect
|
||||
|
||||
3
go.sum
3
go.sum
@ -395,8 +395,9 @@ github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfc
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.3 h1:qMCsGGgs+MAzDFyp9LpAe1Lqy/fY/qCovCm0qnXZOBM=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
|
||||
|
||||
@ -6,26 +6,63 @@ import (
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
// CompleteOptions provides autocompletions based on the options returned by
|
||||
// generateOptions. generateOptions must not write to output, or reference any resources
|
||||
// that are initialized elsewhere.
|
||||
func CompleteOptions(generateOptions func() (options []string)) cli.BashCompleteFunc {
|
||||
return func(cmd *cli.Context) {
|
||||
for _, opt := range generateOptions() {
|
||||
fmt.Fprintf(cmd.App.Writer, "%s\n", opt)
|
||||
}
|
||||
// Also render default completions to support flags
|
||||
cli.DefaultCompleteWithFlags(cmd.Command)(cmd)
|
||||
// defaultCompletions renders the default completions for a command.
|
||||
func defaultCompletions() cli.BashCompleteFunc {
|
||||
return func(c *cli.Context) { cli.DefaultCompleteWithFlags(c.Command)(c) }
|
||||
}
|
||||
|
||||
// CompleteArgs provides autocompletions based on the options returned by
|
||||
// generateOptions. generateOptions is provided for every argument.
|
||||
//
|
||||
// generateOptions must not write to output, or reference any
|
||||
// resources that are initialized elsewhere.
|
||||
func CompleteArgs(generateOptions func() (options []string)) cli.BashCompleteFunc {
|
||||
return func(c *cli.Context) {
|
||||
CompletePositionalArgs(func(_ cli.Args) (options []string) {
|
||||
return generateOptions()
|
||||
})(c)
|
||||
}
|
||||
}
|
||||
|
||||
// CompleteOptionsOnly is like CompleteOptions, but does not render default
|
||||
// completions - useful for generating completions for arguments beyond the first,
|
||||
// where flag help is no longer needed.
|
||||
func CompleteOptionsOnly(generateOptions func() (options []string)) cli.BashCompleteFunc {
|
||||
return func(cmd *cli.Context) {
|
||||
for _, opt := range generateOptions() {
|
||||
fmt.Fprintf(cmd.App.Writer, "%s\n", opt)
|
||||
// CompletePositionalArgs provides autocompletions for multiple positional
|
||||
// arguments based on the options returned by the corresponding options generator.
|
||||
// If there are more arguments than generators, no completion is provided.
|
||||
//
|
||||
// Each generator must not write to output, or reference any resources that are
|
||||
// initialized elsewhere.
|
||||
func CompletePositionalArgs(generators ...func(args cli.Args) (options []string)) cli.BashCompleteFunc {
|
||||
return func(c *cli.Context) {
|
||||
// Let default handler deal with flag completions if the latest argument
|
||||
// looks like the start of a flag
|
||||
if c.NArg() > 0 {
|
||||
if f := c.Args().Get(c.NArg() - 1); f == "-" || f == "--" {
|
||||
defaultCompletions()(c)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// More arguments than positional options generators, we have no more
|
||||
// completions to offer
|
||||
if len(generators) <= c.NArg() {
|
||||
return
|
||||
}
|
||||
|
||||
// Generate the options for this posarg
|
||||
opts := generators[c.NArg()](c.Args())
|
||||
|
||||
// If there are no options, render the previous options if we can, as
|
||||
// user may be typing the previous argument
|
||||
if len(opts) == 0 && c.NArg() >= 1 {
|
||||
opts = generators[c.NArg()-1](c.Args())
|
||||
}
|
||||
|
||||
// Render the options
|
||||
for _, opt := range opts {
|
||||
fmt.Fprintf(c.App.Writer, "%s\n", opt)
|
||||
}
|
||||
// Also render default completions if there are no args yet
|
||||
if c.Args().Len() == 0 {
|
||||
defaultCompletions()(c)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -107,7 +107,7 @@ func Generate(cmdRoot string, sgRoot string) *cli.Command {
|
||||
Usage: "If non-empty, indicates whether or not to generate multi-instance assets with the provided labels to group on. The standard per-instance monitoring assets will NOT be generated.",
|
||||
},
|
||||
},
|
||||
BashComplete: completions.CompleteOptions(func() (options []string) {
|
||||
BashComplete: completions.CompleteArgs(func() (options []string) {
|
||||
return definitions.Default().Names()
|
||||
}),
|
||||
Action: func(c *cli.Context) error {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user