diff --git a/cmd/src/extsvc.go b/cmd/src/extsvc.go index e761dd1714..a716aebc00 100644 --- a/cmd/src/extsvc.go +++ b/cmd/src/extsvc.go @@ -23,6 +23,7 @@ The commands are: list lists the external services on the Sourcegraph instance edit edits external services on the Sourcegraph instance + add add an external service on the Sourcegraph instance Use "src extsvc [command] -h" for more information about a command. ` @@ -52,6 +53,8 @@ type externalService struct { CreatedAt, UpdatedAt string } +var errServiceNotFound = errors.New("no such external service") + func lookupExternalService(ctx context.Context, client api.Client, byID, byName string) (*externalService, error) { var result struct { ExternalServices struct { @@ -72,5 +75,5 @@ func lookupExternalService(ctx context.Context, client api.Client, byID, byName return svc, nil } } - return nil, errors.New("no such external service") + return nil, errServiceNotFound } diff --git a/cmd/src/extsvc_create.go b/cmd/src/extsvc_create.go new file mode 100644 index 0000000000..d79ac48540 --- /dev/null +++ b/cmd/src/extsvc_create.go @@ -0,0 +1,95 @@ +package main + +import ( + "context" + "flag" + "fmt" + "io" + "os" + "strings" + + "github.com/mattn/go-isatty" + "github.com/sourcegraph/sourcegraph/lib/errors" + "github.com/sourcegraph/src-cli/internal/api" +) + +func init() { + usage := ` + Examples: + + create an external service configuration on the Sourcegraph instance: + + $ cat new-config.json | src extsvc create + $ src extsvc create -name 'My GitHub connection' new-config.json + ` + + flagSet := flag.NewFlagSet("create", flag.ExitOnError) + usageFunc := func() { + fmt.Fprintf(flag.CommandLine.Output(), "Usage of 'src extsvc %s':\n", flagSet.Name()) + flagSet.PrintDefaults() + fmt.Println(usage) + } + var ( + nameFlag = flagSet.String("name", "", "exact name of the external service to create") + kindFlag = flagSet.String("kind", "", "kind of the external service to create") + apiFlags = api.NewFlags(flagSet) + ) + + handler := func(args []string) (err error) { + ctx := context.Background() + if err := flagSet.Parse(args); err != nil { + return err + } + if *nameFlag == "" { + return errors.New("-name must be provided") + } + + var createJSON []byte + if len(flagSet.Args()) == 1 { + createJSON, err = os.ReadFile(flagSet.Arg(0)) + if err != nil { + return err + } + } + if !isatty.IsTerminal(os.Stdin.Fd()) { + // stdin is a pipe not a terminal + createJSON, err = io.ReadAll(os.Stdin) + if err != nil { + return err + } + } + + createExternalServiceInput := map[string]interface{}{ + "kind": strings.ToUpper(*kindFlag), + "displayName": *nameFlag, + "config": string(createJSON), + } + queryVars := map[string]interface{}{ + "input": createExternalServiceInput, + } + var result struct{} // TODO: future: allow formatting resulting external service + + client := cfg.apiClient(apiFlags, flagSet.Output()) + if ok, err := client.NewRequest(externalServicesCreateMutation, queryVars).Do(ctx, &result); err != nil { + return err + } else if ok { + fmt.Println("External service created:", *nameFlag) + } + return nil + } + + // Register the command. + extsvcCommands = append(extsvcCommands, &command{ + flagSet: flagSet, + handler: handler, + usageFunc: usageFunc, + }) +} + +const externalServicesCreateMutation = ` + mutation AddExternalService($input: AddExternalServiceInput!) { + addExternalService(input: $input) { + id + warning + } + }`