Skip to content

Commit 735fde8

Browse files
committed
Merge branch 'main' of https://github.com/coder/coder into bq/refactor-users-service
2 parents 93e4e80 + 1a07ee0 commit 735fde8

File tree

186 files changed

+5511
-4714
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

186 files changed

+5511
-4714
lines changed

.github/actions/setup-go/action.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ description: |
44
inputs:
55
version:
66
description: "The Go version to use."
7-
default: "1.20.7"
7+
default: "1.20.8"
88
runs:
99
using: "composite"
1010
steps:

.github/actions/upload-datadog/action.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ runs:
2020
echo "No API key provided, skipping..."
2121
exit 0
2222
fi
23-
npm install -g @datadog/datadog-ci@2.10.0
23+
npm install -g @datadog/datadog-ci@2.21.0
2424
datadog-ci junit upload --service coder ./gotests.xml \
2525
--tags os:${{runner.os}} --tags runner_name:${{runner.name}}
2626
env:

.github/workflows/ci.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ jobs:
220220
with:
221221
# This doesn't need caching. It's super fast anyways!
222222
cache: false
223-
go-version: 1.20.7
223+
go-version: 1.20.8
224224

225225
- name: Install shfmt
226226
run: go install mvdan.cc/sh/v3/cmd/shfmt@v3.5.0

.gitignore

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,14 @@ site/e2e/states/*.json
3030
site/e2e/.auth.json
3131
site/playwright-report/*
3232
site/.swc
33-
site/dist/
3433

3534
# Make target for updating golden files (any dir).
3635
.gen-golden
3736

3837
# Build
39-
/build/
40-
/dist/
41-
site/out/
38+
build/
39+
dist/
40+
out/
4241

4342
# Bundle analysis
4443
site/stats/

.prettierignore

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,14 @@ site/e2e/states/*.json
3333
site/e2e/.auth.json
3434
site/playwright-report/*
3535
site/.swc
36-
site/dist/
3736

3837
# Make target for updating golden files (any dir).
3938
.gen-golden
4039

4140
# Build
42-
/build/
43-
/dist/
44-
site/out/
41+
build/
42+
dist/
43+
out/
4544

4645
# Bundle analysis
4746
site/stats/

.vscode/settings.json

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
"enterprisemeta",
4040
"errgroup",
4141
"eventsourcemock",
42+
"externalauth",
4243
"Failf",
4344
"fatih",
4445
"Formik",
@@ -186,9 +187,6 @@
186187
]
187188
},
188189
"eslint.workingDirectories": ["./site"],
189-
"files.exclude": {
190-
"**/node_modules": true
191-
},
192190
"search.exclude": {
193191
"**.pb.go": true,
194192
"**/*.gen.json": true,
@@ -198,7 +196,11 @@
198196
"docs/api/*.md": true,
199197
"docs/templates/*.md": true,
200198
"LICENSE": true,
201-
"scripts/metricsdocgen/metrics": true
199+
"scripts/metricsdocgen/metrics": true,
200+
"site/out/**": true,
201+
"site/storybook-static/**": true,
202+
"**.map": true,
203+
"pnpm-lock.yaml": true
202204
},
203205
// Ensure files always have a newline.
204206
"files.insertFinalNewline": true,

Makefile

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -107,9 +107,9 @@ endif
107107

108108

109109
clean:
110-
rm -rf build site/out
111-
mkdir -p build site/out/bin
112-
git restore site/out
110+
rm -rf build/ site/build/ site/out/
111+
mkdir -p build/ site/out/bin/
112+
git restore site/out/
113113
.PHONY: clean
114114

