Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
0af76ca
Refactor `pc config` to use key-based get/set/list/describe/unset com…
austin-denoble May 28, 2026
00eb59a
Fix onChange contract in `pc config set` and `unset`
austin-denoble May 28, 2026
62e6b69
Refactor pc config commands for testability and add unit tests
austin-denoble May 31, 2026
8b0af44
correct bug in flow from config input normalization to persistence to…
austin-denoble May 31, 2026
5bfe55c
use msg.FailJSON in get, describe, and list config commands
austin-denoble May 31, 2026
f499f0a
make sure visibleKeys() preserves the ordering of the listed keys
austin-denoble May 31, 2026
1a6a4f9
clean up confusing aliasing around ValidValues and how things are act…
austin-denoble May 31, 2026
8936497
clean up error message when using unset and the value is unchanged
austin-denoble May 31, 2026
f455c64
add 'prod' back to environment configuration
austin-denoble Jun 1, 2026
12ba171
add keyDescriptor.getStoredStr and ConfigProperty.GetStored to suppor…
austin-denoble Jun 1, 2026
b90885b
add onChange to the api-key keyDescriptor to make sure we're updating…
austin-denoble Jun 1, 2026
4759118
Fix JSON output correctness for config set and unset
austin-denoble Jun 1, 2026
1286673
add an -all flag to config list to allow showing hidden configuration…
austin-denoble Jun 1, 2026
31cbc81
make sure config set output is showing what's saved or passed rather …
austin-denoble Jun 1, 2026
af41457
add getStoredStr for api-key keyDescriptor
austin-denoble Jun 1, 2026
d3178b2
always call oauth.Logout() when environment configuration is changed
austin-denoble Jun 1, 2026
2be3a51
allow color aliases
austin-denoble Jun 1, 2026
a768a00
fix autocompletions leaking hidden configuration keys
austin-denoble Jun 2, 2026
351f938
fix(config): respect env var overrides in config set/unset and surfac…
austin-denoble Jun 3, 2026
d96200e
remove long_description from json output
austin-denoble Jun 3, 2026
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
2 changes: 1 addition & 1 deletion internal/pkg/cli/command/auth/configure.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ var (
When you configure a service account, the CLI automatically targets the organization
associated with that account, and prompts you to select a project if multiple exist.

An API overrides any explicitly targeted organization and project, instead targeting
An API key overrides any explicitly targeted organization and project, instead targeting
the organization and project associated with the API key itself. API keys do not grant
Admin API access.

Expand Down
12 changes: 10 additions & 2 deletions internal/pkg/cli/command/config/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,17 @@ func NewConfigCmd() *cobra.Command {
Long: configHelp,
}

cmd.AddCommand(NewSetColorCmd())
cmd.AddCommand(NewSetApiKeyCmd())
// Primary commands
cmd.AddCommand(NewGetCmd())
cmd.AddCommand(NewSetCmd())
cmd.AddCommand(NewUnsetCmd())
cmd.AddCommand(NewListCmd())
cmd.AddCommand(NewDescribeCmd())

// Deprecated aliases kept for backwards compatibility
cmd.AddCommand(NewGetApiKeyCmd())
cmd.AddCommand(NewSetApiKeyCmd())
cmd.AddCommand(NewSetColorCmd())
cmd.AddCommand(NewSetEnvCmd())

return cmd
Expand Down
75 changes: 75 additions & 0 deletions internal/pkg/cli/command/config/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package config

import "context"

// mockConfigService implements ConfigService for unit tests.
// Each field controls what the corresponding method returns.
// The last* fields record the arguments of the most recent call.
type mockConfigService struct {
// Get
getValue string
getSensitive bool
getEnvVarName string
getEnvVarOverride bool
getErr error
lastGetKey string

// GetStored — defaults to getValue/getSensitive/getErr when not explicitly set
getStoredValue string
getStoredSensitive bool
getStoredErr error
getStoredOverride bool // set to true to use getStored* fields instead of get* fields
lastGetStoredKey string

// Set
setLines []string
setErr error
lastSetKey string
lastSetValue string

// Unset
unsetLines []string
unsetErr error
lastUnsetKey string

// List
listResult []ConfigEntry

// Describe
describeResult ConfigDescription
describeErr error
lastDescribeKey string
}

func (m *mockConfigService) Get(key string) (string, bool, string, bool, error) {
m.lastGetKey = key
return m.getValue, m.getSensitive, m.getEnvVarName, m.getEnvVarOverride, m.getErr
}

func (m *mockConfigService) GetStored(key string) (string, bool, error) {
m.lastGetStoredKey = key
if m.getStoredOverride {
return m.getStoredValue, m.getStoredSensitive, m.getStoredErr
}
return m.getValue, m.getSensitive, m.getErr
}

func (m *mockConfigService) Set(ctx context.Context, key, value string) ([]string, error) {
m.lastSetKey = key
m.lastSetValue = value
return m.setLines, m.setErr
}

func (m *mockConfigService) Unset(ctx context.Context, key string) ([]string, error) {
m.lastUnsetKey = key
return m.unsetLines, m.unsetErr
}

func (m *mockConfigService) List(includeHidden bool) []ConfigEntry {
return m.listResult
}

func (m *mockConfigService) Describe(key string) (ConfigDescription, error) {
m.lastDescribeKey = key
return m.describeResult, m.describeErr
}
106 changes: 106 additions & 0 deletions internal/pkg/cli/command/config/describe.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package config

import (
"fmt"
"os"
"strings"

"github.com/pinecone-io/cli/internal/pkg/utils/exit"
"github.com/pinecone-io/cli/internal/pkg/utils/help"
"github.com/pinecone-io/cli/internal/pkg/utils/msg"
"github.com/pinecone-io/cli/internal/pkg/utils/presenters"
"github.com/pinecone-io/cli/internal/pkg/utils/text"
"github.com/spf13/cobra"
)

type DescribeCmdOptions struct {
reveal bool
json bool
}

func NewDescribeCmd() *cobra.Command {
options := DescribeCmdOptions{}

cmd := &cobra.Command{
Use: "describe <key>",
Short: "Show detailed information about a configuration setting",
Example: help.Examples(`
pc config describe api-key
pc config describe environment
pc config describe color --json
`),
Args: cobra.ExactArgs(1),
ValidArgs: visibleKeys(),
Run: func(cmd *cobra.Command, args []string) {
svc := newDefaultConfigService()
if err := runDescribeCmd(svc, args[0], options); err != nil {
msg.FailJSON(options.json, "%s", err)
exit.ErrorMsg(err.Error())
}
},
}

cmd.Flags().BoolVar(&options.reveal, "reveal", false, "Reveal the full value for sensitive settings like api-key")
cmd.Flags().BoolVarP(&options.json, "json", "j", false, "Output as JSON")

return cmd
}

func runDescribeCmd(svc ConfigService, keyName string, opts DescribeCmdOptions) error {
// --json output for the describe command
type describeOutput struct {
Key string `json:"key"`
Value string `json:"value"`
EnvVarName string `json:"env_var_name,omitempty"`
EnvVarOverride *bool `json:"env_var_override,omitempty"`
Description string `json:"description"`
Sensitive bool `json:"sensitive"`
ValidValues []string `json:"valid_values,omitempty"`
}

desc, err := svc.Describe(keyName)
if err != nil {
return err
}

value := desc.Value
if desc.Sensitive && !opts.reveal {
value = presenters.MaskHeadTail(value, 4, 4)
}
if opts.json {
out := describeOutput{
Key: desc.Key,
Value: value,
EnvVarName: desc.EnvVarName,
Description: desc.Description,
Sensitive: desc.Sensitive,
ValidValues: desc.ValidValues,
}
if desc.EnvVarName != "" {
out.EnvVarOverride = &desc.EnvVarOverride
}
fmt.Fprintln(os.Stdout, text.IndentJSON(out))
return nil
}

w := presenters.NewTabWriter()
fmt.Fprintf(w, "KEY\t%s\n", desc.Key)
fmt.Fprintf(w, "VALUE\t%s\n", displayValue(value))
if desc.EnvVarName != "" {
fmt.Fprintf(w, "ENV VAR NAME\t$%s\n", desc.EnvVarName)
fmt.Fprintf(w, "ENV VAR OVERRIDE\t%s\n", text.BoolToString(desc.EnvVarOverride))
}
fmt.Fprintf(w, "SENSITIVE\t%s\n", text.BoolToString(desc.Sensitive))
if len(desc.ValidValues) > 0 {
fmt.Fprintf(w, "VALID VALUES\t%s\n", strings.Join(desc.ValidValues, ", "))
}
fmt.Fprintf(w, "DESCRIPTION\t%s\n", desc.Description)
w.Flush()

if desc.LongDescription != "" {
fmt.Fprintln(os.Stdout)
fmt.Fprintln(os.Stdout, desc.LongDescription)
}

return nil
}
Loading
Loading