mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
chore: move app URL parsing to its own package (#11651)
* chore: move app url parsing to it's own package
This commit is contained in:
@@ -59,6 +59,28 @@ func (i *Validator[T]) Type() string {
|
||||
return i.Value.Type()
|
||||
}
|
||||
|
||||
func (i *Validator[T]) MarshalYAML() (interface{}, error) {
|
||||
m, ok := any(i.Value).(yaml.Marshaler)
|
||||
if !ok {
|
||||
return i.Value, nil
|
||||
}
|
||||
return m.MarshalYAML()
|
||||
}
|
||||
|
||||
func (i *Validator[T]) UnmarshalYAML(n *yaml.Node) error {
|
||||
return n.Decode(i.Value)
|
||||
}
|
||||
|
||||
func (i *Validator[T]) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(i.Value)
|
||||
}
|
||||
|
||||
func (i *Validator[T]) UnmarshalJSON(b []byte) error {
|
||||
return json.Unmarshal(b, i.Value)
|
||||
}
|
||||
|
||||
func (i *Validator[T]) Underlying() pflag.Value { return i.Value }
|
||||
|
||||
// values.go contains a standard set of value types that can be used as
|
||||
// Option Values.
|
||||
|
||||
@@ -378,6 +400,7 @@ func (s *Struct[T]) String() string {
|
||||
return string(byt)
|
||||
}
|
||||
|
||||
// nolint:revive
|
||||
func (s *Struct[T]) MarshalYAML() (interface{}, error) {
|
||||
var n yaml.Node
|
||||
err := n.Encode(s.Value)
|
||||
@@ -387,6 +410,7 @@ func (s *Struct[T]) MarshalYAML() (interface{}, error) {
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// nolint:revive
|
||||
func (s *Struct[T]) UnmarshalYAML(n *yaml.Node) error {
|
||||
// HACK: for compatibility with flags, we use nil slices instead of empty
|
||||
// slices. In most cases, nil slices and empty slices are treated
|
||||
@@ -403,10 +427,12 @@ func (s *Struct[T]) Type() string {
|
||||
return fmt.Sprintf("struct[%T]", s.Value)
|
||||
}
|
||||
|
||||
// nolint:revive
|
||||
func (s *Struct[T]) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(s.Value)
|
||||
}
|
||||
|
||||
// nolint:revive
|
||||
func (s *Struct[T]) UnmarshalJSON(b []byte) error {
|
||||
return json.Unmarshal(b, &s.Value)
|
||||
}
|
||||
|
||||
+5
-1
@@ -6,6 +6,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/mitchellh/go-wordwrap"
|
||||
"github.com/spf13/pflag"
|
||||
"golang.org/x/xerrors"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
@@ -74,13 +75,16 @@ func (optSet *OptionSet) MarshalYAML() (any, error) {
|
||||
Value: opt.YAML,
|
||||
HeadComment: comment,
|
||||
}
|
||||
|
||||
_, isValidator := opt.Value.(interface{ Underlying() pflag.Value })
|
||||
var valueNode yaml.Node
|
||||
if opt.Value == nil {
|
||||
valueNode = yaml.Node{
|
||||
Kind: yaml.ScalarNode,
|
||||
Value: "null",
|
||||
}
|
||||
} else if m, ok := opt.Value.(yaml.Marshaler); ok {
|
||||
} else if m, ok := opt.Value.(yaml.Marshaler); ok && !isValidator {
|
||||
// Validators do a wrap, and should be handled by the else statement.
|
||||
v, err := m.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf(
|
||||
|
||||
+6
-7
@@ -53,8 +53,6 @@ import (
|
||||
"gopkg.in/yaml.v3"
|
||||
"tailscale.com/tailcfg"
|
||||
|
||||
"github.com/coder/pretty"
|
||||
|
||||
"cdr.dev/slog"
|
||||
"cdr.dev/slog/sloggers/sloghuman"
|
||||
"github.com/coder/coder/v2/buildinfo"
|
||||
@@ -75,7 +73,6 @@ import (
|
||||
"github.com/coder/coder/v2/coderd/devtunnel"
|
||||
"github.com/coder/coder/v2/coderd/externalauth"
|
||||
"github.com/coder/coder/v2/coderd/gitsshkey"
|
||||
"github.com/coder/coder/v2/coderd/httpapi"
|
||||
"github.com/coder/coder/v2/coderd/httpmw"
|
||||
"github.com/coder/coder/v2/coderd/oauthpki"
|
||||
"github.com/coder/coder/v2/coderd/prometheusmetrics"
|
||||
@@ -89,6 +86,7 @@ import (
|
||||
"github.com/coder/coder/v2/coderd/util/slice"
|
||||
stringutil "github.com/coder/coder/v2/coderd/util/strings"
|
||||
"github.com/coder/coder/v2/coderd/workspaceapps"
|
||||
"github.com/coder/coder/v2/coderd/workspaceapps/appurl"
|
||||
"github.com/coder/coder/v2/codersdk"
|
||||
"github.com/coder/coder/v2/codersdk/drpc"
|
||||
"github.com/coder/coder/v2/cryptorand"
|
||||
@@ -99,6 +97,7 @@ import (
|
||||
"github.com/coder/coder/v2/provisionersdk"
|
||||
sdkproto "github.com/coder/coder/v2/provisionersdk/proto"
|
||||
"github.com/coder/coder/v2/tailnet"
|
||||
"github.com/coder/pretty"
|
||||
"github.com/coder/retry"
|
||||
"github.com/coder/wgtunnel/tunnelsdk"
|
||||
)
|
||||
@@ -434,11 +433,11 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
|
||||
|
||||
if vals.WildcardAccessURL.String() == "" {
|
||||
// Suffixed wildcard access URL.
|
||||
u, err := url.Parse(fmt.Sprintf("*--%s", tunnel.URL.Hostname()))
|
||||
wu := fmt.Sprintf("*--%s", tunnel.URL.Hostname())
|
||||
err = vals.WildcardAccessURL.Set(wu)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("parse wildcard url: %w", err)
|
||||
return xerrors.Errorf("set wildcard access url %q: %w", wu, err)
|
||||
}
|
||||
vals.WildcardAccessURL = clibase.URL(*u)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -513,7 +512,7 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
|
||||
appHostname := vals.WildcardAccessURL.String()
|
||||
var appHostnameRegex *regexp.Regexp
|
||||
if appHostname != "" {
|
||||
appHostnameRegex, err = httpapi.CompileHostnamePattern(appHostname)
|
||||
appHostnameRegex, err = appurl.CompileHostnamePattern(appHostname)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("parse wildcard access URL %q: %w", appHostname, err)
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/spf13/pflag"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.uber.org/goleak"
|
||||
@@ -1552,6 +1553,18 @@ func TestServer(t *testing.T) {
|
||||
// ValueSource is not going to be correct on the `want`, so just
|
||||
// match that field.
|
||||
wantConfig.Options[i].ValueSource = gotConfig.Options[i].ValueSource
|
||||
|
||||
// If there is a wrapped value with a validator, unwrap it.
|
||||
// The underlying doesn't compare well since it compares go pointers,
|
||||
// and not the actual value.
|
||||
if validator, isValidator := wantConfig.Options[i].Value.(interface{ Underlying() pflag.Value }); isValidator {
|
||||
wantConfig.Options[i].Value = validator.Underlying()
|
||||
}
|
||||
|
||||
if validator, isValidator := gotConfig.Options[i].Value.(interface{ Underlying() pflag.Value }); isValidator {
|
||||
gotConfig.Options[i].Value = validator.Underlying()
|
||||
}
|
||||
|
||||
assert.Equal(
|
||||
t, wantConfig.Options[i],
|
||||
gotConfig.Options[i],
|
||||
|
||||
+1
-1
@@ -167,7 +167,7 @@ NETWORKING OPTIONS:
|
||||
--secure-auth-cookie bool, $CODER_SECURE_AUTH_COOKIE
|
||||
Controls if the 'Secure' property is set on browser session cookies.
|
||||
|
||||
--wildcard-access-url url, $CODER_WILDCARD_ACCESS_URL
|
||||
--wildcard-access-url string, $CODER_WILDCARD_ACCESS_URL
|
||||
Specifies the wildcard hostname to use for workspace applications in
|
||||
the form "*.example.com".
|
||||
|
||||
|
||||
+2
-2
@@ -4,8 +4,8 @@ networking:
|
||||
accessURL:
|
||||
# Specifies the wildcard hostname to use for workspace applications in the form
|
||||
# "*.example.com".
|
||||
# (default: <unset>, type: url)
|
||||
wildcardAccessURL:
|
||||
# (default: <unset>, type: string)
|
||||
wildcardAccessURL: ""
|
||||
# Specifies the custom docs URL.
|
||||
# (default: <unset>, type: url)
|
||||
docsURL:
|
||||
|
||||
Reference in New Issue
Block a user