Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 44 additions & 50 deletions cmd/src/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,18 @@ package main
import (
"context"
"encoding/json"
"flag"
"fmt"
"io"
"os"
"strings"

"github.com/sourcegraph/src-cli/internal/api"
"github.com/sourcegraph/src-cli/internal/cmderrors"

"github.com/mattn/go-isatty"
"github.com/sourcegraph/src-cli/internal/clicompat"
"github.com/sourcegraph/src-cli/internal/cmderrors"
"github.com/urfave/cli/v3"
)

func init() {
usage := `
const apiExamples = `
Exit codes:

0: Success
Expand All @@ -43,28 +41,26 @@ Examples:
$ src api -get-curl -query='query { currentUser { username } }'
`

flagSet := flag.NewFlagSet("api", flag.ExitOnError)
usageFunc := func() {
fmt.Fprintf(flag.CommandLine.Output(), "Usage of 'src %s':\n", flagSet.Name())
flagSet.PrintDefaults()
fmt.Println(usage)
}
var (
queryFlag = flagSet.String("query", "", "GraphQL query to execute, e.g. 'query { currentUser { username } }' (stdin otherwise)")
varsFlag = flagSet.String("vars", "", `GraphQL query variables to include as JSON string, e.g. '{"var": "val", "var2": "val2"}'`)
apiFlags = api.NewFlags(flagSet)
)

handler := func(args []string) error {
err := flagSet.Parse(args)
if err != nil {
return err
}

// Build the GraphQL request.
query := *queryFlag
var apiCommand = clicompat.Wrap(&cli.Command{
Name: "api",
Usage: "interacts with the Sourcegraph GraphQL API",
UsageText: "src api [options] [variable=value ...]",
Description: apiExamples,
HideVersion: true,
DisableSliceFlagSeparator: true,
Flags: clicompat.WithAPIFlags(
&cli.StringFlag{
Name: "query",
Usage: "GraphQL query to execute, e.g. 'query { currentUser { username } }' (stdin otherwise)",
},
&cli.StringFlag{
Name: "vars",
Usage: `GraphQL query variables to include as JSON string, e.g. '{"var": "val", "var2": "val2"}'`,
},
),
Action: func(ctx context.Context, cmd *cli.Command) error {
query := cmd.String("query")
if query == "" {
// Read query from stdin instead.
if isatty.IsTerminal(os.Stdin.Fd()) {
return cmderrors.Usage("expected query to be piped into 'src api' or -query flag to be specified")
}
Expand All @@ -75,42 +71,40 @@ Examples:
query = string(data)
}

// Determine which variables to use in the request.
vars := map[string]any{}
if *varsFlag != "" {
if err := json.Unmarshal([]byte(*varsFlag), &vars); err != nil {
if raw := cmd.String("vars"); raw != "" {
if err := json.Unmarshal([]byte(raw), &vars); err != nil {
return err
}
}
for _, arg := range flagSet.Args() {
idx := strings.Index(arg, "=")
if idx == -1 {
for _, arg := range cmd.Args().Slice() {
key, value, ok := strings.Cut(arg, "=")
if !ok {
return cmderrors.Usagef("parsing argument %q expected 'variable=value' syntax (missing equals)", arg)
}
key := arg[:idx]
value := arg[idx+1:]
vars[key] = value
}

// Perform the request.
var result any
if ok, err := cfg.apiClient(apiFlags, flagSet.Output()).NewRequest(query, vars).DoRaw(context.Background(), &result); err != nil || !ok {
var result struct {
Data any `json:"data,omitempty"`
Errors []json.RawMessage `json:"errors,omitempty"`
}
client := cfg.apiClient(clicompat.APIFlagsFromCmd(cmd), cmd.Writer)
if ok, err := client.NewRequest(query, vars).DoRaw(ctx, &result); err != nil || !ok {
return err
}

// Print the formatted JSON.
f, err := marshalIndent(result)
formatted, err := marshalIndent(result)
if err != nil {
return err
}
_, err = fmt.Fprintln(cmd.Writer, string(formatted))
if err != nil {
return err
}
fmt.Println(string(f))
if len(result.Errors) > 0 {
return cmderrors.ExitCode(cmderrors.GraphqlErrorsExitCode, nil)
}
return nil
}

// Register the command.
commands = append(commands, &command{
flagSet: flagSet,
handler: handler,
usageFunc: usageFunc,
})
}
},
})
7 changes: 7 additions & 0 deletions cmd/src/run_migration_compat.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (

var migratedCommands = map[string]*cli.Command{
"abc": abcCommand,
"api": apiCommand,
"auth": authCommand,
"login": loginCommand,
"version": versionCommand,
Expand Down Expand Up @@ -68,6 +69,12 @@ func runMigrated() (int, error) {
if errors.HasType[*cmderrors.UsageError](err) {
return 2, nil
}
if e, ok := err.(*cmderrors.ExitCodeError); ok {
if e.HasError() {
return e.Code(), e
}
return e.Code(), nil
}
var exitErr cli.ExitCoder
if errors.AsInterface(err, &exitErr) {
return exitErr.ExitCode(), err
Expand Down
Loading