mirror of
https://github.com/coder/coder.git
synced 2026-06-03 04:58:23 +00:00
chore: remove template_update_policies experiment (#11250)
This commit is contained in:
@@ -78,15 +78,6 @@ func (r *RootCmd) templateCreate() *clibase.Cmd {
|
||||
if !entitlements.Features[codersdk.FeatureAccessControl].Enabled {
|
||||
return xerrors.Errorf("your license is not entitled to use enterprise access control, so you cannot set --require-active-version")
|
||||
}
|
||||
|
||||
experiments, exErr := client.Experiments(inv.Context())
|
||||
if exErr != nil {
|
||||
return xerrors.Errorf("get experiments: %w", exErr)
|
||||
}
|
||||
|
||||
if !experiments.Enabled(codersdk.ExperimentTemplateUpdatePolicies) {
|
||||
return xerrors.Errorf("--require-active-version is an experimental feature, contact an administrator to enable the 'template_update_policies' experiment on your Coder server")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@ import (
|
||||
"github.com/coder/coder/v2/cli/clitest"
|
||||
"github.com/coder/coder/v2/coderd/coderdtest"
|
||||
"github.com/coder/coder/v2/coderd/database"
|
||||
"github.com/coder/coder/v2/codersdk"
|
||||
"github.com/coder/coder/v2/provisioner/echo"
|
||||
"github.com/coder/coder/v2/provisionersdk/proto"
|
||||
"github.com/coder/coder/v2/pty/ptytest"
|
||||
@@ -398,14 +397,8 @@ func TestTemplateCreate(t *testing.T) {
|
||||
t.Run("RequireActiveVersionInvalid", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
dv := coderdtest.DeploymentValues(t)
|
||||
dv.Experiments = []string{
|
||||
string(codersdk.ExperimentTemplateUpdatePolicies),
|
||||
}
|
||||
|
||||
client := coderdtest.New(t, &coderdtest.Options{
|
||||
IncludeProvisionerDaemon: true,
|
||||
DeploymentValues: dv,
|
||||
})
|
||||
coderdtest.CreateFirstUser(t, client)
|
||||
source := clitest.CreateTemplateVersionSource(t, completeWithAgent())
|
||||
|
||||
@@ -86,15 +86,6 @@ func (r *RootCmd) templateEdit() *clibase.Cmd {
|
||||
if !entitlements.Features[codersdk.FeatureAccessControl].Enabled {
|
||||
return xerrors.Errorf("your license is not entitled to use enterprise access control, so you cannot set --require-active-version")
|
||||
}
|
||||
|
||||
experiments, exErr := client.Experiments(inv.Context())
|
||||
if exErr != nil {
|
||||
return xerrors.Errorf("get experiments: %w", exErr)
|
||||
}
|
||||
|
||||
if !experiments.Enabled(codersdk.ExperimentTemplateUpdatePolicies) {
|
||||
return xerrors.Errorf("--require-active-version is an experimental feature, contact an administrator to enable the 'template_update_policies' experiment on your Coder server")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Generated
+2
-4
@@ -8829,15 +8829,13 @@ const docTemplate = `{
|
||||
"workspace_actions",
|
||||
"tailnet_pg_coordinator",
|
||||
"single_tailnet",
|
||||
"deployment_health_page",
|
||||
"template_update_policies"
|
||||
"deployment_health_page"
|
||||
],
|
||||
"x-enum-varnames": [
|
||||
"ExperimentWorkspaceActions",
|
||||
"ExperimentTailnetPGCoordinator",
|
||||
"ExperimentSingleTailnet",
|
||||
"ExperimentDeploymentHealthPage",
|
||||
"ExperimentTemplateUpdatePolicies"
|
||||
"ExperimentDeploymentHealthPage"
|
||||
]
|
||||
},
|
||||
"codersdk.ExternalAuth": {
|
||||
|
||||
Generated
+2
-4
@@ -7907,15 +7907,13 @@
|
||||
"workspace_actions",
|
||||
"tailnet_pg_coordinator",
|
||||
"single_tailnet",
|
||||
"deployment_health_page",
|
||||
"template_update_policies"
|
||||
"deployment_health_page"
|
||||
],
|
||||
"x-enum-varnames": [
|
||||
"ExperimentWorkspaceActions",
|
||||
"ExperimentTailnetPGCoordinator",
|
||||
"ExperimentSingleTailnet",
|
||||
"ExperimentDeploymentHealthPage",
|
||||
"ExperimentTemplateUpdatePolicies"
|
||||
"ExperimentDeploymentHealthPage"
|
||||
]
|
||||
},
|
||||
"codersdk.ExternalAuth": {
|
||||
|
||||
@@ -2088,7 +2088,6 @@ const (
|
||||
// Deployment health page
|
||||
ExperimentDeploymentHealthPage Experiment = "deployment_health_page"
|
||||
|
||||
ExperimentTemplateUpdatePolicies Experiment = "template_update_policies"
|
||||
// Add new experiments here!
|
||||
// ExperimentExample Experiment = "example"
|
||||
)
|
||||
|
||||
Generated
+6
-7
@@ -2872,13 +2872,12 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in
|
||||
|
||||
#### Enumerated Values
|
||||
|
||||
| Value |
|
||||
| -------------------------- |
|
||||
| `workspace_actions` |
|
||||
| `tailnet_pg_coordinator` |
|
||||
| `single_tailnet` |
|
||||
| `deployment_health_page` |
|
||||
| `template_update_policies` |
|
||||
| Value |
|
||||
| ------------------------ |
|
||||
| `workspace_actions` |
|
||||
| `tailnet_pg_coordinator` |
|
||||
| `single_tailnet` |
|
||||
| `deployment_health_page` |
|
||||
|
||||
## codersdk.ExternalAuth
|
||||
|
||||
|
||||
@@ -23,11 +23,6 @@ func TestTemplateCreate(t *testing.T) {
|
||||
t.Run("RequireActiveVersion", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
dv := coderdtest.DeploymentValues(t)
|
||||
dv.Experiments = []string{
|
||||
string(codersdk.ExperimentTemplateUpdatePolicies),
|
||||
}
|
||||
|
||||
client, user := coderdenttest.New(t, &coderdenttest.Options{
|
||||
LicenseOptions: &coderdenttest.LicenseOptions{
|
||||
Features: license.Features{
|
||||
@@ -35,7 +30,6 @@ func TestTemplateCreate(t *testing.T) {
|
||||
},
|
||||
},
|
||||
Options: &coderdtest.Options{
|
||||
DeploymentValues: dv,
|
||||
IncludeProvisionerDaemon: true,
|
||||
},
|
||||
})
|
||||
@@ -124,17 +118,11 @@ func TestTemplateCreate(t *testing.T) {
|
||||
t.Run("NotEntitled", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
dv := coderdtest.DeploymentValues(t)
|
||||
dv.Experiments = []string{
|
||||
string(codersdk.ExperimentTemplateUpdatePolicies),
|
||||
}
|
||||
|
||||
client, admin := coderdenttest.New(t, &coderdenttest.Options{
|
||||
LicenseOptions: &coderdenttest.LicenseOptions{
|
||||
Features: license.Features{},
|
||||
},
|
||||
Options: &coderdtest.Options{
|
||||
DeploymentValues: dv,
|
||||
IncludeProvisionerDaemon: true,
|
||||
},
|
||||
})
|
||||
|
||||
@@ -21,11 +21,6 @@ func TestTemplateEdit(t *testing.T) {
|
||||
t.Run("OK", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
dv := coderdtest.DeploymentValues(t)
|
||||
dv.Experiments = []string{
|
||||
string(codersdk.ExperimentTemplateUpdatePolicies),
|
||||
}
|
||||
|
||||
ownerClient, owner := coderdenttest.New(t, &coderdenttest.Options{
|
||||
LicenseOptions: &coderdenttest.LicenseOptions{
|
||||
Features: license.Features{
|
||||
@@ -33,7 +28,6 @@ func TestTemplateEdit(t *testing.T) {
|
||||
},
|
||||
},
|
||||
Options: &coderdtest.Options{
|
||||
DeploymentValues: dv,
|
||||
IncludeProvisionerDaemon: true,
|
||||
},
|
||||
})
|
||||
@@ -64,17 +58,11 @@ func TestTemplateEdit(t *testing.T) {
|
||||
t.Run("NotEntitled", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
dv := coderdtest.DeploymentValues(t)
|
||||
dv.Experiments = []string{
|
||||
string(codersdk.ExperimentTemplateUpdatePolicies),
|
||||
}
|
||||
|
||||
client, owner := coderdenttest.New(t, &coderdenttest.Options{
|
||||
LicenseOptions: &coderdenttest.LicenseOptions{
|
||||
Features: license.Features{},
|
||||
},
|
||||
Options: &coderdtest.Options{
|
||||
DeploymentValues: dv,
|
||||
IncludeProvisionerDaemon: true,
|
||||
},
|
||||
})
|
||||
|
||||
Generated
-2
@@ -1780,13 +1780,11 @@ export type Experiment =
|
||||
| "deployment_health_page"
|
||||
| "single_tailnet"
|
||||
| "tailnet_pg_coordinator"
|
||||
| "template_update_policies"
|
||||
| "workspace_actions";
|
||||
export const Experiments: Experiment[] = [
|
||||
"deployment_health_page",
|
||||
"single_tailnet",
|
||||
"tailnet_pg_coordinator",
|
||||
"template_update_policies",
|
||||
"workspace_actions",
|
||||
];
|
||||
|
||||
|
||||
@@ -121,11 +121,3 @@ export const useIsWorkspaceActionsEnabled = (): boolean => {
|
||||
const allowWorkspaceActions = experiments.includes("workspace_actions");
|
||||
return allowWorkspaceActions && allowAdvancedScheduling;
|
||||
};
|
||||
|
||||
export const useTemplatePoliciesEnabled = (): boolean => {
|
||||
const { entitlements, experiments } = useDashboard();
|
||||
return (
|
||||
entitlements.features.access_control.enabled &&
|
||||
experiments.includes("template_update_policies")
|
||||
);
|
||||
};
|
||||
|
||||
+30
-34
@@ -52,7 +52,6 @@ export interface TemplateSettingsForm {
|
||||
// Helpful to show field errors on Storybook
|
||||
initialTouched?: FormikTouched<UpdateTemplateMeta>;
|
||||
accessControlEnabled: boolean;
|
||||
templatePoliciesEnabled: boolean;
|
||||
}
|
||||
|
||||
export const TemplateSettingsForm: FC<TemplateSettingsForm> = ({
|
||||
@@ -63,7 +62,6 @@ export const TemplateSettingsForm: FC<TemplateSettingsForm> = ({
|
||||
isSubmitting,
|
||||
initialTouched,
|
||||
accessControlEnabled,
|
||||
templatePoliciesEnabled,
|
||||
}) => {
|
||||
const validationSchema = getValidationSchema();
|
||||
const form: FormikContextType<UpdateTemplateMeta> =
|
||||
@@ -180,41 +178,39 @@ export const TemplateSettingsForm: FC<TemplateSettingsForm> = ({
|
||||
</Stack>
|
||||
</Stack>
|
||||
</label>
|
||||
{templatePoliciesEnabled && (
|
||||
<label htmlFor="require_active_version">
|
||||
<Stack direction="row" spacing={1}>
|
||||
<Checkbox
|
||||
id="require_active_version"
|
||||
name="require_active_version"
|
||||
checked={form.values.require_active_version}
|
||||
onChange={form.handleChange}
|
||||
/>
|
||||
<label htmlFor="require_active_version">
|
||||
<Stack direction="row" spacing={1}>
|
||||
<Checkbox
|
||||
id="require_active_version"
|
||||
name="require_active_version"
|
||||
checked={form.values.require_active_version}
|
||||
onChange={form.handleChange}
|
||||
/>
|
||||
|
||||
<Stack direction="column" spacing={0.5}>
|
||||
<Stack
|
||||
direction="row"
|
||||
alignItems="center"
|
||||
spacing={0.5}
|
||||
css={styles.optionText}
|
||||
>
|
||||
Require workspaces automatically update when started.
|
||||
<HelpTooltip>
|
||||
<HelpTooltipTrigger />
|
||||
<HelpTooltipContent>
|
||||
<HelpTooltipText>
|
||||
This setting is not enforced for template admins.
|
||||
</HelpTooltipText>
|
||||
</HelpTooltipContent>
|
||||
</HelpTooltip>
|
||||
</Stack>
|
||||
<span css={styles.optionHelperText}>
|
||||
Workspaces that are manually started or auto-started will
|
||||
use the active template version.
|
||||
</span>
|
||||
<Stack direction="column" spacing={0.5}>
|
||||
<Stack
|
||||
direction="row"
|
||||
alignItems="center"
|
||||
spacing={0.5}
|
||||
css={styles.optionText}
|
||||
>
|
||||
Require workspaces automatically update when started.
|
||||
<HelpTooltip>
|
||||
<HelpTooltipTrigger />
|
||||
<HelpTooltipContent>
|
||||
<HelpTooltipText>
|
||||
This setting is not enforced for template admins.
|
||||
</HelpTooltipText>
|
||||
</HelpTooltipContent>
|
||||
</HelpTooltip>
|
||||
</Stack>
|
||||
<span css={styles.optionHelperText}>
|
||||
Workspaces that are manually started or auto-started will use
|
||||
the active template version.
|
||||
</span>
|
||||
</Stack>
|
||||
</label>
|
||||
)}
|
||||
</Stack>
|
||||
</label>
|
||||
</Stack>
|
||||
</FormSection>
|
||||
|
||||
|
||||
+3
-1
@@ -80,7 +80,9 @@ const fillAndSubmitForm = async ({
|
||||
await userEvent.clear(iconField);
|
||||
await userEvent.type(iconField, icon);
|
||||
|
||||
const allowCancelJobsField = screen.getByRole("checkbox");
|
||||
const allowCancelJobsField = screen.getByRole("checkbox", {
|
||||
name: "Allow users to cancel in-progress workspace jobs. Depending on your template, canceling builds may leave workspaces in an unhealthy state. This option isn't recommended for most use cases.",
|
||||
});
|
||||
// checkbox is checked by default, so it must be clicked to get unchecked
|
||||
if (!allow_user_cancel_workspace_jobs) {
|
||||
await userEvent.click(allowCancelJobsField);
|
||||
|
||||
+1
-6
@@ -10,10 +10,7 @@ import { useTemplateSettings } from "../TemplateSettingsLayout";
|
||||
import { TemplateSettingsPageView } from "./TemplateSettingsPageView";
|
||||
import { templateByNameKey } from "api/queries/templates";
|
||||
import { useOrganizationId } from "hooks";
|
||||
import {
|
||||
useDashboard,
|
||||
useTemplatePoliciesEnabled,
|
||||
} from "components/Dashboard/DashboardProvider";
|
||||
import { useDashboard } from "components/Dashboard/DashboardProvider";
|
||||
|
||||
export const TemplateSettingsPage: FC = () => {
|
||||
const { template: templateName } = useParams() as { template: string };
|
||||
@@ -23,7 +20,6 @@ export const TemplateSettingsPage: FC = () => {
|
||||
const queryClient = useQueryClient();
|
||||
const { entitlements } = useDashboard();
|
||||
const accessControlEnabled = entitlements.features.access_control.enabled;
|
||||
const templatePoliciesEnabled = useTemplatePoliciesEnabled();
|
||||
|
||||
const {
|
||||
mutate: updateTemplate,
|
||||
@@ -62,7 +58,6 @@ export const TemplateSettingsPage: FC = () => {
|
||||
});
|
||||
}}
|
||||
accessControlEnabled={accessControlEnabled}
|
||||
templatePoliciesEnabled={templatePoliciesEnabled}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
||||
-1
@@ -8,7 +8,6 @@ const meta: Meta<typeof TemplateSettingsPageView> = {
|
||||
args: {
|
||||
template: MockTemplate,
|
||||
accessControlEnabled: true,
|
||||
templatePoliciesEnabled: true,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
-3
@@ -13,7 +13,6 @@ export interface TemplateSettingsPageViewProps {
|
||||
typeof TemplateSettingsForm
|
||||
>["initialTouched"];
|
||||
accessControlEnabled: boolean;
|
||||
templatePoliciesEnabled: boolean;
|
||||
}
|
||||
|
||||
export const TemplateSettingsPageView: FC<TemplateSettingsPageViewProps> = ({
|
||||
@@ -24,7 +23,6 @@ export const TemplateSettingsPageView: FC<TemplateSettingsPageViewProps> = ({
|
||||
submitError,
|
||||
initialTouched,
|
||||
accessControlEnabled,
|
||||
templatePoliciesEnabled,
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
@@ -40,7 +38,6 @@ export const TemplateSettingsPageView: FC<TemplateSettingsPageViewProps> = ({
|
||||
onCancel={onCancel}
|
||||
error={submitError}
|
||||
accessControlEnabled={accessControlEnabled}
|
||||
templatePoliciesEnabled={templatePoliciesEnabled}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -30,13 +30,11 @@ export type WorkspaceSettingsFormValues = {
|
||||
export const WorkspaceSettingsForm: FC<{
|
||||
workspace: Workspace;
|
||||
error: unknown;
|
||||
templatePoliciesEnabled: boolean;
|
||||
onCancel: () => void;
|
||||
onSubmit: (values: WorkspaceSettingsFormValues) => Promise<void>;
|
||||
}> = ({ onCancel, onSubmit, workspace, error, templatePoliciesEnabled }) => {
|
||||
}> = ({ onCancel, onSubmit, workspace, error }) => {
|
||||
const formEnabled =
|
||||
(templatePoliciesEnabled && !workspace.template_require_active_version) ||
|
||||
workspace.allow_renames;
|
||||
!workspace.template_require_active_version || workspace.allow_renames;
|
||||
|
||||
const form = useFormik<WorkspaceSettingsFormValues>({
|
||||
onSubmit,
|
||||
@@ -78,39 +76,37 @@ export const WorkspaceSettingsForm: FC<{
|
||||
/>
|
||||
</FormFields>
|
||||
</FormSection>
|
||||
{templatePoliciesEnabled && (
|
||||
<FormSection
|
||||
title="Automatic Updates"
|
||||
description="Configure your workspace to automatically update when started."
|
||||
>
|
||||
<FormFields>
|
||||
<TextField
|
||||
{...getFieldHelpers("automatic_updates")}
|
||||
id="automatic_updates"
|
||||
label="Update Policy"
|
||||
value={
|
||||
workspace.template_require_active_version
|
||||
? "always"
|
||||
: form.values.automatic_updates
|
||||
}
|
||||
select
|
||||
disabled={
|
||||
form.isSubmitting || workspace.template_require_active_version
|
||||
}
|
||||
helperText={
|
||||
workspace.template_require_active_version &&
|
||||
"The template for this workspace requires automatic updates."
|
||||
}
|
||||
>
|
||||
{AutomaticUpdateses.map((value) => (
|
||||
<MenuItem value={value} key={value}>
|
||||
{upperFirst(value)}
|
||||
</MenuItem>
|
||||
))}
|
||||
</TextField>
|
||||
</FormFields>
|
||||
</FormSection>
|
||||
)}
|
||||
<FormSection
|
||||
title="Automatic Updates"
|
||||
description="Configure your workspace to automatically update when started."
|
||||
>
|
||||
<FormFields>
|
||||
<TextField
|
||||
{...getFieldHelpers("automatic_updates")}
|
||||
id="automatic_updates"
|
||||
label="Update Policy"
|
||||
value={
|
||||
workspace.template_require_active_version
|
||||
? "always"
|
||||
: form.values.automatic_updates
|
||||
}
|
||||
select
|
||||
disabled={
|
||||
form.isSubmitting || workspace.template_require_active_version
|
||||
}
|
||||
helperText={
|
||||
workspace.template_require_active_version &&
|
||||
"The template for this workspace requires automatic updates."
|
||||
}
|
||||
>
|
||||
{AutomaticUpdateses.map((value) => (
|
||||
<MenuItem value={value} key={value}>
|
||||
{upperFirst(value)}
|
||||
</MenuItem>
|
||||
))}
|
||||
</TextField>
|
||||
</FormFields>
|
||||
</FormSection>
|
||||
{formEnabled && (
|
||||
<FormFooter onCancel={onCancel} isLoading={form.isSubmitting} />
|
||||
)}
|
||||
|
||||
@@ -7,7 +7,6 @@ import { useMutation } from "react-query";
|
||||
import { displaySuccess } from "components/GlobalSnackbar/utils";
|
||||
import { patchWorkspace, updateWorkspaceAutomaticUpdates } from "api/api";
|
||||
import { WorkspaceSettingsFormValues } from "./WorkspaceSettingsForm";
|
||||
import { useTemplatePoliciesEnabled } from "components/Dashboard/DashboardProvider";
|
||||
|
||||
const WorkspaceSettingsPage = () => {
|
||||
const params = useParams() as {
|
||||
@@ -18,7 +17,6 @@ const WorkspaceSettingsPage = () => {
|
||||
const username = params.username.replace("@", "");
|
||||
const workspace = useWorkspaceSettings();
|
||||
const navigate = useNavigate();
|
||||
const templatePoliciesEnabled = useTemplatePoliciesEnabled();
|
||||
|
||||
const mutation = useMutation({
|
||||
mutationFn: async (formValues: WorkspaceSettingsFormValues) => {
|
||||
@@ -47,7 +45,6 @@ const WorkspaceSettingsPage = () => {
|
||||
workspace={workspace}
|
||||
onCancel={() => navigate(`/@${username}/${workspaceName}`)}
|
||||
onSubmit={mutation.mutateAsync}
|
||||
templatePoliciesEnabled={templatePoliciesEnabled}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -16,12 +16,6 @@ type Story = StoryObj<typeof WorkspaceSettingsPageView>;
|
||||
|
||||
export const Example: Story = {};
|
||||
|
||||
export const AutoUpdates: Story = {
|
||||
args: {
|
||||
templatePoliciesEnabled: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const RenamesDisabled: Story = {
|
||||
args: {
|
||||
workspace: { ...MockWorkspace, allow_renames: false },
|
||||
|
||||
@@ -8,7 +8,6 @@ export type WorkspaceSettingsPageViewProps = {
|
||||
workspace: Workspace;
|
||||
onCancel: () => void;
|
||||
onSubmit: ComponentProps<typeof WorkspaceSettingsForm>["onSubmit"];
|
||||
templatePoliciesEnabled: boolean;
|
||||
};
|
||||
|
||||
export const WorkspaceSettingsPageView: FC<WorkspaceSettingsPageViewProps> = ({
|
||||
@@ -16,7 +15,6 @@ export const WorkspaceSettingsPageView: FC<WorkspaceSettingsPageViewProps> = ({
|
||||
onSubmit,
|
||||
error,
|
||||
workspace,
|
||||
templatePoliciesEnabled,
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
@@ -33,7 +31,6 @@ export const WorkspaceSettingsPageView: FC<WorkspaceSettingsPageViewProps> = ({
|
||||
workspace={workspace}
|
||||
onCancel={onCancel}
|
||||
onSubmit={onSubmit}
|
||||
templatePoliciesEnabled={templatePoliciesEnabled}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user