mirror of
https://github.com/coder/coder.git
synced 2026-10-31 11:02:50 +08:00
feat: add a per-template workspace rename setting (#27558)
This commit is contained in:
Generated
+14
@@ -20753,6 +20753,10 @@ const docTemplate = `{
|
||||
"description": "Allow users to cancel in-progress workspace jobs.\n*bool as the default value is \"true\".",
|
||||
"type": "boolean"
|
||||
},
|
||||
"allow_workspace_renames": {
|
||||
"description": "AllowWorkspaceRenames permits users to rename workspaces built from this\ntemplate. Renaming can be destructive for templates whose Terraform\nreferences the workspace name, so this defaults to false.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"autostart_requirement": {
|
||||
"description": "AutostartRequirement allows optionally specifying the autostart allowed days\nfor workspaces created from this template. This is an enterprise feature.",
|
||||
"allOf": [
|
||||
@@ -21678,6 +21682,7 @@ const docTemplate = `{
|
||||
"$ref": "#/definitions/codersdk.AIConfig"
|
||||
},
|
||||
"allow_workspace_renames": {
|
||||
"description": "Deprecated: Use the per-template allow_workspace_renames setting instead.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"autobuild_poll_interval": {
|
||||
@@ -26543,6 +26548,10 @@ const docTemplate = `{
|
||||
"allow_user_cancel_workspace_jobs": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"allow_workspace_renames": {
|
||||
"description": "AllowWorkspaceRenames permits users to rename workspaces built from this\ntemplate. Renaming can be destructive for templates whose Terraform\nreferences the workspace name.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"autostart_requirement": {
|
||||
"$ref": "#/definitions/codersdk.TemplateAutostartRequirement"
|
||||
},
|
||||
@@ -28102,6 +28111,10 @@ const docTemplate = `{
|
||||
"allow_user_cancel_workspace_jobs": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"allow_workspace_renames": {
|
||||
"description": "AllowWorkspaceRenames permits users to rename workspaces built from this\ntemplate. Renaming can be destructive for templates whose Terraform\nreferences the workspace name.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"autostart_requirement": {
|
||||
"$ref": "#/definitions/codersdk.TemplateAutostartRequirement"
|
||||
},
|
||||
@@ -29139,6 +29152,7 @@ const docTemplate = `{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"allow_renames": {
|
||||
"description": "AllowRenames is the effective rename permission for this workspace,\nderived from the template's allow_workspace_renames setting and the\ndeprecated deployment-wide flag.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"automatic_updates": {
|
||||
|
||||
Generated
+14
@@ -18828,6 +18828,10 @@
|
||||
"description": "Allow users to cancel in-progress workspace jobs.\n*bool as the default value is \"true\".",
|
||||
"type": "boolean"
|
||||
},
|
||||
"allow_workspace_renames": {
|
||||
"description": "AllowWorkspaceRenames permits users to rename workspaces built from this\ntemplate. Renaming can be destructive for templates whose Terraform\nreferences the workspace name, so this defaults to false.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"autostart_requirement": {
|
||||
"description": "AutostartRequirement allows optionally specifying the autostart allowed days\nfor workspaces created from this template. This is an enterprise feature.",
|
||||
"allOf": [
|
||||
@@ -19717,6 +19721,7 @@
|
||||
"$ref": "#/definitions/codersdk.AIConfig"
|
||||
},
|
||||
"allow_workspace_renames": {
|
||||
"description": "Deprecated: Use the per-template allow_workspace_renames setting instead.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"autobuild_poll_interval": {
|
||||
@@ -24405,6 +24410,10 @@
|
||||
"allow_user_cancel_workspace_jobs": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"allow_workspace_renames": {
|
||||
"description": "AllowWorkspaceRenames permits users to rename workspaces built from this\ntemplate. Renaming can be destructive for templates whose Terraform\nreferences the workspace name.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"autostart_requirement": {
|
||||
"$ref": "#/definitions/codersdk.TemplateAutostartRequirement"
|
||||
},
|
||||
@@ -25876,6 +25885,10 @@
|
||||
"allow_user_cancel_workspace_jobs": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"allow_workspace_renames": {
|
||||
"description": "AllowWorkspaceRenames permits users to rename workspaces built from this\ntemplate. Renaming can be destructive for templates whose Terraform\nreferences the workspace name.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"autostart_requirement": {
|
||||
"$ref": "#/definitions/codersdk.TemplateAutostartRequirement"
|
||||
},
|
||||
@@ -26862,6 +26875,7 @@
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"allow_renames": {
|
||||
"description": "AllowRenames is the effective rename permission for this workspace,\nderived from the template's allow_workspace_renames setting and the\ndeprecated deployment-wide flag.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"automatic_updates": {
|
||||
|
||||
@@ -596,6 +596,7 @@ func Template(t testing.TB, db database.Store, seed database.Template) database.
|
||||
UseClassicParameterFlow: takeFirst(seed.UseClassicParameterFlow, false),
|
||||
CorsBehavior: takeFirst(seed.CorsBehavior, database.CorsBehaviorSimple),
|
||||
AgentsAllowed: seed.AgentsAllowed,
|
||||
AllowWorkspaceRenames: seed.AllowWorkspaceRenames,
|
||||
})
|
||||
require.NoError(t, err, "insert template")
|
||||
|
||||
|
||||
Generated
+5
-1
@@ -3571,7 +3571,8 @@ CREATE TABLE templates (
|
||||
cors_behavior cors_behavior DEFAULT 'simple'::cors_behavior NOT NULL,
|
||||
disable_module_cache boolean DEFAULT false NOT NULL,
|
||||
time_til_autostop_notify bigint DEFAULT 0 NOT NULL,
|
||||
agents_allowed boolean DEFAULT true NOT NULL
|
||||
agents_allowed boolean DEFAULT true NOT NULL,
|
||||
allow_workspace_renames boolean DEFAULT false NOT NULL
|
||||
);
|
||||
|
||||
COMMENT ON COLUMN templates.default_ttl IS 'The default duration for autostop for workspaces created from this template.';
|
||||
@@ -3598,6 +3599,8 @@ COMMENT ON COLUMN templates.time_til_autostop_notify IS 'How long before the wor
|
||||
|
||||
COMMENT ON COLUMN templates.agents_allowed IS 'Whether Coder Agents can create workspaces using this template.';
|
||||
|
||||
COMMENT ON COLUMN templates.allow_workspace_renames IS 'Whether workspaces built from this template may be renamed. Renaming can be destructive for templates whose Terraform references the workspace name.';
|
||||
|
||||
CREATE VIEW template_with_names AS
|
||||
SELECT templates.id,
|
||||
templates.created_at,
|
||||
@@ -3632,6 +3635,7 @@ CREATE VIEW template_with_names AS
|
||||
templates.disable_module_cache,
|
||||
templates.time_til_autostop_notify,
|
||||
templates.agents_allowed,
|
||||
templates.allow_workspace_renames,
|
||||
COALESCE(visible_users.avatar_url, ''::text) AS created_by_avatar_url,
|
||||
COALESCE(visible_users.username, ''::text) AS created_by_username,
|
||||
COALESCE(visible_users.name, ''::text) AS created_by_name,
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
DROP VIEW template_with_names;
|
||||
|
||||
ALTER TABLE templates DROP COLUMN allow_workspace_renames;
|
||||
|
||||
CREATE VIEW template_with_names AS
|
||||
SELECT templates.*,
|
||||
COALESCE(visible_users.avatar_url, ''::text) AS created_by_avatar_url,
|
||||
COALESCE(visible_users.username, ''::text) AS created_by_username,
|
||||
COALESCE(visible_users.name, ''::text) AS created_by_name,
|
||||
COALESCE(organizations.name, ''::text) AS organization_name,
|
||||
COALESCE(organizations.display_name, ''::text) AS organization_display_name,
|
||||
COALESCE(organizations.icon, ''::text) AS organization_icon
|
||||
FROM ((templates
|
||||
LEFT JOIN visible_users ON ((templates.created_by = visible_users.id)))
|
||||
LEFT JOIN organizations ON ((templates.organization_id = organizations.id)));
|
||||
|
||||
COMMENT ON VIEW template_with_names IS 'Joins in the display name information such as username, avatar, and organization name.';
|
||||
@@ -0,0 +1,19 @@
|
||||
ALTER TABLE templates ADD COLUMN allow_workspace_renames boolean DEFAULT false NOT NULL;
|
||||
|
||||
COMMENT ON COLUMN templates.allow_workspace_renames IS 'Whether workspaces built from this template may be renamed. Renaming can be destructive for templates whose Terraform references the workspace name.';
|
||||
|
||||
DROP VIEW template_with_names;
|
||||
|
||||
CREATE VIEW template_with_names AS
|
||||
SELECT templates.*,
|
||||
COALESCE(visible_users.avatar_url, ''::text) AS created_by_avatar_url,
|
||||
COALESCE(visible_users.username, ''::text) AS created_by_username,
|
||||
COALESCE(visible_users.name, ''::text) AS created_by_name,
|
||||
COALESCE(organizations.name, ''::text) AS organization_name,
|
||||
COALESCE(organizations.display_name, ''::text) AS organization_display_name,
|
||||
COALESCE(organizations.icon, ''::text) AS organization_icon
|
||||
FROM ((templates
|
||||
LEFT JOIN visible_users ON ((templates.created_by = visible_users.id)))
|
||||
LEFT JOIN organizations ON ((templates.organization_id = organizations.id)));
|
||||
|
||||
COMMENT ON VIEW template_with_names IS 'Joins in the display name information such as username, avatar, and organization name.';
|
||||
@@ -192,6 +192,7 @@ func (q *sqlQuerier) GetAuthorizedTemplates(ctx context.Context, arg GetTemplate
|
||||
&i.DisableModuleCache,
|
||||
&i.TimeTilAutostopNotify,
|
||||
&i.AgentsAllowed,
|
||||
&i.AllowWorkspaceRenames,
|
||||
&i.CreatedByAvatarURL,
|
||||
&i.CreatedByUsername,
|
||||
&i.CreatedByName,
|
||||
|
||||
Generated
+3
@@ -6112,6 +6112,7 @@ type Template struct {
|
||||
DisableModuleCache bool `db:"disable_module_cache" json:"disable_module_cache"`
|
||||
TimeTilAutostopNotify int64 `db:"time_til_autostop_notify" json:"time_til_autostop_notify"`
|
||||
AgentsAllowed bool `db:"agents_allowed" json:"agents_allowed"`
|
||||
AllowWorkspaceRenames bool `db:"allow_workspace_renames" json:"allow_workspace_renames"`
|
||||
CreatedByAvatarURL string `db:"created_by_avatar_url" json:"created_by_avatar_url"`
|
||||
CreatedByUsername string `db:"created_by_username" json:"created_by_username"`
|
||||
CreatedByName string `db:"created_by_name" json:"created_by_name"`
|
||||
@@ -6166,6 +6167,8 @@ type TemplateTable struct {
|
||||
TimeTilAutostopNotify int64 `db:"time_til_autostop_notify" json:"time_til_autostop_notify"`
|
||||
// Whether Coder Agents can create workspaces using this template.
|
||||
AgentsAllowed bool `db:"agents_allowed" json:"agents_allowed"`
|
||||
// Whether workspaces built from this template may be renamed. Renaming can be destructive for templates whose Terraform references the workspace name.
|
||||
AllowWorkspaceRenames bool `db:"allow_workspace_renames" json:"allow_workspace_renames"`
|
||||
}
|
||||
|
||||
// Records aggregated usage statistics for templates/users. All usage is rounded up to the nearest minute.
|
||||
|
||||
Generated
+18
-8
@@ -27674,7 +27674,7 @@ func (q *sqlQuerier) GetTemplateAverageBuildTime(ctx context.Context, templateID
|
||||
|
||||
const getTemplateByID = `-- name: GetTemplateByID :one
|
||||
SELECT
|
||||
id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, default_ttl, created_by, icon, user_acl, group_acl, display_name, allow_user_cancel_workspace_jobs, allow_user_autostart, allow_user_autostop, failure_ttl, time_til_dormant, time_til_dormant_autodelete, autostop_requirement_days_of_week, autostop_requirement_weeks, autostart_block_days_of_week, require_active_version, deprecated, activity_bump, max_port_sharing_level, use_classic_parameter_flow, cors_behavior, disable_module_cache, time_til_autostop_notify, agents_allowed, created_by_avatar_url, created_by_username, created_by_name, organization_name, organization_display_name, organization_icon
|
||||
id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, default_ttl, created_by, icon, user_acl, group_acl, display_name, allow_user_cancel_workspace_jobs, allow_user_autostart, allow_user_autostop, failure_ttl, time_til_dormant, time_til_dormant_autodelete, autostop_requirement_days_of_week, autostop_requirement_weeks, autostart_block_days_of_week, require_active_version, deprecated, activity_bump, max_port_sharing_level, use_classic_parameter_flow, cors_behavior, disable_module_cache, time_til_autostop_notify, agents_allowed, allow_workspace_renames, created_by_avatar_url, created_by_username, created_by_name, organization_name, organization_display_name, organization_icon
|
||||
FROM
|
||||
template_with_names
|
||||
WHERE
|
||||
@@ -27720,6 +27720,7 @@ func (q *sqlQuerier) GetTemplateByID(ctx context.Context, id uuid.UUID) (Templat
|
||||
&i.DisableModuleCache,
|
||||
&i.TimeTilAutostopNotify,
|
||||
&i.AgentsAllowed,
|
||||
&i.AllowWorkspaceRenames,
|
||||
&i.CreatedByAvatarURL,
|
||||
&i.CreatedByUsername,
|
||||
&i.CreatedByName,
|
||||
@@ -27732,7 +27733,7 @@ func (q *sqlQuerier) GetTemplateByID(ctx context.Context, id uuid.UUID) (Templat
|
||||
|
||||
const getTemplateByOrganizationAndName = `-- name: GetTemplateByOrganizationAndName :one
|
||||
SELECT
|
||||
id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, default_ttl, created_by, icon, user_acl, group_acl, display_name, allow_user_cancel_workspace_jobs, allow_user_autostart, allow_user_autostop, failure_ttl, time_til_dormant, time_til_dormant_autodelete, autostop_requirement_days_of_week, autostop_requirement_weeks, autostart_block_days_of_week, require_active_version, deprecated, activity_bump, max_port_sharing_level, use_classic_parameter_flow, cors_behavior, disable_module_cache, time_til_autostop_notify, agents_allowed, created_by_avatar_url, created_by_username, created_by_name, organization_name, organization_display_name, organization_icon
|
||||
id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, default_ttl, created_by, icon, user_acl, group_acl, display_name, allow_user_cancel_workspace_jobs, allow_user_autostart, allow_user_autostop, failure_ttl, time_til_dormant, time_til_dormant_autodelete, autostop_requirement_days_of_week, autostop_requirement_weeks, autostart_block_days_of_week, require_active_version, deprecated, activity_bump, max_port_sharing_level, use_classic_parameter_flow, cors_behavior, disable_module_cache, time_til_autostop_notify, agents_allowed, allow_workspace_renames, created_by_avatar_url, created_by_username, created_by_name, organization_name, organization_display_name, organization_icon
|
||||
FROM
|
||||
template_with_names AS templates
|
||||
WHERE
|
||||
@@ -27786,6 +27787,7 @@ func (q *sqlQuerier) GetTemplateByOrganizationAndName(ctx context.Context, arg G
|
||||
&i.DisableModuleCache,
|
||||
&i.TimeTilAutostopNotify,
|
||||
&i.AgentsAllowed,
|
||||
&i.AllowWorkspaceRenames,
|
||||
&i.CreatedByAvatarURL,
|
||||
&i.CreatedByUsername,
|
||||
&i.CreatedByName,
|
||||
@@ -27797,7 +27799,7 @@ func (q *sqlQuerier) GetTemplateByOrganizationAndName(ctx context.Context, arg G
|
||||
}
|
||||
|
||||
const getTemplates = `-- name: GetTemplates :many
|
||||
SELECT id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, default_ttl, created_by, icon, user_acl, group_acl, display_name, allow_user_cancel_workspace_jobs, allow_user_autostart, allow_user_autostop, failure_ttl, time_til_dormant, time_til_dormant_autodelete, autostop_requirement_days_of_week, autostop_requirement_weeks, autostart_block_days_of_week, require_active_version, deprecated, activity_bump, max_port_sharing_level, use_classic_parameter_flow, cors_behavior, disable_module_cache, time_til_autostop_notify, agents_allowed, created_by_avatar_url, created_by_username, created_by_name, organization_name, organization_display_name, organization_icon FROM template_with_names AS templates
|
||||
SELECT id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, default_ttl, created_by, icon, user_acl, group_acl, display_name, allow_user_cancel_workspace_jobs, allow_user_autostart, allow_user_autostop, failure_ttl, time_til_dormant, time_til_dormant_autodelete, autostop_requirement_days_of_week, autostop_requirement_weeks, autostart_block_days_of_week, require_active_version, deprecated, activity_bump, max_port_sharing_level, use_classic_parameter_flow, cors_behavior, disable_module_cache, time_til_autostop_notify, agents_allowed, allow_workspace_renames, created_by_avatar_url, created_by_username, created_by_name, organization_name, organization_display_name, organization_icon FROM template_with_names AS templates
|
||||
ORDER BY (name, id) ASC
|
||||
`
|
||||
|
||||
@@ -27844,6 +27846,7 @@ func (q *sqlQuerier) GetTemplates(ctx context.Context) ([]Template, error) {
|
||||
&i.DisableModuleCache,
|
||||
&i.TimeTilAutostopNotify,
|
||||
&i.AgentsAllowed,
|
||||
&i.AllowWorkspaceRenames,
|
||||
&i.CreatedByAvatarURL,
|
||||
&i.CreatedByUsername,
|
||||
&i.CreatedByName,
|
||||
@@ -27866,7 +27869,7 @@ func (q *sqlQuerier) GetTemplates(ctx context.Context) ([]Template, error) {
|
||||
|
||||
const getTemplatesWithFilter = `-- name: GetTemplatesWithFilter :many
|
||||
SELECT
|
||||
t.id, t.created_at, t.updated_at, t.organization_id, t.deleted, t.name, t.provisioner, t.active_version_id, t.description, t.default_ttl, t.created_by, t.icon, t.user_acl, t.group_acl, t.display_name, t.allow_user_cancel_workspace_jobs, t.allow_user_autostart, t.allow_user_autostop, t.failure_ttl, t.time_til_dormant, t.time_til_dormant_autodelete, t.autostop_requirement_days_of_week, t.autostop_requirement_weeks, t.autostart_block_days_of_week, t.require_active_version, t.deprecated, t.activity_bump, t.max_port_sharing_level, t.use_classic_parameter_flow, t.cors_behavior, t.disable_module_cache, t.time_til_autostop_notify, t.agents_allowed, t.created_by_avatar_url, t.created_by_username, t.created_by_name, t.organization_name, t.organization_display_name, t.organization_icon
|
||||
t.id, t.created_at, t.updated_at, t.organization_id, t.deleted, t.name, t.provisioner, t.active_version_id, t.description, t.default_ttl, t.created_by, t.icon, t.user_acl, t.group_acl, t.display_name, t.allow_user_cancel_workspace_jobs, t.allow_user_autostart, t.allow_user_autostop, t.failure_ttl, t.time_til_dormant, t.time_til_dormant_autodelete, t.autostop_requirement_days_of_week, t.autostop_requirement_weeks, t.autostart_block_days_of_week, t.require_active_version, t.deprecated, t.activity_bump, t.max_port_sharing_level, t.use_classic_parameter_flow, t.cors_behavior, t.disable_module_cache, t.time_til_autostop_notify, t.agents_allowed, t.allow_workspace_renames, t.created_by_avatar_url, t.created_by_username, t.created_by_name, t.organization_name, t.organization_display_name, t.organization_icon
|
||||
FROM
|
||||
template_with_names AS t
|
||||
LEFT JOIN
|
||||
@@ -28036,6 +28039,7 @@ func (q *sqlQuerier) GetTemplatesWithFilter(ctx context.Context, arg GetTemplate
|
||||
&i.DisableModuleCache,
|
||||
&i.TimeTilAutostopNotify,
|
||||
&i.AgentsAllowed,
|
||||
&i.AllowWorkspaceRenames,
|
||||
&i.CreatedByAvatarURL,
|
||||
&i.CreatedByUsername,
|
||||
&i.CreatedByName,
|
||||
@@ -28076,10 +28080,11 @@ INSERT INTO
|
||||
max_port_sharing_level,
|
||||
use_classic_parameter_flow,
|
||||
cors_behavior,
|
||||
agents_allowed
|
||||
agents_allowed,
|
||||
allow_workspace_renames
|
||||
)
|
||||
VALUES
|
||||
($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18)
|
||||
($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19)
|
||||
`
|
||||
|
||||
type InsertTemplateParams struct {
|
||||
@@ -28101,6 +28106,7 @@ type InsertTemplateParams struct {
|
||||
UseClassicParameterFlow bool `db:"use_classic_parameter_flow" json:"use_classic_parameter_flow"`
|
||||
CorsBehavior CorsBehavior `db:"cors_behavior" json:"cors_behavior"`
|
||||
AgentsAllowed bool `db:"agents_allowed" json:"agents_allowed"`
|
||||
AllowWorkspaceRenames bool `db:"allow_workspace_renames" json:"allow_workspace_renames"`
|
||||
}
|
||||
|
||||
func (q *sqlQuerier) InsertTemplate(ctx context.Context, arg InsertTemplateParams) error {
|
||||
@@ -28123,6 +28129,7 @@ func (q *sqlQuerier) InsertTemplate(ctx context.Context, arg InsertTemplateParam
|
||||
arg.UseClassicParameterFlow,
|
||||
arg.CorsBehavior,
|
||||
arg.AgentsAllowed,
|
||||
arg.AllowWorkspaceRenames,
|
||||
)
|
||||
return err
|
||||
}
|
||||
@@ -28226,7 +28233,8 @@ SET
|
||||
use_classic_parameter_flow = $10,
|
||||
cors_behavior = $11,
|
||||
disable_module_cache = $12,
|
||||
agents_allowed = $13
|
||||
agents_allowed = $13,
|
||||
allow_workspace_renames = $14
|
||||
WHERE
|
||||
id = $1
|
||||
`
|
||||
@@ -28245,6 +28253,7 @@ type UpdateTemplateMetaByIDParams struct {
|
||||
CorsBehavior CorsBehavior `db:"cors_behavior" json:"cors_behavior"`
|
||||
DisableModuleCache bool `db:"disable_module_cache" json:"disable_module_cache"`
|
||||
AgentsAllowed bool `db:"agents_allowed" json:"agents_allowed"`
|
||||
AllowWorkspaceRenames bool `db:"allow_workspace_renames" json:"allow_workspace_renames"`
|
||||
}
|
||||
|
||||
func (q *sqlQuerier) UpdateTemplateMetaByID(ctx context.Context, arg UpdateTemplateMetaByIDParams) error {
|
||||
@@ -28262,6 +28271,7 @@ func (q *sqlQuerier) UpdateTemplateMetaByID(ctx context.Context, arg UpdateTempl
|
||||
arg.CorsBehavior,
|
||||
arg.DisableModuleCache,
|
||||
arg.AgentsAllowed,
|
||||
arg.AllowWorkspaceRenames,
|
||||
)
|
||||
return err
|
||||
}
|
||||
@@ -39515,7 +39525,7 @@ LEFT JOIN LATERAL (
|
||||
) latest_build ON TRUE
|
||||
LEFT JOIN LATERAL (
|
||||
SELECT
|
||||
id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, default_ttl, created_by, icon, user_acl, group_acl, display_name, allow_user_cancel_workspace_jobs, allow_user_autostart, allow_user_autostop, failure_ttl, time_til_dormant, time_til_dormant_autodelete, autostop_requirement_days_of_week, autostop_requirement_weeks, autostart_block_days_of_week, require_active_version, deprecated, activity_bump, max_port_sharing_level, use_classic_parameter_flow, cors_behavior, disable_module_cache, time_til_autostop_notify, agents_allowed
|
||||
id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, default_ttl, created_by, icon, user_acl, group_acl, display_name, allow_user_cancel_workspace_jobs, allow_user_autostart, allow_user_autostop, failure_ttl, time_til_dormant, time_til_dormant_autodelete, autostop_requirement_days_of_week, autostop_requirement_weeks, autostart_block_days_of_week, require_active_version, deprecated, activity_bump, max_port_sharing_level, use_classic_parameter_flow, cors_behavior, disable_module_cache, time_til_autostop_notify, agents_allowed, allow_workspace_renames
|
||||
FROM
|
||||
templates
|
||||
WHERE
|
||||
|
||||
@@ -144,10 +144,11 @@ INSERT INTO
|
||||
max_port_sharing_level,
|
||||
use_classic_parameter_flow,
|
||||
cors_behavior,
|
||||
agents_allowed
|
||||
agents_allowed,
|
||||
allow_workspace_renames
|
||||
)
|
||||
VALUES
|
||||
($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18);
|
||||
($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19);
|
||||
|
||||
-- name: UpdateTemplateActiveVersionByID :exec
|
||||
UPDATE
|
||||
@@ -182,7 +183,8 @@ SET
|
||||
use_classic_parameter_flow = $10,
|
||||
cors_behavior = $11,
|
||||
disable_module_cache = $12,
|
||||
agents_allowed = $13
|
||||
agents_allowed = $13,
|
||||
allow_workspace_renames = $14
|
||||
WHERE
|
||||
id = $1
|
||||
;
|
||||
|
||||
@@ -556,6 +556,7 @@ func (api *API) templateBuilderCreateTemplate(rw http.ResponseWriter, r *http.Re
|
||||
UseClassicParameterFlow: false,
|
||||
CorsBehavior: database.CorsBehaviorSimple,
|
||||
AgentsAllowed: true,
|
||||
AllowWorkspaceRenames: false,
|
||||
})
|
||||
if err != nil {
|
||||
if database.IsUniqueViolation(err, database.UniqueTemplatesOrganizationIDNameIndex) {
|
||||
|
||||
@@ -420,6 +420,7 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque
|
||||
allowUserCancelWorkspaceJobs = ptr.NilToDefault(createTemplate.AllowUserCancelWorkspaceJobs, false)
|
||||
allowUserAutostart = ptr.NilToDefault(createTemplate.AllowUserAutostart, true)
|
||||
allowUserAutostop = ptr.NilToDefault(createTemplate.AllowUserAutostop, true)
|
||||
allowWorkspaceRenames = ptr.NilToDefault(createTemplate.AllowWorkspaceRenames, false)
|
||||
)
|
||||
|
||||
defaultsGroups := database.TemplateACL{}
|
||||
@@ -450,6 +451,7 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque
|
||||
UseClassicParameterFlow: useClassicParameterFlow,
|
||||
CorsBehavior: corsBehavior,
|
||||
AgentsAllowed: agentsAllowed,
|
||||
AllowWorkspaceRenames: allowWorkspaceRenames,
|
||||
})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("insert template: %s", err)
|
||||
@@ -782,6 +784,7 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) {
|
||||
CorsBehavior: resolved.corsBehavior,
|
||||
DisableModuleCache: resolved.disableModuleCache,
|
||||
AgentsAllowed: resolved.agentsAllowed,
|
||||
AllowWorkspaceRenames: resolved.allowWorkspaceRenames,
|
||||
})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("update template metadata: %w", err)
|
||||
@@ -1059,6 +1062,7 @@ func (api *API) convertTemplate(
|
||||
CORSBehavior: codersdk.CORSBehavior(template.CorsBehavior),
|
||||
DisableModuleCache: template.DisableModuleCache,
|
||||
AgentsAllowed: template.AgentsAllowed,
|
||||
AllowWorkspaceRenames: template.AllowWorkspaceRenames,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ type templateMetaUpdate struct {
|
||||
deprecationMessage string
|
||||
useClassicTemplateFlow bool
|
||||
disableModuleCache bool
|
||||
allowWorkspaceRenames bool
|
||||
corsBehavior database.CorsBehavior
|
||||
autostopRequirementDaysOfWeekParsed uint8
|
||||
autostartRequirementDaysOfWeekParsed uint8
|
||||
@@ -87,6 +88,7 @@ func resolveTemplateMetaUpdate(
|
||||
deprecationMessage: ptr.NilToDefault(req.DeprecationMessage, template.Deprecated),
|
||||
useClassicTemplateFlow: ptr.NilToDefault(req.UseClassicParameterFlow, template.UseClassicParameterFlow),
|
||||
disableModuleCache: ptr.NilToDefault(req.DisableModuleCache, template.DisableModuleCache),
|
||||
allowWorkspaceRenames: ptr.NilToDefault(req.AllowWorkspaceRenames, template.AllowWorkspaceRenames),
|
||||
groupACL: template.GroupACL,
|
||||
|
||||
// Default to the original values
|
||||
|
||||
@@ -44,6 +44,7 @@ func baselineTemplate() database.Template {
|
||||
UseClassicParameterFlow: true,
|
||||
CorsBehavior: database.CorsBehaviorPassthru,
|
||||
DisableModuleCache: true,
|
||||
AllowWorkspaceRenames: true,
|
||||
GroupACL: database.TemplateACL{
|
||||
orgID.String(): {"read"},
|
||||
},
|
||||
@@ -87,6 +88,7 @@ func baselineResolved() templateMetaUpdate {
|
||||
deprecationMessage: tpl.Deprecated,
|
||||
useClassicTemplateFlow: tpl.UseClassicParameterFlow,
|
||||
disableModuleCache: tpl.DisableModuleCache,
|
||||
allowWorkspaceRenames: tpl.AllowWorkspaceRenames,
|
||||
corsBehavior: tpl.CorsBehavior,
|
||||
autostopRequirementDaysOfWeekParsed: 0b0000001,
|
||||
autostartRequirementDaysOfWeekParsed: 0b1000000,
|
||||
@@ -290,6 +292,13 @@ func TestResolveTemplateMetaUpdate(t *testing.T) {
|
||||
r.disableModuleCache = false
|
||||
}},
|
||||
},
|
||||
{
|
||||
name: "AllowWorkspaceRenames",
|
||||
req: codersdk.UpdateTemplateMeta{AllowWorkspaceRenames: ptr.Ref(false)},
|
||||
expected: expected{override: func(r *templateMetaUpdate) {
|
||||
r.allowWorkspaceRenames = false
|
||||
}},
|
||||
},
|
||||
|
||||
// CORS behavior.
|
||||
{
|
||||
|
||||
@@ -1844,6 +1844,38 @@ func TestPatchTemplateMeta(t *testing.T) {
|
||||
assert.False(t, updated.DisableModuleCache, "expected false")
|
||||
})
|
||||
|
||||
t.Run("AllowWorkspaceRenames", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
client := coderdtest.New(t, nil)
|
||||
user := coderdtest.CreateFirstUser(t, client)
|
||||
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
|
||||
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
|
||||
require.False(t, template.AllowWorkspaceRenames, "default is false")
|
||||
|
||||
ctx := testutil.Context(t, testutil.WaitLong)
|
||||
|
||||
req := codersdk.UpdateTemplateMeta{
|
||||
AllowWorkspaceRenames: ptr.Ref(true),
|
||||
}
|
||||
updated, err := client.UpdateTemplateMeta(ctx, template.ID, req)
|
||||
require.NoError(t, err)
|
||||
assert.True(t, updated.AllowWorkspaceRenames, "expected true")
|
||||
|
||||
// Omitting the field preserves the existing value.
|
||||
req.AllowWorkspaceRenames = nil
|
||||
_, err = client.UpdateTemplateMeta(ctx, template.ID, req)
|
||||
require.NoError(t, err)
|
||||
updated, err = client.Template(ctx, template.ID)
|
||||
require.NoError(t, err)
|
||||
assert.True(t, updated.AllowWorkspaceRenames, "expected true")
|
||||
|
||||
req.AllowWorkspaceRenames = ptr.Ref(false)
|
||||
updated, err = client.UpdateTemplateMeta(ctx, template.ID, req)
|
||||
require.NoError(t, err)
|
||||
assert.False(t, updated.AllowWorkspaceRenames, "expected false")
|
||||
})
|
||||
|
||||
t.Run("SupportEmptyOrDefaultFields", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
||||
+22
-13
@@ -1154,9 +1154,17 @@ func (api *API) patchWorkspace(rw http.ResponseWriter, r *http.Request) {
|
||||
// patched in the future, it's enough if one changes.
|
||||
name := workspace.Name
|
||||
if req.Name != "" || req.Name != workspace.Name {
|
||||
if !api.AllowWorkspaceRenames {
|
||||
template, err := api.Database.GetTemplateByID(ctx, workspace.TemplateID)
|
||||
if err != nil {
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Internal error fetching workspace template.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
if !api.AllowWorkspaceRenames && !template.AllowWorkspaceRenames {
|
||||
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
|
||||
Message: "Workspace renames are not allowed.",
|
||||
Message: "Workspace renames are not enabled for this template.",
|
||||
})
|
||||
return
|
||||
}
|
||||
@@ -2596,10 +2604,11 @@ func (api *API) patchWorkspaceACL(rw http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
type workspaceData struct {
|
||||
templates []database.Template
|
||||
builds []codersdk.WorkspaceBuild
|
||||
appStatuses []codersdk.WorkspaceAppStatus
|
||||
allowRenames bool
|
||||
templates []database.Template
|
||||
builds []codersdk.WorkspaceBuild
|
||||
appStatuses []codersdk.WorkspaceAppStatus
|
||||
// deploymentAllowsRenames is the deprecated deployment-wide rename flag.
|
||||
deploymentAllowsRenames bool
|
||||
}
|
||||
|
||||
// @Summary Completely clears the workspace's user and group ACLs.
|
||||
@@ -2757,10 +2766,10 @@ func (api *API) workspaceData(ctx context.Context, workspaces []database.Workspa
|
||||
}
|
||||
|
||||
return workspaceData{
|
||||
templates: templates,
|
||||
appStatuses: db2sdk.WorkspaceAppStatuses(appStatuses),
|
||||
builds: apiBuilds,
|
||||
allowRenames: api.AllowWorkspaceRenames,
|
||||
templates: templates,
|
||||
appStatuses: db2sdk.WorkspaceAppStatuses(appStatuses),
|
||||
builds: apiBuilds,
|
||||
deploymentAllowsRenames: api.AllowWorkspaceRenames,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -2846,7 +2855,7 @@ func convertWorkspaces(
|
||||
workspace,
|
||||
build,
|
||||
template,
|
||||
data.allowRenames,
|
||||
data.deploymentAllowsRenames,
|
||||
appStatus,
|
||||
)
|
||||
if err != nil {
|
||||
@@ -2865,7 +2874,7 @@ func convertWorkspace(
|
||||
workspace database.Workspace,
|
||||
workspaceBuild codersdk.WorkspaceBuild,
|
||||
template database.Template,
|
||||
allowRenames bool,
|
||||
deploymentAllowsRenames bool,
|
||||
latestAppStatus codersdk.WorkspaceAppStatus,
|
||||
) (codersdk.Workspace, error) {
|
||||
if requesterID == uuid.Nil {
|
||||
@@ -2953,7 +2962,7 @@ func convertWorkspace(
|
||||
FailingAgents: failingAgents,
|
||||
},
|
||||
AutomaticUpdates: codersdk.AutomaticUpdates(workspace.AutomaticUpdates),
|
||||
AllowRenames: allowRenames,
|
||||
AllowRenames: deploymentAllowsRenames || template.AllowWorkspaceRenames,
|
||||
Favorite: requesterFavorite,
|
||||
NextStartAt: nextStartAt,
|
||||
IsPrebuild: workspace.IsPrebuild(),
|
||||
|
||||
@@ -220,7 +220,44 @@ func TestWorkspace(t *testing.T) {
|
||||
err := client.UpdateWorkspace(ctx, ws1.ID, codersdk.UpdateWorkspaceRequest{
|
||||
Name: want,
|
||||
})
|
||||
require.ErrorContains(t, err, "Workspace renames are not allowed")
|
||||
require.ErrorContains(t, err, "Workspace renames are not enabled for this template")
|
||||
})
|
||||
|
||||
t.Run("RenameAllowedByTemplate", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
// The deployment-wide flag is off. The template setting alone must be
|
||||
// enough to permit renames.
|
||||
client := coderdtest.New(t, &coderdtest.Options{
|
||||
IncludeProvisionerDaemon: true,
|
||||
AllowWorkspaceRenames: false,
|
||||
})
|
||||
user := coderdtest.CreateFirstUser(t, client)
|
||||
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
|
||||
coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
|
||||
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID, func(req *codersdk.CreateTemplateRequest) {
|
||||
req.AllowWorkspaceRenames = ptr.Ref(true)
|
||||
})
|
||||
ws1 := coderdtest.CreateWorkspace(t, client, template.ID)
|
||||
coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, ws1.LatestBuild.ID)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitMedium)
|
||||
defer cancel()
|
||||
|
||||
require.True(t, template.AllowWorkspaceRenames)
|
||||
|
||||
fetched, err := client.Workspace(ctx, ws1.ID)
|
||||
require.NoError(t, err)
|
||||
require.True(t, fetched.AllowRenames)
|
||||
|
||||
const want = "new-name"
|
||||
err = client.UpdateWorkspace(ctx, ws1.ID, codersdk.UpdateWorkspaceRequest{
|
||||
Name: want,
|
||||
})
|
||||
require.NoError(t, err, "workspace rename failed")
|
||||
|
||||
ws, err := client.Workspace(ctx, ws1.ID)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, want, ws.Name)
|
||||
})
|
||||
|
||||
t.Run("TemplateProperties", func(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user