- Notifications
You must be signed in to change notification settings - Fork1.1k
feat: refactor deployment config#6347
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Merged
Changes fromall commits
Commits
Show all changes
89 commits Select commitHold shift + click to select a range
6c29207 Initial scaffold
ammario12dcc45 Add Duration
ammariod1e2e15 Begin converting AccessURL
ammario8db4626 fixup! Begin converting AccessURL
ammariodc81f47 Start migrating Server
ammariod511001 Convert a couple more fields
ammario8cc406e replace DeploymentConfig[T] with bigcli.[T]
ammario18b2552 Remove .Value calls
ammariobad7aca Finish destroying newConfig
ammariof075ad5 delete deployment/
ammario69600d7 rewrite server.go
ammario63159a6 ugh
ammario03b08fa Server boots
ammarioe0d6c1e Move critical options code into `codersdk`
ammario5bebd0f DefaultCacheDir
ammario2c7b39d Merge remote-tracking branch 'origin/main' into bigcli
ammario05b3a10 Fix config dir bug
ammariodcbd0d8 update golden --help
ammariofc06f64 Support NoOptDefValue
ammariod31fa37 Don't hide pflag.FlagSet
ammario0d7d557 Help template scaffold
ammariof3d45d3 Show env in help output
ammariod322114 Merge remote-tracking branch 'origin/main' into bigcli
ammario8f9d44b Write more descriptions
ammarioacac92d Organize telemetry
ammario1c8359b Finish grouping up flags
ammario8d0020f Render subcommands
ammario882a80f Convert Groups to first class bigcli feature
ammarioae858b4 deepMapNode?
ammariob34d481 Add YAML tags everywhere.......
ammarioe0e113b Minor changes
ammario02c8f6c Group Enterprise flags
ammario000466f Massive refactor to improve help formatting
ammarioc6133f2 Improve help formatting again
ammarioab21e8f Send group descriptions to YAML
ammariob816b1a Fix YAML tests
ammario559b046 make gen
ammario3b24149 Pass linter
ammarioe422c1d Fix slim bugs
ammarioea6c3b7 Start frontend... about to go to sleep 🥱
ammariod4aa8d3 Merge remote-tracking branch 'origin/main' into bigcli
ammario58b6324 Fix remaining go compilation errors
ammariocae2eab Do some type generation
ammariod4bd380 Fix most broken frontend code...
ammario8a493ef Add envparse library
ammario84b59be Add legacy git auth env support
ammarioac3507f Fix Git Provider rendering in frontend
ammario95db142 Remove unused lint rules
ammario790f45a Update golden files
ammario360b600 Fix all stories
ammario2344013 Fix server tests
ammario394fbfa Merge remote-tracking branch 'origin/main' into bigcli
ammarioac909b5 Disable clidocsgen.. for now
ammario8a2637d Server tests pass?
ammario3ed919e Start figuring out CLI array bug
ammariod397839 bigcli: fix slice parsing
ammario957500b fix remaining calls to deprecated "experimental"
ammario0890005 Fix more tests
ammario622df7f make gen
ammario362618e Fix another server test bug
ammario2fa8b78 Fix logger!
ammario28e4b07 fix access url test
ammario410ad26 make gen
ammario5c3f648 fix frontend!
ammariof29889f Merge remote-tracking branch 'origin/main' into bigcli
ammario6ced9cf Debug log gitAuthConfigs
ammariod9d1592 No more implicit options
ammario74c6da2 Re-enable cli docs gen
ammario9e53c96 De-pointer DeploymentValues
ammario06f82b5 Decompose DeploymentConfig
ammario2f5a522 Some comments
ammario53e92fc Move envparse into bigcli
ammarioe9e2908 Minor changes
ammarioc3a11fd Add context to clitest.Start
ammarioa090cd4 Remove dead function
ammariod9a8da6 Merge remote-tracking branch 'origin/main' into bigcli
ammarioe53367a Fix FE
ammario6252316 make lint passes
ammariobf1a099 Pass highlyConfigurable
ammario274d5c5 Context bug
ammarioa213d25 Rename to clibase
ammario2938980 fix slim build
ammario140438e Merge remote-tracking branch 'origin/main' into bigcli
ammario46936f5 Fix merge issues
ammario06277c4 Set max token lifetime correctly
ammariofc8e6ca Command -> Cmd
ammario2a74445 Typo
ammario3cfb4bf Show disabled badge in zero option table
ammario4d8bc75 Merge remote-tracking branch 'origin/main' into bigcli
ammarioFile filter
Filter by extension
Conversations
Failed to load comments.
Loading
Uh oh!
There was an error while loading.Please reload this page.
Jump to
Jump to file
Failed to load files.
Loading
Uh oh!
There was an error while loading.Please reload this page.
Diff view
Diff view
There are no files selected for viewing
2 changes: 0 additions & 2 deletions.golangci.yaml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
3 changes: 2 additions & 1 deletionMakefile
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
86 changes: 86 additions & 0 deletionscli/clibase/clibase.go
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,86 @@ | ||
| // Package clibase offers an all-in-one solution for a highly configurable CLI | ||
| // application. Within Coder, we use it for our `server` subcommand, which | ||
| // demands more functionality than cobra/viper can offer. | ||
| // | ||
| // We will extend its usage to the rest of our application, completely replacing | ||
| // cobra/viper. It's also a candidate to be broken out into its own open-source | ||
| // library, so we avoid deep coupling with Coder concepts. | ||
| package clibase | ||
| import ( | ||
| "strings" | ||
| "golang.org/x/exp/maps" | ||
| ) | ||
| // Group describes a hierarchy of groups that an option or command belongs to. | ||
| type Group struct { | ||
| Parent *Group `json:"parent,omitempty"` | ||
| Name string `json:"name,omitempty"` | ||
| Children []Group `json:"children,omitempty"` | ||
| Description string `json:"description,omitempty"` | ||
| } | ||
| func (g *Group) AddChild(child Group) { | ||
| child.Parent = g | ||
| g.Children = append(g.Children, child) | ||
| } | ||
| // Ancestry returns the group and all of its parents, in order. | ||
| func (g *Group) Ancestry() []Group { | ||
| if g == nil { | ||
| return nil | ||
| } | ||
| groups := []Group{*g} | ||
| for p := g.Parent; p != nil; p = p.Parent { | ||
| // Prepend to the slice so that the order is correct. | ||
| groups = append([]Group{*p}, groups...) | ||
| } | ||
| return groups | ||
| } | ||
| func (g *Group) FullName() string { | ||
| var names []string | ||
| for _, g := range g.Ancestry() { | ||
| names = append(names, g.Name) | ||
| } | ||
| return strings.Join(names, " / ") | ||
| } | ||
| // Annotations is an arbitrary key-mapping used to extend the Option and Command types. | ||
| // Its methods won't panic if the map is nil. | ||
| type Annotations map[string]string | ||
| // Mark sets a value on the annotations map, creating one | ||
| // if it doesn't exist. Mark does not mutate the original and | ||
| // returns a copy. It is suitable for chaining. | ||
| func (a Annotations) Mark(key string, value string) Annotations { | ||
| var aa Annotations | ||
| if a != nil { | ||
| aa = maps.Clone(a) | ||
| } else { | ||
| aa = make(Annotations) | ||
| } | ||
| aa[key] = value | ||
| return aa | ||
| } | ||
| // IsSet returns true if the key is set in the annotations map. | ||
| func (a Annotations) IsSet(key string) bool { | ||
| if a == nil { | ||
| return false | ||
| } | ||
| _, ok := a[key] | ||
| return ok | ||
| } | ||
| // Get retrieves a key from the map, returning false if the key is not found | ||
| // or the map is nil. | ||
| func (a Annotations) Get(key string) (string, bool) { | ||
| if a == nil { | ||
| return "", false | ||
| } | ||
| v, ok := a[key] | ||
| return v, ok | ||
| } |
48 changes: 48 additions & 0 deletionscli/clibase/cmd.go
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| package clibase | ||
| import "strings" | ||
| // Cmd describes an executable command. | ||
| type Cmd struct { | ||
| // Parent is the direct parent of the command. | ||
| Parent *Cmd | ||
| // Children is a list of direct descendants. | ||
| Children []*Cmd | ||
| // Use is provided in form "command [flags] [args...]". | ||
| Use string | ||
| // Short is a one-line description of the command. | ||
| Short string | ||
| // Long is a detailed description of the command, | ||
| // presented on its help page. It may contain examples. | ||
| Long string | ||
| Options OptionSet | ||
| Annotations Annotations | ||
| } | ||
| // Name returns the first word in the Use string. | ||
| func (c *Cmd) Name() string { | ||
| return strings.Split(c.Use, " ")[0] | ||
| } | ||
| // FullName returns the full invocation name of the command, | ||
| // as seen on the command line. | ||
| func (c *Cmd) FullName() string { | ||
| var names []string | ||
| if c.Parent != nil { | ||
| names = append(names, c.Parent.FullName()) | ||
| } | ||
| names = append(names, c.Name()) | ||
| return strings.Join(names, " ") | ||
| } | ||
| // FullName returns usage of the command, preceded | ||
| // by the usage of its parents. | ||
| func (c *Cmd) FullUsage() string { | ||
| var uses []string | ||
| if c.Parent != nil { | ||
| uses = append(uses, c.Parent.FullUsage()) | ||
| } | ||
| uses = append(uses, c.Use) | ||
| return strings.Join(uses, " ") | ||
| } |
42 changes: 42 additions & 0 deletionscli/clibase/env.go
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| package clibase | ||
ammario marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
| import "strings" | ||
| // name returns the name of the environment variable. | ||
| func envName(line string) string { | ||
| return strings.ToUpper( | ||
| strings.SplitN(line, "=", 2)[0], | ||
| ) | ||
| } | ||
| // value returns the value of the environment variable. | ||
| func envValue(line string) string { | ||
| tokens := strings.SplitN(line, "=", 2) | ||
| if len(tokens) < 2 { | ||
| return "" | ||
| } | ||
| return tokens[1] | ||
| } | ||
| // Var represents a single environment variable of form | ||
| // NAME=VALUE. | ||
| type EnvVar struct { | ||
| Name string | ||
| Value string | ||
| } | ||
| // EnvsWithPrefix returns all environment variables starting with | ||
| // prefix without said prefix. | ||
| func EnvsWithPrefix(environ []string, prefix string) []EnvVar { | ||
| var filtered []EnvVar | ||
| for _, line := range environ { | ||
| name := envName(line) | ||
| if strings.HasPrefix(name, prefix) { | ||
| filtered = append(filtered, EnvVar{ | ||
| Name: strings.TrimPrefix(name, prefix), | ||
| Value: envValue(line), | ||
| }) | ||
| } | ||
| } | ||
| return filtered | ||
| } | ||
44 changes: 44 additions & 0 deletionscli/clibase/env_test.go
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| package clibase_test | ||
| import ( | ||
| "reflect" | ||
| "testing" | ||
| "github.com/coder/coder/cli/clibase" | ||
| ) | ||
| func TestFilterNamePrefix(t *testing.T) { | ||
| t.Parallel() | ||
| type args struct { | ||
| environ []string | ||
| prefix string | ||
| } | ||
| tests := []struct { | ||
| name string | ||
| args args | ||
| want []clibase.EnvVar | ||
| }{ | ||
| {"empty", args{[]string{}, "SHIRE"}, nil}, | ||
| { | ||
| "ONE", | ||
| args{ | ||
| []string{ | ||
| "SHIRE_BRANDYBUCK=hmm", | ||
| }, | ||
| "SHIRE_", | ||
| }, | ||
| []clibase.EnvVar{ | ||
| {Name: "BRANDYBUCK", Value: "hmm"}, | ||
| }, | ||
| }, | ||
| } | ||
| for _, tt := range tests { | ||
| tt := tt | ||
| t.Run(tt.name, func(t *testing.T) { | ||
| t.Parallel() | ||
| if got := clibase.EnvsWithPrefix(tt.args.environ, tt.args.prefix); !reflect.DeepEqual(got, tt.want) { | ||
| t.Errorf("EnvsWithPrefix() = %v, want %v", got, tt.want) | ||
| } | ||
| }) | ||
| } | ||
| } |
149 changes: 149 additions & 0 deletionscli/clibase/option.go
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,149 @@ | ||
| package clibase | ||
| import ( | ||
| "os" | ||
| "github.com/hashicorp/go-multierror" | ||
| "github.com/spf13/pflag" | ||
| "golang.org/x/xerrors" | ||
| ) | ||
| // Option is a configuration option for a CLI application. | ||
| type Option struct { | ||
| Name string `json:"name,omitempty"` | ||
| Description string `json:"description,omitempty"` | ||
| // Flag is the long name of the flag used to configure this option. If unset, | ||
| // flag configuring is disabled. | ||
| Flag string `json:"flag,omitempty"` | ||
| // FlagShorthand is the one-character shorthand for the flag. If unset, no | ||
| // shorthand is used. | ||
| FlagShorthand string `json:"flag_shorthand,omitempty"` | ||
| // Env is the environment variable used to configure this option. If unset, | ||
| // environment configuring is disabled. | ||
| Env string `json:"env,omitempty"` | ||
| // YAML is the YAML key used to configure this option. If unset, YAML | ||
| // configuring is disabled. | ||
| YAML string `json:"yaml,omitempty"` | ||
| // Default is parsed into Value if set. | ||
| Default string `json:"default,omitempty"` | ||
| // Value includes the types listed in values.go. | ||
| Value pflag.Value `json:"value,omitempty"` | ||
| // Annotations enable extensions to clibase higher up in the stack. It's useful for | ||
| // help formatting and documentation generation. | ||
| Annotations Annotations `json:"annotations,omitempty"` | ||
| // Group is a group hierarchy that helps organize this option in help, configs | ||
| // and other documentation. | ||
| Group *Group `json:"group,omitempty"` | ||
| // UseInstead is a list of options that should be used instead of this one. | ||
| // The field is used to generate a deprecation warning. | ||
| UseInstead []Option `json:"use_instead,omitempty"` | ||
| Hidden bool `json:"hidden,omitempty"` | ||
| } | ||
| // OptionSet is a group of options that can be applied to a command. | ||
| type OptionSet []Option | ||
| // Add adds the given Options to the OptionSet. | ||
| func (s *OptionSet) Add(opts ...Option) { | ||
| *s = append(*s, opts...) | ||
| } | ||
| // FlagSet returns a pflag.FlagSet for the OptionSet. | ||
| func (s *OptionSet) FlagSet() *pflag.FlagSet { | ||
| fs := pflag.NewFlagSet("", pflag.ContinueOnError) | ||
| for _, opt := range *s { | ||
| if opt.Flag == "" { | ||
| continue | ||
| } | ||
| var noOptDefValue string | ||
| { | ||
| no, ok := opt.Value.(NoOptDefValuer) | ||
| if ok { | ||
| noOptDefValue = no.NoOptDefValue() | ||
| } | ||
| } | ||
| fs.AddFlag(&pflag.Flag{ | ||
| Name: opt.Flag, | ||
| Shorthand: opt.FlagShorthand, | ||
| Usage: opt.Description, | ||
| Value: opt.Value, | ||
| DefValue: "", | ||
| Changed: false, | ||
| Deprecated: "", | ||
| NoOptDefVal: noOptDefValue, | ||
| Hidden: opt.Hidden, | ||
| }) | ||
| } | ||
| fs.Usage = func() { | ||
| _, _ = os.Stderr.WriteString("Override (*FlagSet).Usage() to print help text.\n") | ||
| } | ||
| return fs | ||
| } | ||
| // ParseEnv parses the given environment variables into the OptionSet. | ||
| func (s *OptionSet) ParseEnv(globalPrefix string, environ []string) error { | ||
| var merr *multierror.Error | ||
| // We parse environment variables first instead of using a nested loop to | ||
| // avoid N*M complexity when there are a lot of options and environment | ||
| // variables. | ||
| envs := make(map[string]string) | ||
| for _, v := range EnvsWithPrefix(environ, globalPrefix) { | ||
| envs[v.Name] = v.Value | ||
| } | ||
| for _, opt := range *s { | ||
| if opt.Env == "" { | ||
| continue | ||
| } | ||
| envVal, ok := envs[opt.Env] | ||
| if !ok { | ||
| continue | ||
| } | ||
| if err := opt.Value.Set(envVal); err != nil { | ||
| merr = multierror.Append( | ||
| merr, xerrors.Errorf("parse %q: %w", opt.Name, err), | ||
| ) | ||
| } | ||
| } | ||
| return merr.ErrorOrNil() | ||
| } | ||
| // SetDefaults sets the default values for each Option. | ||
| // It should be called before all parsing (e.g. ParseFlags, ParseEnv). | ||
| func (s *OptionSet) SetDefaults() error { | ||
| var merr *multierror.Error | ||
| for _, opt := range *s { | ||
| if opt.Default == "" { | ||
| continue | ||
| } | ||
| if opt.Value == nil { | ||
| merr = multierror.Append( | ||
| merr, | ||
| xerrors.Errorf( | ||
| "parse %q: no Value field set\nFull opt: %+v", | ||
| opt.Name, opt, | ||
| ), | ||
| ) | ||
| continue | ||
| } | ||
| if err := opt.Value.Set(opt.Default); err != nil { | ||
| merr = multierror.Append( | ||
| merr, xerrors.Errorf("parse %q: %w", opt.Name, err), | ||
| ) | ||
| } | ||
| } | ||
| return merr.ErrorOrNil() | ||
| } |
Oops, something went wrong.
Uh oh!
There was an error while loading.Please reload this page.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.