Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit4b99e2d

Browse files
authored
feat: add YAML support to server (#6934)
1 parenta3c6cb1 commit4b99e2d

32 files changed

+1578
-441
lines changed

‎.golangci.yaml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ issues:
194194
linters:
195195
# We use assertions rather than explicitly checking errors in tests
196196
-errcheck
197+
-forcetypeassert
197198

198199
fix:true
199200
max-issues-per-linter:0

‎Makefile‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -518,7 +518,7 @@ update-golden-files: cli/testdata/.gen-golden helm/tests/testdata/.gen-golden sc
518518
.PHONY: update-golden-files
519519

520520
cli/testdata/.gen-golden:$(wildcard cli/testdata/*.golden)$(wildcard cli/*.tpl)$(GO_SRC_FILES)
521-
gotest ./cli -run=TestCommandHelp -update
521+
gotest ./cli -run="Test(CommandHelp|ServerYAML)" -update
522522
touch"$@"
523523

524524
helm/tests/testdata/.gen-golden:$(wildcard helm/tests/testdata/*.golden)$(GO_SRC_FILES)

‎cli/clibase/clibase.go‎

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,10 @@ import (
1414

1515
// Group describes a hierarchy of groups that an option or command belongs to.
1616
typeGroupstruct {
17-
Parent*Group`json:"parent,omitempty"`
18-
Namestring`json:"name,omitempty"`
19-
Children []Group`json:"children,omitempty"`
20-
Descriptionstring`json:"description,omitempty"`
21-
}
22-
23-
func (g*Group)AddChild(childGroup) {
24-
child.Parent=g
25-
g.Children=append(g.Children,child)
17+
Parent*Group`json:"parent,omitempty"`
18+
Namestring`json:"name,omitempty"`
19+
YAMLstring`json:"yaml,omitempty"`
20+
Descriptionstring`json:"description,omitempty"`
2621
}
2722

2823
// Ancestry returns the group and all of its parents, in order.

‎cli/clibase/cmd.go‎

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"github.com/spf13/pflag"
1414
"golang.org/x/exp/slices"
1515
"golang.org/x/xerrors"
16+
"gopkg.in/yaml.v3"
1617
)
1718

1819
// Cmd describes an executable command.
@@ -76,10 +77,8 @@ func (c *Cmd) PrepareAll() error {
7677
}
7778
varmerrerror
7879

79-
slices.SortFunc(c.Options,func(a,bOption)bool {
80-
returna.Flag<b.Flag
81-
})
82-
for_,opt:=rangec.Options {
80+
fori:=rangec.Options {
81+
opt:=&c.Options[i]
8382
ifopt.Name=="" {
8483
switch {
8584
caseopt.Flag!="":
@@ -102,6 +101,10 @@ func (c *Cmd) PrepareAll() error {
102101
}
103102
}
104103
}
104+
105+
slices.SortFunc(c.Options,func(a,bOption)bool {
106+
returna.Name<b.Name
107+
})
105108
slices.SortFunc(c.Children,func(a,b*Cmd)bool {
106109
returna.Name()<b.Name()
107110
})
@@ -262,17 +265,38 @@ func (inv *Invocation) run(state *runState) error {
262265
parsedArgs=inv.parsedFlags.Args()
263266
}
264267

265-
// Set defaults for flags that weren't set by the user.
266-
skipDefaults:=make(map[int]struct{},len(inv.Command.Options))
268+
// Set value sources for flags.
267269
fori,opt:=rangeinv.Command.Options {
268270
iffl:=inv.parsedFlags.Lookup(opt.Flag);fl!=nil&&fl.Changed {
269-
skipDefaults[i]=struct{}{}
271+
inv.Command.Options[i].ValueSource=ValueSourceFlag
272+
}
273+
}
274+
275+
// Read YAML configs, if any.
276+
for_,opt:=rangeinv.Command.Options {
277+
path,ok:=opt.Value.(*YAMLConfigPath)
278+
if!ok||path.String()=="" {
279+
continue
270280
}
271-
ifopt.envChanged {
272-
skipDefaults[i]=struct{}{}
281+
282+
byt,err:=os.ReadFile(path.String())
283+
iferr!=nil {
284+
returnxerrors.Errorf("reading yaml: %w",err)
285+
}
286+
287+
varn yaml.Node
288+
err=yaml.Unmarshal(byt,&n)
289+
iferr!=nil {
290+
returnxerrors.Errorf("decoding yaml: %w",err)
291+
}
292+
293+
err=inv.Command.Options.UnmarshalYAML(&n)
294+
iferr!=nil {
295+
returnxerrors.Errorf("applying yaml: %w",err)
273296
}
274297
}
275-
err=inv.Command.Options.SetDefaults(skipDefaults)
298+
299+
err=inv.Command.Options.SetDefaults()
276300
iferr!=nil {
277301
returnxerrors.Errorf("setting defaults: %w",err)
278302
}

‎cli/clibase/cmd_test.go‎

Lines changed: 73 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"bytes"
55
"context"
66
"fmt"
7+
"os"
78
"strings"
89
"testing"
910

@@ -555,42 +556,80 @@ func TestCommand_EmptySlice(t *testing.T) {
555556
funcTestCommand_DefaultsOverride(t*testing.T) {
556557
t.Parallel()
557558

558-
vargotstring
559-
cmd:=&clibase.Cmd{
560-
Options: clibase.OptionSet{
561-
{
562-
Name:"url",
563-
Flag:"url",
564-
Default:"def.com",
565-
Env:"URL",
566-
Value:clibase.StringOf(&got),
567-
},
568-
},
569-
Handler: (func(i*clibase.Invocation)error {
570-
_,_=fmt.Fprintf(i.Stdout,"%s",got)
571-
returnnil
572-
}),
559+
test:=func(namestring,wantstring,fnfunc(t*testing.T,inv*clibase.Invocation)) {
560+
t.Run(name,func(t*testing.T) {
561+
t.Parallel()
562+
563+
var (
564+
gotstring
565+
config clibase.YAMLConfigPath
566+
)
567+
cmd:=&clibase.Cmd{
568+
Options: clibase.OptionSet{
569+
{
570+
Name:"url",
571+
Flag:"url",
572+
Default:"def.com",
573+
Env:"URL",
574+
Value:clibase.StringOf(&got),
575+
YAML:"url",
576+
},
577+
{
578+
Name:"config",
579+
Flag:"config",
580+
Default:"",
581+
Value:&config,
582+
},
583+
},
584+
Handler: (func(i*clibase.Invocation)error {
585+
_,_=fmt.Fprintf(i.Stdout,"%s",got)
586+
returnnil
587+
}),
588+
}
589+
590+
inv:=cmd.Invoke()
591+
stdio:=fakeIO(inv)
592+
fn(t,inv)
593+
err:=inv.Run()
594+
require.NoError(t,err)
595+
require.Equal(t,want,stdio.Stdout.String())
596+
})
573597
}
574598

575-
// Base case
576-
inv:=cmd.Invoke()
577-
stdio:=fakeIO(inv)
578-
err:=inv.Run()
579-
require.NoError(t,err)
580-
require.Equal(t,"def.com",stdio.Stdout.String())
599+
test("DefaultOverNothing","def.com",func(t*testing.T,inv*clibase.Invocation) {})
581600

582-
// Flag overrides
583-
inv=cmd.Invoke("--url","good.com")
584-
stdio=fakeIO(inv)
585-
err=inv.Run()
586-
require.NoError(t,err)
587-
require.Equal(t,"good.com",stdio.Stdout.String())
601+
test("FlagOverDefault","good.com",func(t*testing.T,inv*clibase.Invocation) {
602+
inv.Args= []string{"--url","good.com"}
603+
})
588604

589-
// Env overrides
590-
inv=cmd.Invoke()
591-
inv.Environ.Set("URL","good.com")
592-
stdio=fakeIO(inv)
593-
err=inv.Run()
594-
require.NoError(t,err)
595-
require.Equal(t,"good.com",stdio.Stdout.String())
605+
test("EnvOverDefault","good.com",func(t*testing.T,inv*clibase.Invocation) {
606+
inv.Environ.Set("URL","good.com")
607+
})
608+
609+
test("FlagOverEnv","good.com",func(t*testing.T,inv*clibase.Invocation) {
610+
inv.Environ.Set("URL","bad.com")
611+
inv.Args= []string{"--url","good.com"}
612+
})
613+
614+
test("FlagOverYAML","good.com",func(t*testing.T,inv*clibase.Invocation) {
615+
fi,err:=os.CreateTemp(t.TempDir(),"config.yaml")
616+
require.NoError(t,err)
617+
deferfi.Close()
618+
619+
_,err=fi.WriteString("url: bad.com")
620+
require.NoError(t,err)
621+
622+
inv.Args= []string{"--config",fi.Name(),"--url","good.com"}
623+
})
624+
625+
test("YAMLOverDefault","good.com",func(t*testing.T,inv*clibase.Invocation) {
626+
fi,err:=os.CreateTemp(t.TempDir(),"config.yaml")
627+
require.NoError(t,err)
628+
deferfi.Close()
629+
630+
_,err=fi.WriteString("url: good.com")
631+
require.NoError(t,err)
632+
633+
inv.Args= []string{"--config",fi.Name()}
634+
})
596635
}

‎cli/clibase/option.go‎

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,23 @@ package clibase
22

33
import (
44
"os"
5+
"strings"
56

67
"github.com/hashicorp/go-multierror"
78
"github.com/spf13/pflag"
89
"golang.org/x/xerrors"
910
)
1011

12+
typeValueSourcestring
13+
14+
const (
15+
ValueSourceNoneValueSource=""
16+
ValueSourceFlagValueSource="flag"
17+
ValueSourceEnvValueSource="env"
18+
ValueSourceYAMLValueSource="yaml"
19+
ValueSourceDefaultValueSource="default"
20+
)
21+
1122
// Option is a configuration option for a CLI application.
1223
typeOptionstruct {
1324
Namestring`json:"name,omitempty"`
@@ -47,7 +58,18 @@ type Option struct {
4758

4859
Hiddenbool`json:"hidden,omitempty"`
4960

50-
envChangedbool
61+
ValueSourceValueSource`json:"value_source,omitempty"`
62+
}
63+
64+
func (oOption)YAMLPath()string {
65+
ifo.YAML=="" {
66+
return""
67+
}
68+
vargs []string
69+
for_,g:=rangeo.Group.Ancestry() {
70+
gs=append(gs,g.YAML)
71+
}
72+
returnstrings.Join(append(gs,o.YAML),".")
5173
}
5274

5375
// OptionSet is a group of options that can be applied to a command.
@@ -135,8 +157,7 @@ func (s *OptionSet) ParseEnv(vs []EnvVar) error {
135157
continue
136158
}
137159

138-
opt.envChanged=true
139-
(*s)[i]=opt
160+
(*s)[i].ValueSource=ValueSourceEnv
140161
iferr:=opt.Value.Set(envVal);err!=nil {
141162
merr=multierror.Append(
142163
merr,xerrors.Errorf("parse %q: %w",opt.Name,err),
@@ -148,8 +169,8 @@ func (s *OptionSet) ParseEnv(vs []EnvVar) error {
148169
}
149170

150171
// SetDefaults sets the default values for each Option, skipping values
151-
// thathavealreadybeen set as indicated by the skip map.
152-
func (s*OptionSet)SetDefaults(skipmap[int]struct{})error {
172+
// that alreadyhave a value source.
173+
func (s*OptionSet)SetDefaults()error {
153174
ifs==nil {
154175
returnnil
155176
}
@@ -158,10 +179,8 @@ func (s *OptionSet) SetDefaults(skip map[int]struct{}) error {
158179

159180
fori,opt:=range*s {
160181
// Skip values that may have already been set by the user.
161-
iflen(skip)>0 {
162-
if_,ok:=skip[i];ok {
163-
continue
164-
}
182+
ifopt.ValueSource!=ValueSourceNone {
183+
continue
165184
}
166185

167186
ifopt.Default=="" {
@@ -178,6 +197,7 @@ func (s *OptionSet) SetDefaults(skip map[int]struct{}) error {
178197
)
179198
continue
180199
}
200+
(*s)[i].ValueSource=ValueSourceDefault
181201
iferr:=opt.Value.Set(opt.Default);err!=nil {
182202
merr=multierror.Append(
183203
merr,xerrors.Errorf("parse %q: %w",opt.Name,err),
@@ -186,3 +206,15 @@ func (s *OptionSet) SetDefaults(skip map[int]struct{}) error {
186206
}
187207
returnmerr.ErrorOrNil()
188208
}
209+
210+
// ByName returns the Option with the given name, or nil if no such option
211+
// exists.
212+
func (s*OptionSet)ByName(namestring)*Option {
213+
fori:=range*s {
214+
opt:=&(*s)[i]
215+
ifopt.Name==name {
216+
returnopt
217+
}
218+
}
219+
returnnil
220+
}

‎cli/clibase/option_test.go‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ func TestOptionSet_ParseFlags(t *testing.T) {
4949
},
5050
}
5151

52-
err:=os.SetDefaults(nil)
52+
err:=os.SetDefaults()
5353
require.NoError(t,err)
5454

5555
err=os.FlagSet().Parse([]string{"--name","foo","--name","bar"})
@@ -111,7 +111,7 @@ func TestOptionSet_ParseEnv(t *testing.T) {
111111
},
112112
}
113113

114-
err:=os.SetDefaults(nil)
114+
err:=os.SetDefaults()
115115
require.NoError(t,err)
116116

117117
err=os.ParseEnv(clibase.ParseEnviron([]string{"CODER_WORKSPACE_NAME="},"CODER_"))
@@ -133,7 +133,7 @@ func TestOptionSet_ParseEnv(t *testing.T) {
133133
},
134134
}
135135

136-
err:=os.SetDefaults(nil)
136+
err:=os.SetDefaults()
137137
require.NoError(t,err)
138138

139139
err=os.ParseEnv([]clibase.EnvVar{
@@ -157,7 +157,7 @@ func TestOptionSet_ParseEnv(t *testing.T) {
157157
},
158158
}
159159

160-
err:=os.SetDefaults(nil)
160+
err:=os.SetDefaults()
161161
require.NoError(t,err)
162162

163163
err=os.ParseEnv([]clibase.EnvVar{

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp