Skip to content

Commit

Permalink
Merge branch version/0-47-0-RC1 to adopt changes from PR #3528
Browse files Browse the repository at this point in the history
  • Loading branch information
as-builds committed Oct 11, 2024
2 parents f3a8cb1 + e09e5b1 commit 2f8cbdf
Show file tree
Hide file tree
Showing 7 changed files with 184 additions and 16 deletions.
6 changes: 3 additions & 3 deletions cmd/state/internal/cmdtree/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,17 @@ import (
func newConfigCommand(prime *primer.Values) *captain.Command {
return captain.NewCommand(
"config",
locale.Tl("config_title", "Config"),
locale.Tl("config_title", "Listing Configuration Keys and Values"),
locale.Tl("config_description", "Manage the State Tool configuration"),
prime,
[]*captain.Flag{},
[]*captain.Argument{},
func(ccmd *captain.Command, _ []string) error {
runner, err := config.NewConfig(prime)
runner, err := config.NewList(prime)
if err != nil {
return err
}
return runner.Run(ccmd.Usage)
return runner.Run()
}).SetGroup(UtilsGroup).SetSupportsStructuredOutput()
}

Expand Down
2 changes: 2 additions & 0 deletions internal/colorize/colorize.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,8 @@ func colorize(ct ColorTheme, writer io.Writer, arg string) {
ct.Warning(writer)
case `ERROR`:
ct.Error(writer)
case `BOLD`:
ct.Bold(writer)
case `DISABLED`:
ct.Disabled(writer)
case `ACTIONABLE`:
Expand Down
10 changes: 10 additions & 0 deletions internal/locale/locales/en-us.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1518,6 +1518,12 @@ version:
other: Version
license:
other: License
key:
other: Key
value:
other: Value
default:
other: Default
vulnerabilities:
other: Vulnerabilities (CVEs)
dependency_row:
Expand Down Expand Up @@ -1560,3 +1566,7 @@ install_report_updated:
other: "Updated: [NOTICE]{{.V0}}[/RESET]"
install_report_removed:
other: "Removed: [NOTICE]{{.V0}}[/RESET]"
config_get_help:
other: "To GET the value for a specific config key run '[ACTIONABLE]state config get <key>[/RESET]'"
config_set_help:
other: "To SET the value for a specific config key run '[ACTIONABLE]state config set <key> <value>[/RESET]'"
33 changes: 30 additions & 3 deletions internal/mediators/config/registry.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package config

import "sort"

type Type int

const (
Expand Down Expand Up @@ -29,6 +31,7 @@ type Option struct {
GetEvent Event
SetEvent Event
isRegistered bool
isHidden bool
}

type Registry map[string]Option
Expand All @@ -49,19 +52,28 @@ func NewEnum(options []string, default_ string) *Enums {
func GetOption(key string) Option {
rule, ok := registry[key]
if !ok {
return Option{key, String, "", EmptyEvent, EmptyEvent, false}
return Option{key, String, "", EmptyEvent, EmptyEvent, false, false}
}
return rule
}

// Registers a config option without get/set events.
func RegisterOption(key string, t Type, defaultValue interface{}) {
RegisterOptionWithEvents(key, t, defaultValue, EmptyEvent, EmptyEvent)
registerOption(key, t, defaultValue, EmptyEvent, EmptyEvent, false)
}

// Registers a hidden config option without get/set events.
func RegisterHiddenOption(key string, t Type, defaultValue interface{}) {
registerOption(key, t, defaultValue, EmptyEvent, EmptyEvent, true)
}

// Registers a config option with get/set events.
func RegisterOptionWithEvents(key string, t Type, defaultValue interface{}, get, set Event) {
registry[key] = Option{key, t, defaultValue, get, set, true}
registerOption(key, t, defaultValue, get, set, false)
}

func registerOption(key string, t Type, defaultValue interface{}, get, set Event, hidden bool) {
registry[key] = Option{key, t, defaultValue, get, set, true, hidden}
}

func KnownOption(rule Option) bool {
Expand All @@ -74,3 +86,18 @@ func GetDefault(opt Option) interface{} {
}
return opt.Default
}

// Registered returns all registered options, excluding hidden ones
func Registered() []Option {
var opts []Option
for _, opt := range registry {
if opt.isHidden {
continue
}
opts = append(opts, opt)
}
sort.SliceStable(opts, func(i, j int) bool {
return opts[i].Name < opts[j].Name
})
return opts
}
2 changes: 1 addition & 1 deletion internal/runbits/runtime/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import (
)

func init() {
configMediator.RegisterOption(constants.AsyncRuntimeConfig, configMediator.Bool, false)
configMediator.RegisterHiddenOption(constants.AsyncRuntimeConfig, configMediator.Bool, false)
}

type Opts struct {
Expand Down
120 changes: 111 additions & 9 deletions internal/runners/config/config.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
package config

import (
"fmt"
"strings"

"github.com/ActiveState/cli/internal/config"
"github.com/ActiveState/cli/internal/locale"
mediator "github.com/ActiveState/cli/internal/mediators/config"
"github.com/ActiveState/cli/internal/output"
"github.com/ActiveState/cli/internal/primer"
"github.com/ActiveState/cli/internal/table"
)

type Config struct {
out output.Outputer
cfg *config.Instance
type List struct {
prime primeable
}

type primeable interface {
Expand All @@ -18,13 +23,110 @@ type primeable interface {
primer.Analyticer
}

func NewConfig(prime primeable) (*Config, error) {
return &Config{
out: prime.Output(),
cfg: prime.Config(),
func NewList(prime primeable) (*List, error) {
return &List{
prime: prime,
}, nil
}

func (c *Config) Run(usageFunc func() error) error {
return usageFunc()
type structuredConfigData struct {
Key string `json:"key"`
Value interface{} `json:"value"`
Default interface{} `json:"default"`
opt mediator.Option
}

func (c *List) Run() error {
registered := mediator.Registered()

cfg := c.prime.Config()
out := c.prime.Output()

var data []structuredConfigData
for _, opt := range registered {
configuredValue := cfg.Get(opt.Name)
data = append(data, structuredConfigData{
Key: opt.Name,
Value: configuredValue,
Default: mediator.GetDefault(opt),
opt: opt,
})
}

if out.Type().IsStructured() {
out.Print(output.Structured(data))
} else {
if err := c.renderUserFacing(data); err != nil {
return err
}
}

return nil
}

func (c *List) renderUserFacing(configData []structuredConfigData) error {
cfg := c.prime.Config()
out := c.prime.Output()

tbl := table.New(locale.Ts("key", "value", "default"))
tbl.HideDash = true
for _, config := range configData {
tbl.AddRow([]string{
fmt.Sprintf("[CYAN]%s[/RESET]", config.Key),
renderConfigValue(cfg, config.opt),
fmt.Sprintf("[DISABLED]%s[/RESET]", formatValue(config.opt, config.Default)),
})
}

out.Print(tbl.Render())
out.Notice("")
out.Notice(locale.T("config_get_help"))
out.Notice(locale.T("config_set_help"))

return nil
}

func renderConfigValue(cfg *config.Instance, opt mediator.Option) string {
configured := cfg.Get(opt.Name)
var tags []string
if opt.Type == mediator.Bool {
if configured == true {
tags = append(tags, "[GREEN]")
} else {
tags = append(tags, "[RED]")
}
}

value := formatValue(opt, configured)
if cfg.IsSet(opt.Name) {
tags = append(tags, "[BOLD]")
value = value + "*"
}

if len(tags) > 0 {
return fmt.Sprintf("%s%s[/RESET]", strings.Join(tags, ""), value)
}

return value
}

func formatValue(opt mediator.Option, value interface{}) string {
switch opt.Type {
case mediator.Enum, mediator.String:
return formatString(fmt.Sprintf("%v", value))
default:
return fmt.Sprintf("%v", value)
}
}

func formatString(value string) string {
if value == "" {
return "\"\""
}

if len(value) > 100 {
value = value[:100] + "..."
}

return fmt.Sprintf("\"%s\"", value)
}
27 changes: 27 additions & 0 deletions test/integration/config_int_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,33 @@ func (suite *ConfigIntegrationTestSuite) TestJSON() {
AssertValidJSON(suite.T(), cp)
}

func (suite *ConfigIntegrationTestSuite) TestList() {
suite.OnlyRunForTags(tagsuite.Config)
ts := e2e.New(suite.T(), false)
defer ts.Close()

cp := ts.Spawn("config")
cp.Expect("Key")
cp.Expect("Value")
cp.Expect("Default")
cp.Expect("optin.buildscripts")
cp.Expect("false")
cp.ExpectExitCode(0)

cp = ts.Spawn("config", "set", "optin.buildscripts", "true")
cp.Expect("Successfully")
cp.ExpectExitCode(0)

cp = ts.Spawn("config")
cp.Expect("Key")
cp.Expect("Value")
cp.Expect("Default")
cp.Expect("optin.buildscripts")
cp.Expect("true*")
cp.ExpectExitCode(0)

suite.Require().NotContains(cp.Snapshot(), constants.AsyncRuntimeConfig)
}
func TestConfigIntegrationTestSuite(t *testing.T) {
suite.Run(t, new(ConfigIntegrationTestSuite))
}

0 comments on commit 2f8cbdf

Please sign in to comment.