Skip to content

Return template parameters in consistent order #2975

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 3 commits into from
Jul 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 0 additions & 5 deletions cli/templatecreate.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"fmt"
"os"
"path/filepath"
"sort"
"strings"
"time"

Expand Down Expand Up @@ -226,10 +225,6 @@ func createValidTemplateVersion(cmd *cobra.Command, args createValidTemplateVers
valuesBySchemaID[parameterValue.SchemaID.String()] = parameterValue
}

sort.Slice(parameterSchemas, func(i, j int) bool {
return parameterSchemas[i].Name < parameterSchemas[j].Name
})

// parameterMapFromFile can be nil if parameter file is not specified
var parameterMapFromFile map[string]string
if args.ParameterFile != "" {
Expand Down
4 changes: 4 additions & 0 deletions coderd/database/databasefake/databasefake.go
Original file line number Diff line number Diff line change
Expand Up @@ -1027,6 +1027,9 @@ func (q *fakeQuerier) GetParameterSchemasByJobID(_ context.Context, jobID uuid.U
if len(parameters) == 0 {
return nil, sql.ErrNoRows
}
sort.Slice(parameters, func(i, j int) bool {
return parameters[i].Index < parameters[j].Index
})
return parameters, nil
}

Expand Down Expand Up @@ -1555,6 +1558,7 @@ func (q *fakeQuerier) InsertParameterSchema(_ context.Context, arg database.Inse
ValidationCondition: arg.ValidationCondition,
ValidationTypeSystem: arg.ValidationTypeSystem,
ValidationValueType: arg.ValidationValueType,
Index: arg.Index,
}
q.parameterSchemas = append(q.parameterSchemas, param)
return param, nil
Expand Down
3 changes: 2 additions & 1 deletion coderd/database/dump.sql

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

1 change: 1 addition & 0 deletions coderd/database/migrations/000029_variable_order.down.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE parameter_schemas DROP COLUMN index;
15 changes: 15 additions & 0 deletions coderd/database/migrations/000029_variable_order.up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
-- temporarily create index column as nullable
ALTER TABLE parameter_schemas ADD COLUMN index integer;

-- initialize ordering for existing parameters
WITH tmp AS (
SELECT id, row_number() OVER (PARTITION BY job_id ORDER BY name) AS index
FROM parameter_schemas
)
UPDATE parameter_schemas
SET index = tmp.index
FROM tmp
WHERE parameter_schemas.id = tmp.id;

-- all rows should now be initialized
ALTER TABLE parameter_schemas ALTER COLUMN index SET NOT NULL;
1 change: 1 addition & 0 deletions coderd/database/models.go

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

19 changes: 14 additions & 5 deletions coderd/database/queries.sql.go

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

10 changes: 7 additions & 3 deletions coderd/database/queries/parameterschemas.sql
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ SELECT
FROM
parameter_schemas
WHERE
job_id = $1;
job_id = $1
ORDER BY
index;

-- name: GetParameterSchemasCreatedAfter :many
SELECT * FROM parameter_schemas WHERE created_at > $1;
Expand All @@ -27,7 +29,8 @@ INSERT INTO
validation_error,
validation_condition,
validation_type_system,
validation_value_type
validation_value_type,
index
)
VALUES
(
Expand All @@ -46,5 +49,6 @@ VALUES
$13,
$14,
$15,
$16
$16,
$17
) RETURNING *;
4 changes: 3 additions & 1 deletion coderd/provisionerdaemons.go
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,7 @@ func (server *provisionerdServer) UpdateJob(ctx context.Context, request *proto.
}

