Skip to content

chore: add form_type parameter argument to db #17920

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 61 commits into from
May 29, 2025
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
af8bead
chore: initial migration
Emyrk May 19, 2025
a65f276
make gen
Emyrk May 19, 2025
9996c8c
update insert query
Emyrk May 19, 2025
feaeef7
make gen
Emyrk May 19, 2025
25d04ad
update provisioenrsdk
Emyrk May 19, 2025
0317037
make gen
Emyrk May 19, 2025
a28c610
passing form_type to coderd
Emyrk May 19, 2025
49b8035
feat: form_type plumbing and validation for multi select
Emyrk May 19, 2025
0f3d557
update terraform dep for struct tags
Emyrk May 19, 2025
1a9e711
remove dead comments
Emyrk May 19, 2025
c317769
add unit test for 'inOptionSet'
Emyrk May 19, 2025
c11a3c4
chore: add unit test for improper multi-select
Emyrk May 19, 2025
bc83309
make gen
Emyrk May 19, 2025
108ad42
make fmt
Emyrk May 19, 2025
383b64f
Merge branch 'main' into stevenmasley/param_form_type
Emyrk May 19, 2025
0325364
Merge remote-tracking branch 'origin/main' into stevenmasley/param_fo…
Emyrk May 21, 2025
2560400
create form_type enum in db
Emyrk May 21, 2025
b630365
chore: check enum value before insert
Emyrk May 21, 2025
b8e121a
compile fix
Emyrk May 21, 2025
c271424
delete duplicate converter
Emyrk May 21, 2025
ea5c4b8
Merge remote-tracking branch 'origin/main' into stevenmasley/param_fo…
Emyrk May 21, 2025
827ae32
migration bump
Emyrk May 21, 2025
8beade9
make gen
Emyrk May 21, 2025
5d9ccb6
linting
Emyrk May 21, 2025
6de1b01
fixup entities
Emyrk May 21, 2025
44c53ff
Merge remote-tracking branch 'origin/main' into stevenmasley/param_fo…
Emyrk May 22, 2025
85acc1f
test for bad form_type
Emyrk May 22, 2025
2200db7
handle null options
Emyrk May 22, 2025
77d65cb
Merge remote-tracking branch 'origin/main' into stevenmasley/param_fo…
Emyrk May 22, 2025
940b7aa
init nil slice
Emyrk May 22, 2025
1ff7012
make form_type an enum in the proto
Emyrk May 23, 2025
856ccaa
make gen
Emyrk May 23, 2025
ce07f00
add proto enum converters
Emyrk May 23, 2025
aa46cab
add db validation
Emyrk May 23, 2025
ad362e0
rename error enum
Emyrk May 23, 2025
33c3bde
compile fix
Emyrk May 23, 2025
9c1d812
compile fix on test
Emyrk May 23, 2025
be9d88e
make gen
Emyrk May 23, 2025
a3d8446
handle error type
Emyrk May 23, 2025
8229966
fixups
Emyrk May 23, 2025
24f2e05
linting
Emyrk May 23, 2025
3c687e4
text fixup
Emyrk May 23, 2025
f52e789
fixup comment
Emyrk May 27, 2025
8ada165
Merge remote-tracking branch 'origin/main' into stevenmasley/param_fo…
Emyrk May 27, 2025
6fabc27
try to resolve some gen issues
Emyrk May 27, 2025
0dc98e4
make gen
Emyrk May 27, 2025
c74baef
fixup test asserts
Emyrk May 27, 2025
cedf39f
more explicit form type in unit test
Emyrk May 27, 2025
6e9beed
Merge remote-tracking branch 'origin/main' into stevenmasley/param_fo…
Emyrk May 27, 2025
3c97ec7
bump migration
Emyrk May 27, 2025
becfd7c
Merge remote-tracking branch 'origin/main' into stevenmasley/param_fo…
Emyrk May 27, 2025
deaff2a
make gen
Emyrk May 27, 2025
cab124a
bump migration
Emyrk May 27, 2025
1388d27
add enums struct tag to FormType
Emyrk May 28, 2025
716200f
spaces over tabs
Emyrk May 28, 2025
2e9723b
make inOptionSet more strict
Emyrk May 28, 2025
9d52e48
make gen
Emyrk May 28, 2025
f012e51
Merge remote-tracking branch 'origin/main' into stevenmasley/param_fo…
Emyrk May 28, 2025
ba70555
migration bump
Emyrk May 28, 2025
1876d03
Merge remote-tracking branch 'origin/main' into stevenmasley/param_fo…
Emyrk May 29, 2025
c1187e6
ci redo
Emyrk May 29, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions coderd/database/dbmem/dbmem.go
Original file line number Diff line number Diff line change
Expand Up @@ -9303,6 +9303,7 @@ func (q *FakeQuerier) InsertTemplateVersionParameter(_ context.Context, arg data
DisplayName: arg.DisplayName,
Description: arg.Description,
Type: arg.Type,
FormType: arg.FormType,
Mutable: arg.Mutable,
DefaultValue: arg.DefaultValue,
Icon: arg.Icon,
Expand Down
3 changes: 3 additions & 0 deletions coderd/database/dump.sql

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE template_version_parameters DROP COLUMN form_type;
6 changes: 6 additions & 0 deletions coderd/database/migrations/000328_parameter_form_type.up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
-- Intentionally leaving the default blank. The provisioner will not re-run any
-- imports to backfill these values. Missing values just have to be handled.
ALTER TABLE template_version_parameters ADD COLUMN form_type text NOT NULL DEFAULT '';

COMMENT ON COLUMN template_version_parameters.form_type
IS 'Specify what form_type should be used to render the parameter in the UI. This value should correspond to an enum, but this will not be enforced in the sql. Mistakes here should not be fatal for functional usage.';
2 changes: 2 additions & 0 deletions coderd/database/models.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 9 additions & 3 deletions coderd/database/queries.sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion coderd/database/queries/templateversionparameters.sql
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ INSERT INTO
name,
description,
type,
form_type,
mutable,
default_value,
icon,
Expand Down Expand Up @@ -37,7 +38,8 @@ VALUES
$14,
$15,
$16,
$17
$17,
$18
) RETURNING *;

