diff --git a/cli/deployment/config.go b/cli/deployment/config.go index c35b9abd63..1887fbac71 100644 --- a/cli/deployment/config.go +++ b/cli/deployment/config.go @@ -367,6 +367,11 @@ func newConfig() *codersdk.DeploymentConfig { Default: 10 * time.Minute, }, }, + Experimental: &codersdk.DeploymentConfigField[bool]{ + Name: "Experimental", + Usage: "Enable experimental features. Experimental features are not ready for production.", + Flag: "experimental", + }, } } diff --git a/cli/root.go b/cli/root.go index 34d9cb1473..4bce0a3d26 100644 --- a/cli/root.go +++ b/cli/root.go @@ -50,12 +50,10 @@ const ( varNoFeatureWarning = "no-feature-warning" varForceTty = "force-tty" varVerbose = "verbose" - varExperimental = "experimental" notLoggedInMessage = "You are not logged in. Try logging in using 'coder login '." envNoVersionCheck = "CODER_NO_VERSION_WARNING" envNoFeatureWarning = "CODER_NO_FEATURE_WARNING" - envExperimental = "CODER_EXPERIMENTAL" envSessionToken = "CODER_SESSION_TOKEN" envURL = "CODER_URL" ) @@ -217,7 +215,6 @@ func Root(subcommands []*cobra.Command) *cobra.Command { cmd.PersistentFlags().Bool(varNoOpen, false, "Block automatically opening URLs in the browser.") _ = cmd.PersistentFlags().MarkHidden(varNoOpen) cliflag.Bool(cmd.PersistentFlags(), varVerbose, "v", "CODER_VERBOSE", false, "Enable verbose output.") - cliflag.Bool(cmd.PersistentFlags(), varExperimental, "", envExperimental, false, "Enable experimental features. Experimental features are not ready for production.") return cmd } @@ -643,19 +640,3 @@ func (h *headerTransport) RoundTrip(req *http.Request) (*http.Response, error) { } return h.transport.RoundTrip(req) } - -// ExperimentalEnabled returns if the experimental feature flag is enabled. -func ExperimentalEnabled(cmd *cobra.Command) bool { - enabled, _ := cmd.Flags().GetBool(varExperimental) - return enabled -} - -// EnsureExperimental will ensure that the experimental feature flag is set if the given flag is set. -func EnsureExperimental(cmd *cobra.Command, name string) error { - _, set := cliflag.IsSet(cmd, name) - if set && !ExperimentalEnabled(cmd) { - return xerrors.Errorf("flag %s is set but requires flag --experimental or environment variable CODER_EXPERIMENTAL=true.", name) - } - - return nil -} diff --git a/cli/root_test.go b/cli/root_test.go index 05768fcae7..1ff3d18d36 100644 --- a/cli/root_test.go +++ b/cli/root_test.go @@ -17,7 +17,6 @@ import ( "github.com/coder/coder/buildinfo" "github.com/coder/coder/cli" - "github.com/coder/coder/cli/cliflag" "github.com/coder/coder/cli/clitest" "github.com/coder/coder/codersdk" "github.com/coder/coder/testutil" @@ -230,19 +229,4 @@ func TestRoot(t *testing.T) { // This won't succeed, because we're using the login cmd to assert requests. _ = cmd.Execute() }) - - t.Run("Experimental", func(t *testing.T) { - t.Parallel() - - cmd, _ := clitest.New(t, "--experimental") - err := cmd.Execute() - require.NoError(t, err) - require.True(t, cli.ExperimentalEnabled(cmd)) - - cmd, _ = clitest.New(t, "help", "--verbose") - _ = cmd.Execute() - _, set := cliflag.IsSet(cmd, "verbose") - require.True(t, set) - require.ErrorContains(t, cli.EnsureExperimental(cmd, "verbose"), "--experimental") - }) } diff --git a/cli/server.go b/cli/server.go index ca2bddefe0..1685e668cd 100644 --- a/cli/server.go +++ b/cli/server.go @@ -357,7 +357,6 @@ func Server(vip *viper.Viper, newAPI func(context.Context, *coderd.Options) (*co AutoImportTemplates: validatedAutoImportTemplates, MetricsCacheRefreshInterval: cfg.MetricsCacheRefreshInterval.Value, AgentStatsRefreshInterval: cfg.AgentStatRefreshInterval.Value, - Experimental: ExperimentalEnabled(cmd), DeploymentConfig: cfg, PrometheusRegistry: prometheus.NewRegistry(), } diff --git a/cli/testdata/coder_--help.golden b/cli/testdata/coder_--help.golden index 567875fe1c..da0dc9b461 100644 --- a/cli/testdata/coder_--help.golden +++ b/cli/testdata/coder_--help.golden @@ -44,9 +44,6 @@ Workspace Commands: update Update a workspace Flags: - --experimental Enable experimental features. Experimental features are not - ready for production. - Consumes $CODER_EXPERIMENTAL --global-config coder Path to the global coder config directory. Consumes $CODER_CONFIG_DIR (default "/tmp/coder-cli-test-config") --header stringArray HTTP headers added to all requests. Provide as "Key=Value". diff --git a/cli/testdata/coder_server_--help.golden b/cli/testdata/coder_server_--help.golden index ba82ae3681..40016c3efc 100644 --- a/cli/testdata/coder_server_--help.golden +++ b/cli/testdata/coder_server_--help.golden @@ -52,6 +52,10 @@ Flags: Consumes $CODER_DERP_SERVER_STUN_ADDRESSES (default [stun.l.google.com:19302]) + --experimental Enable experimental features. + Experimental features are not ready for + production. + Consumes $CODER_EXPERIMENTAL -h, --help help for server --oauth2-github-allow-signups Whether new users can sign up with GitHub. @@ -190,9 +194,6 @@ Flags: Consumes $CODER_WILDCARD_ACCESS_URL Global Flags: - --experimental Enable experimental features. Experimental features are not - ready for production. - Consumes $CODER_EXPERIMENTAL --global-config coder Path to the global coder config directory. Consumes $CODER_CONFIG_DIR (default "/tmp/coder-cli-test-config") --header stringArray HTTP headers added to all requests. Provide as "Key=Value". diff --git a/coderd/coderdtest/coderdtest.go b/coderd/coderdtest/coderdtest.go index 6758509635..a24a3f896c 100644 --- a/coderd/coderdtest/coderdtest.go +++ b/coderd/coderdtest/coderdtest.go @@ -35,6 +35,7 @@ import ( "github.com/google/uuid" "github.com/moby/moby/pkg/namesgenerator" "github.com/spf13/afero" + "github.com/spf13/pflag" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "golang.org/x/oauth2" @@ -49,6 +50,8 @@ import ( "cdr.dev/slog" "cdr.dev/slog/sloggers/slogtest" + "github.com/coder/coder/cli/config" + "github.com/coder/coder/cli/deployment" "github.com/coder/coder/coderd" "github.com/coder/coder/coderd/audit" "github.com/coder/coder/coderd/autobuild/executor" @@ -159,6 +162,9 @@ func NewOptions(t *testing.T, options *Options) (func(http.Handler), context.Can if options.Database == nil { options.Database, options.Pubsub = dbtestutil.NewDB(t) } + if options.DeploymentConfig == nil { + options.DeploymentConfig = DeploymentConfig(t) + } ctx, cancelFunc := context.WithCancel(context.Background()) lifecycleExecutor := executor.New( @@ -236,7 +242,6 @@ func NewOptions(t *testing.T, options *Options) (func(http.Handler), context.Can CacheDir: t.TempDir(), Database: options.Database, Pubsub: options.Pubsub, - Experimental: options.Experimental, GitAuthConfigs: options.GitAuthConfigs, Auditor: options.Auditor, @@ -903,3 +908,13 @@ d8h4Ht09E+f3nhTEc87mODkl7WJZpHL6V2sORfeq/eIkds+H6CJ4hy5w/bSw8tjf sz9Di8sGIaUbLZI2rd0CQQCzlVwEtRtoNCyMJTTrkgUuNufLP19RZ5FpyXxBO5/u QastnN77KfUwdj3SJt44U/uh1jAIv4oSLBr8HYUkbnI8 -----END RSA PRIVATE KEY-----` + +func DeploymentConfig(t *testing.T) *codersdk.DeploymentConfig { + vip := deployment.NewViper() + fs := pflag.NewFlagSet(randomUsername(), pflag.ContinueOnError) + fs.String(config.FlagName, randomUsername(), randomUsername()) + cfg, err := deployment.Config(fs, vip) + require.NoError(t, err) + + return cfg +} diff --git a/coderd/deploymentconfig_test.go b/coderd/deploymentconfig_test.go index a0031ac6c3..5389151d2d 100644 --- a/coderd/deploymentconfig_test.go +++ b/coderd/deploymentconfig_test.go @@ -4,11 +4,8 @@ import ( "context" "testing" - "github.com/spf13/pflag" "github.com/stretchr/testify/require" - "github.com/coder/coder/cli/config" - "github.com/coder/coder/cli/deployment" "github.com/coder/coder/coderd/coderdtest" "github.com/coder/coder/testutil" ) @@ -18,11 +15,7 @@ func TestDeploymentConfig(t *testing.T) { hi := "hi" ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() - vip := deployment.NewViper() - fs := pflag.NewFlagSet("test", pflag.ContinueOnError) - fs.String(config.FlagName, hi, "usage") - cfg, err := deployment.Config(fs, vip) - require.NoError(t, err) + cfg := coderdtest.DeploymentConfig(t) // values should be returned cfg.AccessURL.Value = hi // values should not be returned diff --git a/codersdk/deploymentconfig.go b/codersdk/deploymentconfig.go index 550890a03e..7d6ed987f8 100644 --- a/codersdk/deploymentconfig.go +++ b/codersdk/deploymentconfig.go @@ -39,6 +39,7 @@ type DeploymentConfig struct { SCIMAPIKey *DeploymentConfigField[string] `json:"scim_api_key" typescript:",notnull"` UserWorkspaceQuota *DeploymentConfigField[int] `json:"user_workspace_quota" typescript:",notnull"` Provisioner *ProvisionerConfig `json:"provisioner" typescript:",notnull"` + Experimental *DeploymentConfigField[bool] `json:"experimental" typescript:",notnull"` } type DERP struct { diff --git a/enterprise/coderd/coderd.go b/enterprise/coderd/coderd.go index adebd11364..0266455691 100644 --- a/enterprise/coderd/coderd.go +++ b/enterprise/coderd/coderd.go @@ -232,7 +232,7 @@ func (api *API) updateEntitlements(ctx context.Context) error { if err != nil { return err } - entitlements.Experimental = api.Experimental + entitlements.Experimental = api.DeploymentConfig.Experimental.Value featureChanged := func(featureName string) (changed bool, enabled bool) { if api.entitlements.Features == nil { diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index 55ac336141..b5b9297a61 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -303,6 +303,7 @@ export interface DeploymentConfig { readonly scim_api_key: DeploymentConfigField readonly user_workspace_quota: DeploymentConfigField readonly provisioner: ProvisionerConfig + readonly experimental: DeploymentConfigField } // From codersdk/deploymentconfig.go