if len(request.ParameterSchemas) > 0 {
for _, protoParameter := range request.ParameterSchemas {
for index, protoParameter := range request.ParameterSchemas {
validationTypeSystem, err := convertValidationTypeSystem(protoParameter.ValidationTypeSystem)
if err != nil {
return nil, xerrors.Errorf("convert validation type system for %q: %w", protoParameter.Name, err)
Expand All @@ -428,6 +428,8 @@ func (server *provisionerdServer) UpdateJob(ctx context.Context, request *proto.

AllowOverrideDestination: protoParameter.AllowOverrideDestination,
AllowOverrideSource: protoParameter.AllowOverrideSource,

Index: int32(index),
}

// It's possible a parameter doesn't define a default source!
Expand Down
34 changes: 24 additions & 10 deletions coderd/templateversions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -244,17 +244,30 @@ func TestTemplateVersionParameters(t *testing.T) {
Parse: []*proto.Parse_Response{{
Type: &proto.Parse_Response_Complete{
Complete: &proto.Parse_Complete{
ParameterSchemas: []*proto.ParameterSchema{{
Name: "example",
RedisplayValue: true,
DefaultSource: &proto.ParameterSource{
Scheme: proto.ParameterSource_DATA,
Value: "hello",
ParameterSchemas: []*proto.ParameterSchema{
{
Name: "example",
RedisplayValue: true,
DefaultSource: &proto.ParameterSource{
Scheme: proto.ParameterSource_DATA,
Value: "hello",
},
DefaultDestination: &proto.ParameterDestination{
Scheme: proto.ParameterDestination_PROVISIONER_VARIABLE,
},
},
DefaultDestination: &proto.ParameterDestination{
Scheme: proto.ParameterDestination_PROVISIONER_VARIABLE,
{
Name: "abcd",
RedisplayValue: true,
DefaultSource: &proto.ParameterSource{
Scheme: proto.ParameterSource_DATA,
Value: "world",
},
DefaultDestination: &proto.ParameterDestination{
Scheme: proto.ParameterDestination_PROVISIONER_VARIABLE,
},
},
}},
},
},
},
}},
Expand All @@ -264,8 +277,9 @@ func TestTemplateVersionParameters(t *testing.T) {
params, err := client.TemplateVersionParameters(context.Background(), version.ID)
require.NoError(t, err)
require.NotNil(t, params)
require.Len(t, params, 1)
require.Len(t, params, 2)
require.Equal(t, "hello", params[0].SourceValue)
require.Equal(t, "world", params[1].SourceValue)
})
}

Expand Down
19 changes: 18 additions & 1 deletion provisioner/terraform/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"os"
"path/filepath"
"sort"
"strings"

"github.com/hashicorp/terraform-config-inspect/tfconfig"
Expand All @@ -22,8 +23,17 @@ func (*server) Parse(request *proto.Parse_Request, stream proto.DRPCProvisioner_
return xerrors.Errorf("load module: %s", formatDiagnostics(request.Directory, diags))
}

parameters := make([]*proto.ParameterSchema, 0, len(module.Variables))
// Sort variables by (filename, line) to make the ordering consistent
variables := make([]*tfconfig.Variable, 0, len(module.Variables))
for _, v := range module.Variables {
variables = append(variables, v)
}
sort.Slice(variables, func(i, j int) bool {
return compareSourcePos(variables[i].Pos, variables[j].Pos)
})
Comment on lines +26 to +33
Copy link
Member

Choose a reason for hiding this comment

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

This is pretty cool. It's awesome that customers will be able to control the order that variables display in the UI 👀


parameters := make([]*proto.ParameterSchema, 0, len(variables))
for _, v := range variables {
schema, err := convertVariableToParameter(v)
if err != nil {
return xerrors.Errorf("convert variable %q: %w", v.Name, err)
Expand Down Expand Up @@ -129,3 +139,10 @@ func formatDiagnostics(baseDir string, diags tfconfig.Diagnostics) string {

return spacer + strings.TrimSpace(msgs.String())
}

func compareSourcePos(x, y tfconfig.SourcePos) bool {
if x.Filename != y.Filename {
return x.Filename < y.Filename
}
return x.Line < y.Line
}
52 changes: 52 additions & 0 deletions provisioner/terraform/parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,58 @@ func TestParse(t *testing.T) {
},
ErrorContains: `The ";" character is not valid.`,
},
{
Name: "multiple-variables",
Files: map[string]string{
"main1.tf": `variable "foo" { }
variable "bar" { }`,
"main2.tf": `variable "baz" { }
variable "quux" { }`,
},
Response: &proto.Parse_Response{
Type: &proto.Parse_Response_Complete{
Complete: &proto.Parse_Complete{
ParameterSchemas: []*proto.ParameterSchema{
{
Name: "foo",
RedisplayValue: true,
AllowOverrideSource: true,
Description: "",
DefaultDestination: &proto.ParameterDestination{
Scheme: proto.ParameterDestination_PROVISIONER_VARIABLE,
},
},
{
Name: "bar",
RedisplayValue: true,
AllowOverrideSource: true,
Description: "",
DefaultDestination: &proto.ParameterDestination{
Scheme: proto.ParameterDestination_PROVISIONER_VARIABLE,
},
},
{
Name: "baz",
RedisplayValue: true,
AllowOverrideSource: true,
Description: "",
DefaultDestination: &proto.ParameterDestination{
Scheme: proto.ParameterDestination_PROVISIONER_VARIABLE,
},
},
{
Name: "quux",
RedisplayValue: true,
AllowOverrideSource: true,
Description: "",
DefaultDestination: &proto.ParameterDestination{
Scheme: proto.ParameterDestination_PROVISIONER_VARIABLE,
},
}},
},
},
},
},
}

for _, testCase := range testCases {
Expand Down