diff --git a/cmd/src/repos.go b/cmd/src/repos.go index b5c2020344..d58fe0abe0 100644 --- a/cmd/src/repos.go +++ b/cmd/src/repos.go @@ -23,6 +23,9 @@ The commands are: get gets a repository list lists repositories delete deletes repositories + add-kvp adds a key-value pair to a repository + update-kvp updates a key-value pair on a repository + delete-kvp deletes a key-value pair from a repository Use "src repos [command] -h" for more information about a command. ` @@ -63,6 +66,10 @@ fragment RepositoryFields on Repository { displayName } viewerCanAdminister + keyValuePairs { + key + value + } } ` @@ -77,6 +84,12 @@ type Repository struct { ExternalRepository ExternalRepository `json:"externalRepository"` DefaultBranch GitRef `json:"defaultBranch"` ViewerCanAdminister bool `json:"viewerCanAdminister"` + KeyValuePairs []KeyValuePair `json:"keyValuePairs"` +} + +type KeyValuePair struct { + Key string `json:"key"` + Value *string `json:"value"` } type ExternalRepository struct { diff --git a/cmd/src/repos_add_kvp.go b/cmd/src/repos_add_kvp.go new file mode 100644 index 0000000000..d7155c54c1 --- /dev/null +++ b/cmd/src/repos_add_kvp.go @@ -0,0 +1,99 @@ +package main + +import ( + "context" + "flag" + "fmt" + + "github.com/sourcegraph/sourcegraph/lib/errors" + "github.com/sourcegraph/src-cli/internal/api" +) + +func init() { + usage := ` +Examples: + + Add a key-value pair to a repository: + + $ src repos add-kvp -repo=repoID -key=mykey -value=myvalue + + Omitting -value will create a tag (a key with a null value). +` + + flagSet := flag.NewFlagSet("add-kvp", flag.ExitOnError) + usageFunc := func() { + fmt.Fprintf(flag.CommandLine.Output(), "Usage of 'src repos %s':\n", flagSet.Name()) + flagSet.PrintDefaults() + fmt.Println(usage) + } + var ( + repoFlag = flagSet.String("repo", "", `The ID of the repo to add the key-value pair to (required)`) + keyFlag = flagSet.String("key", "", `The name of the key to add (required)`) + valueFlag = flagSet.String("value", "", `The value associated with the key. Defaults to null.`) + apiFlags = api.NewFlags(flagSet) + ) + + handler := func(args []string) error { + if err := flagSet.Parse(args); err != nil { + return err + } + if *repoFlag == "" { + return errors.New("error: repo is required") + } + + keyFlag = nil + valueFlag = nil + flagSet.Visit(func(f *flag.Flag) { + if f.Name == "key" { + key := f.Value.String() + keyFlag = &key + } + + if f.Name == "value" { + value := f.Value.String() + valueFlag = &value + } + }) + if keyFlag == nil { + return errors.New("error: key is required") + } + + client := cfg.apiClient(apiFlags, flagSet.Output()) + + query := `mutation addKVP( + $repo: ID!, + $key: String!, + $value: String, +) { + addRepoKeyValuePair( + repo: $repo, + key: $key, + value: $value, + ) { + alwaysNil + } +}` + + if ok, err := client.NewRequest(query, map[string]interface{}{ + "repo": *repoFlag, + "key": *keyFlag, + "value": valueFlag, + }).Do(context.Background(), nil); err != nil || !ok { + return err + } + + if valueFlag != nil { + fmt.Printf("Key-value pair '%s:%v' created.\n", *keyFlag, *valueFlag) + } else { + fmt.Printf("Key-value pair '%s:' created.\n", *keyFlag) + } + return nil + } + + // Register the command. + reposCommands = append(reposCommands, &command{ + flagSet: flagSet, + handler: handler, + usageFunc: usageFunc, + }) +} diff --git a/cmd/src/repos_delete_kvp.go b/cmd/src/repos_delete_kvp.go new file mode 100644 index 0000000000..4b9612a3a9 --- /dev/null +++ b/cmd/src/repos_delete_kvp.go @@ -0,0 +1,84 @@ +package main + +import ( + "context" + "flag" + "fmt" + + "github.com/sourcegraph/sourcegraph/lib/errors" + "github.com/sourcegraph/src-cli/internal/api" +) + +func init() { + usage := ` +Examples: + + Delete a key-value pair from a repository: + + $ src repos delete-kvp -repo=repoID -key=mykey + +` + + flagSet := flag.NewFlagSet("delete-kvp", flag.ExitOnError) + usageFunc := func() { + fmt.Fprintf(flag.CommandLine.Output(), "Usage of 'src repos %s':\n", flagSet.Name()) + flagSet.PrintDefaults() + fmt.Println(usage) + } + var ( + repoFlag = flagSet.String("repo", "", `The ID of the repo with the key-value pair to be deleted (required)`) + keyFlag = flagSet.String("key", "", `The name of the key to be deleted (required)`) + apiFlags = api.NewFlags(flagSet) + ) + + handler := func(args []string) error { + if err := flagSet.Parse(args); err != nil { + return err + } + if *repoFlag == "" { + return errors.New("error: repo is required") + } + + keyFlag = nil + flagSet.Visit(func(f *flag.Flag) { + if f.Name == "key" { + key := f.Value.String() + keyFlag = &key + } + }) + if keyFlag == nil { + return errors.New("error: key is required") + } + + client := cfg.apiClient(apiFlags, flagSet.Output()) + + query := `mutation deleteKVP( + $repo: ID!, + $key: String!, +) { + deleteRepoKeyValuePair( + repo: $repo, + key: $key, + ) { + alwaysNil + } +}` + + if ok, err := client.NewRequest(query, map[string]interface{}{ + "repo": *repoFlag, + "key": *keyFlag, + }).Do(context.Background(), nil); err != nil || !ok { + return err + } + + fmt.Printf("Key-value pair with key '%s' deleted.\n", *keyFlag) + return nil + } + + // Register the command. + reposCommands = append(reposCommands, &command{ + flagSet: flagSet, + handler: handler, + usageFunc: usageFunc, + }) +} diff --git a/cmd/src/repos_update_kvp.go b/cmd/src/repos_update_kvp.go new file mode 100644 index 0000000000..4e12e9a423 --- /dev/null +++ b/cmd/src/repos_update_kvp.go @@ -0,0 +1,99 @@ +package main + +import ( + "context" + "flag" + "fmt" + + "github.com/sourcegraph/sourcegraph/lib/errors" + "github.com/sourcegraph/src-cli/internal/api" +) + +func init() { + usage := ` +Examples: + + Update the value for a key on a repository: + + $ src repos update-kvp -repo=repoID -key=my-key -value=new-value + + Omitting -value will set the value of the key to null. +` + + flagSet := flag.NewFlagSet("update-kvp", flag.ExitOnError) + usageFunc := func() { + fmt.Fprintf(flag.CommandLine.Output(), "Usage of 'src repos %s':\n", flagSet.Name()) + flagSet.PrintDefaults() + fmt.Println(usage) + } + var ( + repoFlag = flagSet.String("repo", "", `The ID of the repo with the key to be updated (required)`) + keyFlag = flagSet.String("key", "", `The name of the key to be updated (required)`) + valueFlag = flagSet.String("value", "", `The new value of the key to be set. Defaults to null.`) + apiFlags = api.NewFlags(flagSet) + ) + + handler := func(args []string) error { + if err := flagSet.Parse(args); err != nil { + return err + } + if *repoFlag == "" { + return errors.New("error: repo is required") + } + + keyFlag = nil + valueFlag = nil + flagSet.Visit(func(f *flag.Flag) { + if f.Name == "key" { + key := f.Value.String() + keyFlag = &key + } + + if f.Name == "value" { + value := f.Value.String() + valueFlag = &value + } + }) + if keyFlag == nil { + return errors.New("error: key is required") + } + + client := cfg.apiClient(apiFlags, flagSet.Output()) + + query := `mutation updateKVP( + $repo: ID!, + $key: String!, + $value: String, +) { + updateRepoKeyValuePair( + repo: $repo, + key: $key, + value: $value, + ) { + alwaysNil + } +}` + + if ok, err := client.NewRequest(query, map[string]interface{}{ + "repo": *repoFlag, + "key": *keyFlag, + "value": valueFlag, + }).Do(context.Background(), nil); err != nil || !ok { + return err + } + + if valueFlag != nil { + fmt.Printf("Value of key '%s' updated to '%v'\n", *keyFlag, *valueFlag) + } else { + fmt.Printf("Value of key '%s' updated to \n", *keyFlag) + } + return nil + } + + // Register the command. + reposCommands = append(reposCommands, &command{ + flagSet: flagSet, + handler: handler, + usageFunc: usageFunc, + }) +}