115115
build-slim: $(CODER_SLIM_BINARIES)
@@ -542,12 +542,11 @@ site/src/api/typesGenerated.ts: scripts/apitypings/main.go $(shell find ./coders
542542
cd site
543543
pnpm run format:types ./src/api/typesGenerated.ts
544544

545-
site/e2e/provisionerGenerated.ts:
545+
site/e2e/provisionerGenerated.ts: provisionerd/proto/provisionerd.pb.go provisionersdk/proto/provisioner.pb.go
546546
cd site
547547
../scripts/pnpm_install.sh
548548
pnpm run gen:provisioner
549549

550-
551550
examples/examples.gen.json: scripts/examplegen/main.go examples/examples.go $(shell find ./examples/templates)
552551
go run ./scripts/examplegen/main.go > examples/examples.gen.json
553552

cli/clibase/option.go

Lines changed: 120 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package clibase
22

33
import (
4+
"bytes"
5+
"encoding/json"
46
"os"
57
"strings"
68

@@ -65,6 +67,20 @@ type Option struct {
6567
ValueSource ValueSource `json:"value_source,omitempty"`
6668
}
6769

70+
// optionNoMethods is just a wrapper around Option so we can defer to the
71+
// default json.Unmarshaler behavior.
72+
type optionNoMethods Option
73+
74+
func (o *Option) UnmarshalJSON(data []byte) error {
75+
// If an option has no values, we have no idea how to unmarshal it.
76+
// So just discard the json data.
77+
if o.Value == nil {
78+
o.Value = &DiscardValue
79+
}
80+
81+
return json.Unmarshal(data, (*optionNoMethods)(o))
82+
}
83+
6884
func (o Option) YAMLPath() string {
6985
if o.YAML == "" {
7086
return ""
@@ -79,15 +95,101 @@ func (o Option) YAMLPath() string {
7995
// OptionSet is a group of options that can be applied to a command.
8096
type OptionSet []Option
8197

98+
// UnmarshalJSON implements json.Unmarshaler for OptionSets. Options have an
99+
// interface Value type that cannot handle unmarshalling because the types cannot
100+
// be inferred. Since it is a slice, instantiating the Options first does not
101+
// help.
102+
//
103+
// However, we typically do instantiate the slice to have the correct types.
104+
// So this unmarshaller will attempt to find the named option in the existing
105+
// set, if it cannot, the value is discarded. If the option exists, the value
106+
// is unmarshalled into the existing option, and replaces the existing option.
107+
//
108+
// The value is discarded if it's type cannot be inferred. This behavior just
109+
// feels "safer", although it should never happen if the correct option set
110+
// is passed in. The situation where this could occur is if a client and server
111+
// are on different versions with different options.
112+
func (optSet *OptionSet) UnmarshalJSON(data []byte) error {
113+
dec := json.NewDecoder(bytes.NewBuffer(data))
114+
// Should be a json array, so consume the starting open bracket.
115+
t, err := dec.Token()
116+
if err != nil {
117+
return xerrors.Errorf("read array open bracket: %w", err)
118+
}
119+
if t != json.Delim('[') {
120+
return xerrors.Errorf("expected array open bracket, got %q", t)
121+
}
122+
123+
// As long as json elements exist, consume them. The counter is used for
124+
// better errors.
125+
var i int
126+
OptionSetDecodeLoop:
127+
for dec.More() {
128+
var opt Option
129+
// jValue is a placeholder value that allows us to capture the
130+
// raw json for the value to attempt to unmarshal later.
131+
var jValue jsonValue
132+
opt.Value = &jValue
133+
err := dec.Decode(&opt)
134+
if err != nil {
135+
return xerrors.Errorf("decode %d option: %w", i, err)
136+
}
137+
// This counter is used to contextualize errors to show which element of
138+
// the array we failed to decode. It is only used in the error above, as
139+
// if the above works, we can instead use the Option.Name which is more
140+
// descriptive and useful. So increment here for the next decode.
141+
i++
142+
143+
// Try to see if the option already exists in the option set.
144+
// If it does, just update the existing option.
145+
for optIndex, have := range *optSet {
146+
if have.Name == opt.Name {
147+
if jValue != nil {
148+
err := json.Unmarshal(jValue, &(*optSet)[optIndex].Value)
149+
if err != nil {
150+
return xerrors.Errorf("decode option %q value: %w", have.Name, err)
151+
}
152+
// Set the opt's value
153+
opt.Value = (*optSet)[optIndex].Value
154+
} else {
155+
// Hopefully the user passed empty values in the option set. There is no easy way
156+
// to tell, and if we do not do this, it breaks json.Marshal if we do it again on
157+
// this new option set.
158+
opt.Value = (*optSet)[optIndex].Value
159+
}
160+
// Override the existing.
161+
(*optSet)[optIndex] = opt
162+
// Go to the next option to decode.
163+
continue OptionSetDecodeLoop
164+
}
165+
}
166+
167+
// If the option doesn't exist, the value will be discarded.
168+
// We do this because we cannot infer the type of the value.
169+
opt.Value = DiscardValue
170+
*optSet = append(*optSet, opt)
171+
}
172+
173+
t, err = dec.Token()
174+
if err != nil {
175+
return xerrors.Errorf("read array close bracket: %w", err)
176+
}
177+
if t != json.Delim(']') {
178+
return xerrors.Errorf("expected array close bracket, got %q", t)
179+
}
180+
181+
return nil
182+
}
183+
82184
// Add adds the given Options to the OptionSet.
83-
func (s *OptionSet) Add(opts ...Option) {
84-
*s = append(*s, opts...)
185+
func (optSet *OptionSet) Add(opts ...Option) {
186+
*optSet = append(*optSet, opts...)
85187
}
86188

87189
// Filter will only return options that match the given filter. (return true)
88-
func (s OptionSet) Filter(filter func(opt Option) bool) OptionSet {
190+
func (optSet OptionSet) Filter(filter func(opt Option) bool) OptionSet {
89191
cpy := make(OptionSet, 0)
90-
for _, opt := range s {
192+
for _, opt := range optSet {
91193
if filter(opt) {
92194
cpy = append(cpy, opt)
93195
}
@@ -96,13 +198,13 @@ func (s OptionSet) Filter(filter func(opt Option) bool) OptionSet {
96198
}
97199

98200
// FlagSet returns a pflag.FlagSet for the OptionSet.
99-
func (s *OptionSet) FlagSet() *pflag.FlagSet {
100-
if s == nil {
201+
func (optSet *OptionSet) FlagSet() *pflag.FlagSet {
202+
if optSet == nil {
101203
return &pflag.FlagSet{}
102204
}
103205

104206
fs := pflag.NewFlagSet("", pflag.ContinueOnError)
105-
for _, opt := range *s {
207+
for _, opt := range *optSet {
106208
if opt.Flag == "" {
107209
continue
108210
}
@@ -139,8 +241,8 @@ func (s *OptionSet) FlagSet() *pflag.FlagSet {
139241

140242
// ParseEnv parses the given environment variables into the OptionSet.
141243
// Use EnvsWithPrefix to filter out prefixes.
142-
func (s *OptionSet) ParseEnv(vs []EnvVar) error {
143-
if s == nil {
244+
func (optSet *OptionSet) ParseEnv(vs []EnvVar) error {
245+
if optSet == nil {
144246
return nil
145247
}
146248

@@ -154,7 +256,7 @@ func (s *OptionSet) ParseEnv(vs []EnvVar) error {
154256
envs[v.Name] = v.Value
155257
}
156258

157-
for i, opt := range *s {
259+
for i, opt := range *optSet {
158260
if opt.Env == "" {
159261
continue
160262
}
@@ -172,7 +274,7 @@ func (s *OptionSet) ParseEnv(vs []EnvVar) error {
172274
continue
173275
}
174276

175-
(*s)[i].ValueSource = ValueSourceEnv
277+
(*optSet)[i].ValueSource = ValueSourceEnv
176278
if err := opt.Value.Set(envVal); err != nil {
177279
merr = multierror.Append(
178280
merr, xerrors.Errorf("parse %q: %w", opt.Name, err),
@@ -185,14 +287,14 @@ func (s *OptionSet) ParseEnv(vs []EnvVar) error {
185287

186288
// SetDefaults sets the default values for each Option, skipping values
187289
// that already have a value source.
188-
func (s *OptionSet) SetDefaults() error {
189-
if s == nil {
290+
func (optSet *OptionSet) SetDefaults() error {
291+
if optSet == nil {
190292
return nil
191293
}
192294

193295
var merr *multierror.Error
194296

195-
for i, opt := range *s {
297+
for i, opt := range *optSet {
196298
// Skip values that may have already been set by the user.
197299
if opt.ValueSource != ValueSourceNone {
198300
continue
@@ -212,7 +314,7 @@ func (s *OptionSet) SetDefaults() error {
212314
)
213315
continue
214316
}
215-
(*s)[i].ValueSource = ValueSourceDefault
317+
(*optSet)[i].ValueSource = ValueSourceDefault
216318
if err := opt.Value.Set(opt.Default); err != nil {
217319
merr = multierror.Append(
218320
merr, xerrors.Errorf("parse %q: %w", opt.Name, err),
@@ -224,9 +326,9 @@ func (s *OptionSet) SetDefaults() error {
224326

225327
// ByName returns the Option with the given name, or nil if no such option
226328
// exists.
227-
func (s *OptionSet) ByName(name string) *Option {
228-
for i := range *s {
229-
opt := &(*s)[i]
329+
func (optSet *OptionSet) ByName(name string) *Option {
330+
for i := range *optSet {
331+
opt := &(*optSet)[i]
230332
if opt.Name == name {
231333
return opt
232334
}

0 commit comments

Comments
 (0)