Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit d892427

Browse files
authored
fix: do not warn on valid known experiments (#18514)
Fixes #18024 * drive-by: renames `handleExperimentsSafe` to `handleExperimentsAvailable` to better match semantics * defines list of `codersdk.ExperimentsKnown` and updates `ReadExperiments` to log on invalid experiments * typescript-ignores `codersdk.Experiments` so apitypings generates a valid enum list of possible values of experiment * updates OverviewPageView to distinguish between known 'hidden' experiments and unknown 'invalid' experiments
1 parent 4f98fd4 commit d892427

File tree

10 files changed

+54
-21
lines changed

10 files changed

+54
-21
lines changed

coderd/coderd.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -972,7 +972,7 @@ func New(options *Options) *API {
972972
})
973973
r.Route("/experiments", func(r chi.Router) {
974974
r.Use(apiKeyMiddleware)
975-
r.Get("/available", handleExperimentsSafe)
975+
r.Get("/available", handleExperimentsAvailable)
976976
r.Get("/", api.handleExperimentsGet)
977977
})
978978
r.Get("/updatecheck", api.updateCheck)
@@ -1895,7 +1895,9 @@ func ReadExperiments(log slog.Logger, raw []string) codersdk.Experiments {
18951895
exps = append(exps, codersdk.ExperimentsSafe...)
18961896
default:
18971897
ex := codersdk.Experiment(strings.ToLower(v))
1898-
if !slice.Contains(codersdk.ExperimentsSafe, ex) {
1898+
if !slice.Contains(codersdk.ExperimentsKnown, ex) {
1899+
log.Warn(context.Background(), "ignoring unknown experiment", slog.F("experiment", ex))
1900+
} else if !slice.Contains(codersdk.ExperimentsSafe, ex) {
18991901
log.Warn(context.Background(), "🐉 HERE BE DRAGONS: opting into hidden experiment", slog.F("experiment", ex))
19001902
}
19011903
exps = append(exps, ex)

coderd/experiments.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ func (api *API) handleExperimentsGet(rw http.ResponseWriter, r *http.Request) {
2626
// @Tags General
2727
// @Success 200 {array} codersdk.Experiment
2828
// @Router /experiments/available [get]
29-
func handleExperimentsSafe(rw http.ResponseWriter, r *http.Request) {
29+
func handleExperimentsAvailable(rw http.ResponseWriter, r *http.Request) {
3030
ctx := r.Context()
3131
httpapi.Write(ctx, rw, http.StatusOK, codersdk.AvailableExperiments{
3232
Safe: codersdk.ExperimentsSafe,

codersdk/deployment.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3372,6 +3372,18 @@ const (
33723372
ExperimentAITasks Experiment = "ai-tasks" // Enables the new AI tasks feature.
33733373
)
33743374

3375+
// ExperimentsKnown should include all experiments defined above.
3376+
var ExperimentsKnown = Experiments{
3377+
ExperimentExample,
3378+
ExperimentAutoFillParameters,
3379+
ExperimentNotifications,
3380+
ExperimentWorkspaceUsage,
3381+
ExperimentWebPush,
3382+
ExperimentWorkspacePrebuilds,
3383+
ExperimentAgenticChat,
3384+
ExperimentAITasks,
3385+
}
3386+
33753387
// ExperimentsSafe should include all experiments that are safe for
33763388
// users to opt-in to via --experimental='*'.
33773389
// Experiments that are not ready for consumption by all users should
@@ -3384,6 +3396,9 @@ var ExperimentsSafe = Experiments{
33843396
// Multiple experiments may be enabled at the same time.
33853397
// Experiments are not safe for production use, and are not guaranteed to
33863398
// be backwards compatible. They may be removed or renamed at any time.
3399+
// The below typescript-ignore annotation allows our typescript generator
3400+
// to generate an enum list, which is used in the frontend.
3401+
// @typescript-ignore Experiments
33873402
type Experiments []Experiment
33883403

33893404
// Returns a list of experiments that are enabled for the deployment.

site/src/api/queries/experiments.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import { API } from "api/api";
2-
import type { Experiments } from "api/typesGenerated";
2+
import { type Experiment, Experiments } from "api/typesGenerated";
33
import type { MetadataState } from "hooks/useEmbeddedMetadata";
44
import { cachedQuery } from "./util";
55

66
const experimentsKey = ["experiments"] as const;
77

8-
export const experiments = (metadata: MetadataState<Experiments>) => {
8+
export const experiments = (metadata: MetadataState<Experiment[]>) => {
99
return cachedQuery({
1010
metadata,
1111
queryKey: experimentsKey,
@@ -19,3 +19,7 @@ export const availableExperiments = () => {
1919
queryFn: async () => API.getAvailableExperiments(),
2020
};
2121
};
22+
23+
export const isKnownExperiment = (experiment: string): boolean => {
24+
return Experiments.includes(experiment as Experiment);
25+
};

site/src/api/typesGenerated.ts

Lines changed: 10 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

site/src/hooks/useEmbeddedMetadata.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type {
22
AppearanceConfig,
33
BuildInfoResponse,
44
Entitlements,
5-
Experiments,
5+
Experiment,
66
Region,
77
User,
88
UserAppearanceSettings,
@@ -24,7 +24,7 @@ export const DEFAULT_METADATA_KEY = "property";
2424
*/
2525
type AvailableMetadata = Readonly<{
2626
user: User;
27-
experiments: Experiments;
27+
experiments: Experiment[];
2828
appearance: AppearanceConfig;
2929
userAppearance: UserAppearanceSettings;
3030
entitlements: Entitlements;
@@ -89,7 +89,7 @@ export class MetadataManager implements MetadataManagerApi {
8989
userAppearance:
9090
this.registerValue<UserAppearanceSettings>("userAppearance"),
9191
entitlements: this.registerValue<Entitlements>("entitlements"),
92-
experiments: this.registerValue<Experiments>("experiments"),
92+
experiments: this.registerValue<Experiment[]>("experiments"),
9393
"build-info": this.registerValue<BuildInfoResponse>("build-info"),
9494
regions: this.registerRegionValue(),
9595
tasksTabVisible: this.registerValue<boolean>("tasksTabVisible"),

site/src/modules/dashboard/DashboardProvider.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { organizations } from "api/queries/organizations";
55
import type {
66
AppearanceConfig,
77
Entitlements,
8-
Experiments,
8+
Experiment,
99
Organization,
1010
} from "api/typesGenerated";
1111
import { ErrorAlert } from "components/Alert/ErrorAlert";
@@ -19,7 +19,7 @@ import { selectFeatureVisibility } from "./entitlements";
1919

2020
export interface DashboardValue {
2121
entitlements: Entitlements;
22-
experiments: Experiments;
22+
experiments: Experiment[];
2323
appearance: AppearanceConfig;
2424
organizations: readonly Organization[];
2525
showOrganizations: boolean;

site/src/pages/DeploymentSettingsPage/OverviewPage/OverviewPage.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
import { deploymentDAUs } from "api/queries/deployment";
2-
import { availableExperiments, experiments } from "api/queries/experiments";
2+
import {
3+
availableExperiments,
4+
experiments,
5+
isKnownExperiment,
6+
} from "api/queries/experiments";
37
import { useEmbeddedMetadata } from "hooks/useEmbeddedMetadata";
48
import { useDeploymentConfig } from "modules/management/DeploymentConfigProvider";
59
import type { FC } from "react";
@@ -18,7 +22,7 @@ const OverviewPage: FC = () => {
1822
const safeExperiments = safeExperimentsQuery.data?.safe ?? [];
1923
const invalidExperiments =
2024
enabledExperimentsQuery.data?.filter((exp) => {
21-
return !safeExperiments.includes(exp);
25+
return !isKnownExperiment(exp);
2226
}) ?? [];
2327

2428
const { data: dailyActiveUsers } = useQuery(deploymentDAUs());

site/src/pages/DeploymentSettingsPage/OverviewPage/OverviewPageView.stories.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ const meta: Meta<typeof OverviewPageView> = {
3030
description:
3131
"Enable one or more experiments. These are not ready for production. Separate multiple experiments with commas, or enter '*' to opt-in to all available experiments.",
3232
flag: "experiments",
33-
value: ["workspace_actions"],
33+
value: ["example"],
3434
flag_shorthand: "",
3535
hidden: false,
3636
},
@@ -82,8 +82,8 @@ export const allExperimentsEnabled: Story = {
8282
hidden: false,
8383
},
8484
],
85-
safeExperiments: ["shared-ports"],
86-
invalidExperiments: ["invalid"],
85+
safeExperiments: ["example"],
86+
invalidExperiments: [],
8787
},
8888
};
8989

@@ -118,7 +118,7 @@ export const invalidExperimentsEnabled: Story = {
118118
hidden: false,
119119
},
120120
],
121-
safeExperiments: ["shared-ports"],
121+
safeExperiments: ["example"],
122122
invalidExperiments: ["invalid"],
123123
},
124124
};

site/src/pages/DeploymentSettingsPage/OverviewPage/OverviewPageView.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import AlertTitle from "@mui/material/AlertTitle";
22
import type {
33
DAUsResponse,
4-
Experiments,
4+
Experiment,
55
SerpentOption,
66
} from "api/typesGenerated";
77
import { Link } from "components/Link/Link";
@@ -22,8 +22,8 @@ import { UserEngagementChart } from "./UserEngagementChart";
2222
type OverviewPageViewProps = {
2323
deploymentOptions: SerpentOption[];
2424
dailyActiveUsers: DAUsResponse | undefined;
25-
readonly invalidExperiments: Experiments | string[];
26-
readonly safeExperiments: Experiments | string[];
25+
readonly invalidExperiments: readonly string[];
26+
readonly safeExperiments: readonly Experiment[];
2727
};
2828

2929
export const OverviewPageView: FC<OverviewPageViewProps> = ({

0 commit comments

Comments
 (0)