-- name: GetTemplateVersionParameters :many
Expand Down
1 change: 1 addition & 0 deletions coderd/provisionerdserver/provisionerdserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -1414,6 +1414,7 @@ func (s *server) CompleteJob(ctx context.Context, completed *proto.CompletedJob)
DisplayName: richParameter.DisplayName,
Description: richParameter.Description,
Type: richParameter.Type,
FormType: richParameter.FormType,
Mutable: richParameter.Mutable,
DefaultValue: richParameter.DefaultValue,
Icon: richParameter.Icon,
Expand Down
1 change: 1 addition & 0 deletions coderd/templateversions.go
Original file line number Diff line number Diff line change
Expand Up @@ -1895,6 +1895,7 @@ func convertTemplateVersionParameter(param database.TemplateVersionParameter) (c
Description: param.Description,
DescriptionPlaintext: descriptionPlaintext,
Type: param.Type,
FormType: param.FormType,
Mutable: param.Mutable,
DefaultValue: param.DefaultValue,
Icon: param.Icon,
Expand Down
30 changes: 29 additions & 1 deletion coderd/workspaces_test.go
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like to see a test here for the kind of build inputs that could trigger the new error path in codersdk added below.

Copy link
Member Author

@Emyrk Emyrk May 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The previous code was stricter (not allowing multi-select).

So the new code allows more inputs, rather than removing.

But I will hit the new error path 👍

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added TestWorkspaceWithMultiSelectFailure

Original file line number Diff line number Diff line change
Expand Up @@ -3527,6 +3527,12 @@ func TestWorkspaceWithRichParameters(t *testing.T) {
secondParameterDescription = "_This_ is second *parameter*"
secondParameterValue = "2"
secondParameterValidationMonotonic = codersdk.MonotonicOrderIncreasing

thirdParameterName = "third_parameter"
thirdParameterType = "list(string)"
thirdParameterFormType = "multi-select"
thirdParameterDefault = `["red"]`
thirdParameterOption = "red"
)

client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
Expand All @@ -3552,6 +3558,18 @@ func TestWorkspaceWithRichParameters(t *testing.T) {
ValidationMax: ptr.Ref(int32(3)),
ValidationMonotonic: string(secondParameterValidationMonotonic),
},
{
Name: thirdParameterName,
Type: thirdParameterType,
DefaultValue: thirdParameterDefault,
Options: []*proto.RichParameterOption{
{
Name: thirdParameterOption,
Value: thirdParameterOption,
},
},
FormType: thirdParameterFormType,
},
},
},
},
Expand All @@ -3575,22 +3593,32 @@ func TestWorkspaceWithRichParameters(t *testing.T) {

templateRichParameters, err := client.TemplateVersionRichParameters(ctx, version.ID)
require.NoError(t, err)
require.Len(t, templateRichParameters, 2)
require.Len(t, templateRichParameters, 3)
require.Equal(t, firstParameterName, templateRichParameters[0].Name)
require.Equal(t, firstParameterType, templateRichParameters[0].Type)
require.Equal(t, firstParameterDescription, templateRichParameters[0].Description)
require.Equal(t, firstParameterDescriptionPlaintext, templateRichParameters[0].DescriptionPlaintext)
require.Equal(t, codersdk.ValidationMonotonicOrder(""), templateRichParameters[0].ValidationMonotonic) // no validation for string

require.Equal(t, secondParameterName, templateRichParameters[1].Name)
require.Equal(t, secondParameterDisplayName, templateRichParameters[1].DisplayName)
require.Equal(t, secondParameterType, templateRichParameters[1].Type)
require.Equal(t, secondParameterDescription, templateRichParameters[1].Description)
require.Equal(t, secondParameterDescriptionPlaintext, templateRichParameters[1].DescriptionPlaintext)
require.Equal(t, secondParameterValidationMonotonic, templateRichParameters[1].ValidationMonotonic)

third := templateRichParameters[2]
require.Equal(t, thirdParameterName, third.Name)
require.Equal(t, thirdParameterType, third.Type)
require.Equal(t, thirdParameterFormType, third.FormType)
require.Equal(t, thirdParameterDefault, third.DefaultValue)
require.Equal(t, thirdParameterOption, third.Options[0].Name)
require.Equal(t, thirdParameterOption, third.Options[0].Value)

expectedBuildParameters := []codersdk.WorkspaceBuildParameter{
{Name: firstParameterName, Value: firstParameterValue},
{Name: secondParameterName, Value: secondParameterValue},
{Name: thirdParameterName, Value: thirdParameterDefault},
}

template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
Expand Down
52 changes: 40 additions & 12 deletions codersdk/richparameters.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package codersdk

import (
"encoding/json"

"golang.org/x/xerrors"
"tailscale.com/types/ptr"

"github.com/coder/coder/v2/coderd/util/slice"
"github.com/coder/terraform-provider-coder/v2/provider"
)

Expand Down Expand Up @@ -66,18 +69,8 @@ func validateBuildParameter(richParameter TemplateVersionParameter, buildParamet
current = richParameter.DefaultValue
}

if len(richParameter.Options) > 0 {
var matched bool
for _, opt := range richParameter.Options {
if opt.Value == current {
matched = true
break
}
}

if !matched {
return xerrors.Errorf("parameter value must match one of options: %s", parameterValuesAsArray(richParameter.Options))
}
if len(richParameter.Options) > 0 && !inOptionSet(richParameter, current) {
return xerrors.Errorf("parameter value must match one of options: %s", parameterValuesAsArray(richParameter.Options))
}

if !validationEnabled(richParameter) {
Expand All @@ -104,6 +97,41 @@ func validateBuildParameter(richParameter TemplateVersionParameter, buildParamet
return validation.Valid(richParameter.Type, current, previous)
}

// inOptionSet returns if the value given is in the set of options for a parameter.
func inOptionSet(richParameter TemplateVersionParameter, value string) bool {
optionValues := make([]string, 0, len(richParameter.Options))
for _, option := range richParameter.Options {
optionValues = append(optionValues, option.Value)
}

// This is the simple case
if slice.Contains(optionValues, value) {
return true
}

// If the type is `list(string)` and the form_type is `multi-select`, then we check each individual
// value in the list against the option set. If the form_type is the empty string, we have to consider the
// possibility it might be a multi-select. Old provisioners do not send us the form_type.
mightBeMultiSelect := richParameter.Type == provider.OptionTypeListString && (richParameter.FormType == string(provider.ParameterFormTypeMultiSelect) || richParameter.FormType == "")
if !mightBeMultiSelect {
return false
}

var checks []string
err := json.Unmarshal([]byte(value), &checks)
if err != nil {
return false
}

for _, check := range checks {
if !slice.Contains(optionValues, check) {
return false
}
}

return true
}

func findBuildParameter(params []WorkspaceBuildParameter, parameterName string) (*WorkspaceBuildParameter, bool) {
if params == nil {
return nil, false
Expand Down
1 change: 1 addition & 0 deletions codersdk/templateversions.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ type TemplateVersionParameter struct {
Description string `json:"description"`
DescriptionPlaintext string `json:"description_plaintext"`
Type string `json:"type" enums:"string,number,bool,list(string)"`
FormType string `json:"form_type"`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't we at least want an enums: tag?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, TIL enums is a swagger doc, not a validation thing. This is never consumed as input (an api request). I'll add it for the swagger docs.

Mutable bool `json:"mutable"`
DefaultValue string `json:"default_value"`
Icon string `json:"icon"`
Expand Down
10 changes: 5 additions & 5 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ require (
github.com/coder/quartz v0.1.3
github.com/coder/retry v1.5.1
github.com/coder/serpent v0.10.0
github.com/coder/terraform-provider-coder/v2 v2.4.1
github.com/coder/terraform-provider-coder/v2 v2.4.3-0.20250519162750-a4f40659a9be
github.com/coder/websocket v1.8.13
github.com/coder/wgtunnel v0.1.13-0.20240522110300-ade90dfb2da0
github.com/coreos/go-oidc/v3 v3.14.1
Expand Down Expand Up @@ -207,7 +207,7 @@ require (
golang.org/x/tools v0.32.0
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da
google.golang.org/api v0.231.0
google.golang.org/grpc v1.72.0
google.golang.org/grpc v1.72.1
google.golang.org/protobuf v1.36.6
gopkg.in/DataDog/dd-trace-go.v1 v1.73.0
gopkg.in/natefinch/lumberjack.v2 v2.2.1
Expand Down Expand Up @@ -333,7 +333,7 @@ require (
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 // indirect
github.com/hashicorp/go-cty v1.5.0 // indirect
github.com/hashicorp/go-hclog v1.6.3 // indirect
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect
Expand All @@ -344,9 +344,9 @@ require (
github.com/hashicorp/hcl v1.0.1-vault-7 // indirect
github.com/hashicorp/hcl/v2 v2.23.0
github.com/hashicorp/logutils v1.0.0 // indirect
github.com/hashicorp/terraform-plugin-go v0.26.0 // indirect
github.com/hashicorp/terraform-plugin-go v0.27.0 // indirect
github.com/hashicorp/terraform-plugin-log v0.9.0 // indirect
github.com/hashicorp/terraform-plugin-sdk/v2 v2.36.1 // indirect
github.com/hashicorp/terraform-plugin-sdk/v2 v2.37.0 // indirect
github.com/hdevalence/ed25519consensus v0.1.0 // indirect
github.com/illarion/gonotify v1.0.1 // indirect
github.com/insomniacslk/dhcp v0.0.0-20231206064809-8c70d406f6d2 // indirect
Expand Down
Loading
Loading