mirror of https://github.com/coder/coder.git
feat: preserve order of rich parameters (#6689)
* WIP * TDD * Implement * WIP
This commit is contained in:
parent
2321160c62
commit
fce8a4adf0
|
@ -99,12 +99,20 @@ func ConvertState(modules []*tfjson.StateModule, rawGraph string) (*State, error
|
|||
// Indexes Terraform resources by their label.
|
||||
// The label is what "terraform graph" uses to reference nodes.
|
||||
tfResourcesByLabel := map[string]map[string]*tfjson.StateResource{}
|
||||
|
||||
// Extra array to preserve the order of rich parameters.
|
||||
tfResourcesRichParameters := make([]*tfjson.StateResource, 0)
|
||||
|
||||
var findTerraformResources func(mod *tfjson.StateModule)
|
||||
findTerraformResources = func(mod *tfjson.StateModule) {
|
||||
for _, module := range mod.ChildModules {
|
||||
findTerraformResources(module)
|
||||
}
|
||||
for _, resource := range mod.Resources {
|
||||
if resource.Type == "coder_parameter" {
|
||||
tfResourcesRichParameters = append(tfResourcesRichParameters, resource)
|
||||
}
|
||||
|
||||
label := convertAddressToLabel(resource.Address)
|
||||
if tfResourcesByLabel[label] == nil {
|
||||
tfResourcesByLabel[label] = map[string]*tfjson.StateResource{}
|
||||
|
@ -434,46 +442,44 @@ func ConvertState(modules []*tfjson.StateModule, rawGraph string) (*State, error
|
|||
}
|
||||
|
||||
parameters := make([]*proto.RichParameter, 0)
|
||||
for _, tfResources := range tfResourcesByLabel {
|
||||
for _, resource := range tfResources {
|
||||
if resource.Type != "coder_parameter" {
|
||||
continue
|
||||
}
|
||||
var param provider.Parameter
|
||||
err = mapstructure.Decode(resource.AttributeValues, ¶m)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("decode map values for coder_parameter.%s: %w", resource.Name, err)
|
||||
}
|
||||
protoParam := &proto.RichParameter{
|
||||
Name: param.Name,
|
||||
Description: param.Description,
|
||||
Type: param.Type,
|
||||
Mutable: param.Mutable,
|
||||
DefaultValue: param.Default,
|
||||
Icon: param.Icon,
|
||||
Required: !param.Optional,
|
||||
LegacyVariableName: param.LegacyVariableName,
|
||||
}
|
||||
if len(param.Validation) == 1 {
|
||||
protoParam.ValidationRegex = param.Validation[0].Regex
|
||||
protoParam.ValidationError = param.Validation[0].Error
|
||||
protoParam.ValidationMax = int32(param.Validation[0].Max)
|
||||
protoParam.ValidationMin = int32(param.Validation[0].Min)
|
||||
protoParam.ValidationMonotonic = param.Validation[0].Monotonic
|
||||
}
|
||||
if len(param.Option) > 0 {
|
||||
protoParam.Options = make([]*proto.RichParameterOption, 0, len(param.Option))
|
||||
for _, option := range param.Option {
|
||||
protoParam.Options = append(protoParam.Options, &proto.RichParameterOption{
|
||||
Name: option.Name,
|
||||
Description: option.Description,
|
||||
Value: option.Value,
|
||||
Icon: option.Icon,
|
||||
})
|
||||
}
|
||||
}
|
||||
parameters = append(parameters, protoParam)
|
||||
for _, resource := range tfResourcesRichParameters {
|
||||
if resource.Type != "coder_parameter" {
|
||||
continue
|
||||
}
|
||||
var param provider.Parameter
|
||||
err = mapstructure.Decode(resource.AttributeValues, ¶m)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("decode map values for coder_parameter.%s: %w", resource.Name, err)
|
||||
}
|
||||
protoParam := &proto.RichParameter{
|
||||
Name: param.Name,
|
||||
Description: param.Description,
|
||||
Type: param.Type,
|
||||
Mutable: param.Mutable,
|
||||
DefaultValue: param.Default,
|
||||
Icon: param.Icon,
|
||||
Required: !param.Optional,
|
||||
LegacyVariableName: param.LegacyVariableName,
|
||||
}
|
||||
if len(param.Validation) == 1 {
|
||||
protoParam.ValidationRegex = param.Validation[0].Regex
|
||||
protoParam.ValidationError = param.Validation[0].Error
|
||||
protoParam.ValidationMax = int32(param.Validation[0].Max)
|
||||
protoParam.ValidationMin = int32(param.Validation[0].Min)
|
||||
protoParam.ValidationMonotonic = param.Validation[0].Monotonic
|
||||
}
|
||||
if len(param.Option) > 0 {
|
||||
protoParam.Options = make([]*proto.RichParameterOption, 0, len(param.Option))
|
||||
for _, option := range param.Option {
|
||||
protoParam.Options = append(protoParam.Options, &proto.RichParameterOption{
|
||||
Name: option.Name,
|
||||
Description: option.Description,
|
||||
Value: option.Value,
|
||||
Icon: option.Icon,
|
||||
})
|
||||
}
|
||||
}
|
||||
parameters = append(parameters, protoParam)
|
||||
}
|
||||
|
||||
// A map is used to ensure we don't have duplicates!
|
||||
|
|
|
@ -279,12 +279,14 @@ func TestConvertResources(t *testing.T) {
|
|||
Name: "dev",
|
||||
Type: "null_resource",
|
||||
Agents: []*proto.Agent{{
|
||||
Name: "dev",
|
||||
OperatingSystem: "windows",
|
||||
Architecture: "arm64",
|
||||
Auth: &proto.Agent_Token{},
|
||||
LoginBeforeReady: true,
|
||||
ConnectionTimeoutSeconds: 120,
|
||||
Name: "dev",
|
||||
OperatingSystem: "windows",
|
||||
ShutdownScriptTimeoutSeconds: 300,
|
||||
StartupScriptTimeoutSeconds: 300,
|
||||
Architecture: "arm64",
|
||||
Auth: &proto.Agent_Token{},
|
||||
LoginBeforeReady: true,
|
||||
ConnectionTimeoutSeconds: 120,
|
||||
}},
|
||||
}},
|
||||
parameters: []*proto.RichParameter{{
|
||||
|
@ -298,6 +300,11 @@ func TestConvertResources(t *testing.T) {
|
|||
Value: "second",
|
||||
}},
|
||||
Required: true,
|
||||
}, {
|
||||
Name: "Sample",
|
||||
Type: "string",
|
||||
Description: "blah blah",
|
||||
DefaultValue: "ok",
|
||||
}},
|
||||
},
|
||||
"git-auth-providers": {
|
||||
|
@ -345,7 +352,6 @@ func TestConvertResources(t *testing.T) {
|
|||
state, err := terraform.ConvertState(modules, string(tfPlanGraph))
|
||||
require.NoError(t, err)
|
||||
sortResources(state.Resources)
|
||||
sortParameters(state.Parameters)
|
||||
sort.Strings(state.GitAuthProviders)
|
||||
|
||||
expectedNoMetadata := make([]*proto.Resource, 0)
|
||||
|
@ -399,7 +405,6 @@ func TestConvertResources(t *testing.T) {
|
|||
state, err := terraform.ConvertState([]*tfjson.StateModule{tfState.Values.RootModule}, string(tfStateGraph))
|
||||
require.NoError(t, err)
|
||||
sortResources(state.Resources)
|
||||
sortParameters(state.Parameters)
|
||||
sort.Strings(state.GitAuthProviders)
|
||||
for _, resource := range state.Resources {
|
||||
for _, agent := range resource.Agents {
|
||||
|
@ -618,14 +623,3 @@ func sortResources(resources []*proto.Resource) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func sortParameters(parameters []*proto.RichParameter) {
|
||||
sort.Slice(parameters, func(i, j int) bool {
|
||||
return parameters[i].Name < parameters[j].Name
|
||||
})
|
||||
for _, parameter := range parameters {
|
||||
sort.Slice(parameter.Options, func(i, j int) bool {
|
||||
return parameter.Options[i].Name < parameter.Options[j].Name
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,11 +2,18 @@ terraform {
|
|||
required_providers {
|
||||
coder = {
|
||||
source = "coder/coder"
|
||||
version = "0.6.6"
|
||||
version = "0.6.20"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data "coder_parameter" "sample" {
|
||||
name = "Sample"
|
||||
type = "string"
|
||||
description = "blah blah"
|
||||
default = "ok"
|
||||
}
|
||||
|
||||
data "coder_parameter" "example" {
|
||||
name = "Example"
|
||||
type = "string"
|
||||
|
|
|
@ -4,15 +4,18 @@ digraph {
|
|||
subgraph "root" {
|
||||
"[root] coder_agent.dev (expand)" [label = "coder_agent.dev", shape = "box"]
|
||||
"[root] data.coder_parameter.example (expand)" [label = "data.coder_parameter.example", shape = "box"]
|
||||
"[root] data.coder_parameter.sample (expand)" [label = "data.coder_parameter.sample", shape = "box"]
|
||||
"[root] null_resource.dev (expand)" [label = "null_resource.dev", shape = "box"]
|
||||
"[root] provider[\"registry.terraform.io/coder/coder\"]" [label = "provider[\"registry.terraform.io/coder/coder\"]", shape = "diamond"]
|
||||
"[root] provider[\"registry.terraform.io/hashicorp/null\"]" [label = "provider[\"registry.terraform.io/hashicorp/null\"]", shape = "diamond"]
|
||||
"[root] coder_agent.dev (expand)" -> "[root] provider[\"registry.terraform.io/coder/coder\"]"
|
||||
"[root] data.coder_parameter.example (expand)" -> "[root] provider[\"registry.terraform.io/coder/coder\"]"
|
||||
"[root] data.coder_parameter.sample (expand)" -> "[root] provider[\"registry.terraform.io/coder/coder\"]"
|
||||
"[root] null_resource.dev (expand)" -> "[root] coder_agent.dev (expand)"
|
||||
"[root] null_resource.dev (expand)" -> "[root] provider[\"registry.terraform.io/hashicorp/null\"]"
|
||||
"[root] provider[\"registry.terraform.io/coder/coder\"] (close)" -> "[root] coder_agent.dev (expand)"
|
||||
"[root] provider[\"registry.terraform.io/coder/coder\"] (close)" -> "[root] data.coder_parameter.example (expand)"
|
||||
"[root] provider[\"registry.terraform.io/coder/coder\"] (close)" -> "[root] data.coder_parameter.sample (expand)"
|
||||
"[root] provider[\"registry.terraform.io/hashicorp/null\"] (close)" -> "[root] null_resource.dev (expand)"
|
||||
"[root] root" -> "[root] provider[\"registry.terraform.io/coder/coder\"] (close)"
|
||||
"[root] root" -> "[root] provider[\"registry.terraform.io/hashicorp/null\"] (close)"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"format_version": "1.1",
|
||||
"terraform_version": "1.2.6",
|
||||
"terraform_version": "1.4.0",
|
||||
"planned_values": {
|
||||
"root_module": {
|
||||
"resources": [
|
||||
|
@ -17,10 +17,13 @@
|
|||
"connection_timeout": 120,
|
||||
"dir": null,
|
||||
"env": null,
|
||||
"login_before_ready": true,
|
||||
"motd_file": null,
|
||||
"os": "windows",
|
||||
"shutdown_script": null,
|
||||
"shutdown_script_timeout": 300,
|
||||
"startup_script": null,
|
||||
"startup_script_timeout": 300,
|
||||
"troubleshooting_url": null
|
||||
},
|
||||
"sensitive_values": {}
|
||||
|
@ -58,10 +61,13 @@
|
|||
"connection_timeout": 120,
|
||||
"dir": null,
|
||||
"env": null,
|
||||
"login_before_ready": true,
|
||||
"motd_file": null,
|
||||
"os": "windows",
|
||||
"shutdown_script": null,
|
||||
"shutdown_script_timeout": 300,
|
||||
"startup_script": null,
|
||||
"startup_script_timeout": 300,
|
||||
"troubleshooting_url": null
|
||||
},
|
||||
"after_unknown": {
|
||||
|
@ -99,7 +105,7 @@
|
|||
],
|
||||
"prior_state": {
|
||||
"format_version": "1.0",
|
||||
"terraform_version": "1.2.6",
|
||||
"terraform_version": "1.4.0",
|
||||
"values": {
|
||||
"root_module": {
|
||||
"resources": [
|
||||
|
@ -114,7 +120,9 @@
|
|||
"default": null,
|
||||
"description": null,
|
||||
"icon": null,
|
||||
"id": "80782610-71f2-45a2-97ea-6029ddbf7ae8",
|
||||
"id": "5820e575-2637-4830-b6a3-75f4c664b447",
|
||||
"legacy_variable": null,
|
||||
"legacy_variable_name": null,
|
||||
"mutable": false,
|
||||
"name": "Example",
|
||||
"option": [
|
||||
|
@ -131,6 +139,7 @@
|
|||
"value": "second"
|
||||
}
|
||||
],
|
||||
"optional": false,
|
||||
"type": "string",
|
||||
"validation": null,
|
||||
"value": ""
|
||||
|
@ -141,6 +150,30 @@
|
|||
{}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"address": "data.coder_parameter.sample",
|
||||
"mode": "data",
|
||||
"type": "coder_parameter",
|
||||
"name": "sample",
|
||||
"provider_name": "registry.terraform.io/coder/coder",
|
||||
"schema_version": 0,
|
||||
"values": {
|
||||
"default": "ok",
|
||||
"description": "blah blah",
|
||||
"icon": null,
|
||||
"id": "9cac2300-0618-45f6-97d9-2f0395b1a0b4",
|
||||
"legacy_variable": null,
|
||||
"legacy_variable_name": null,
|
||||
"mutable": false,
|
||||
"name": "Sample",
|
||||
"option": null,
|
||||
"optional": true,
|
||||
"type": "string",
|
||||
"validation": null,
|
||||
"value": "ok"
|
||||
},
|
||||
"sensitive_values": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -151,7 +184,7 @@
|
|||
"coder": {
|
||||
"name": "coder",
|
||||
"full_name": "registry.terraform.io/coder/coder",
|
||||
"version_constraint": "0.6.6"
|
||||
"version_constraint": "0.6.20"
|
||||
},
|
||||
"null": {
|
||||
"name": "null",
|
||||
|
@ -220,6 +253,28 @@
|
|||
}
|
||||
},
|
||||
"schema_version": 0
|
||||
},
|
||||
{
|
||||
"address": "data.coder_parameter.sample",
|
||||
"mode": "data",
|
||||
"type": "coder_parameter",
|
||||
"name": "sample",
|
||||
"provider_config_key": "coder",
|
||||
"expressions": {
|
||||
"default": {
|
||||
"constant_value": "ok"
|
||||
},
|
||||
"description": {
|
||||
"constant_value": "blah blah"
|
||||
},
|
||||
"name": {
|
||||
"constant_value": "Sample"
|
||||
},
|
||||
"type": {
|
||||
"constant_value": "string"
|
||||
}
|
||||
},
|
||||
"schema_version": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -4,15 +4,18 @@ digraph {
|
|||
subgraph "root" {
|
||||
"[root] coder_agent.dev (expand)" [label = "coder_agent.dev", shape = "box"]
|
||||
"[root] data.coder_parameter.example (expand)" [label = "data.coder_parameter.example", shape = "box"]
|
||||
"[root] data.coder_parameter.sample (expand)" [label = "data.coder_parameter.sample", shape = "box"]
|
||||
"[root] null_resource.dev (expand)" [label = "null_resource.dev", shape = "box"]
|
||||
"[root] provider[\"registry.terraform.io/coder/coder\"]" [label = "provider[\"registry.terraform.io/coder/coder\"]", shape = "diamond"]
|
||||
"[root] provider[\"registry.terraform.io/hashicorp/null\"]" [label = "provider[\"registry.terraform.io/hashicorp/null\"]", shape = "diamond"]
|
||||
"[root] coder_agent.dev (expand)" -> "[root] provider[\"registry.terraform.io/coder/coder\"]"
|
||||
"[root] data.coder_parameter.example (expand)" -> "[root] provider[\"registry.terraform.io/coder/coder\"]"
|
||||
"[root] data.coder_parameter.sample (expand)" -> "[root] provider[\"registry.terraform.io/coder/coder\"]"
|
||||
"[root] null_resource.dev (expand)" -> "[root] coder_agent.dev (expand)"
|
||||
"[root] null_resource.dev (expand)" -> "[root] provider[\"registry.terraform.io/hashicorp/null\"]"
|
||||
"[root] provider[\"registry.terraform.io/coder/coder\"] (close)" -> "[root] coder_agent.dev (expand)"
|
||||
"[root] provider[\"registry.terraform.io/coder/coder\"] (close)" -> "[root] data.coder_parameter.example (expand)"
|
||||
"[root] provider[\"registry.terraform.io/coder/coder\"] (close)" -> "[root] data.coder_parameter.sample (expand)"
|
||||
"[root] provider[\"registry.terraform.io/hashicorp/null\"] (close)" -> "[root] null_resource.dev (expand)"
|
||||
"[root] root" -> "[root] provider[\"registry.terraform.io/coder/coder\"] (close)"
|
||||
"[root] root" -> "[root] provider[\"registry.terraform.io/hashicorp/null\"] (close)"
|
||||
|
|
|
@ -1,33 +1,9 @@
|
|||
{
|
||||
"format_version": "1.0",
|
||||
"terraform_version": "1.2.6",
|
||||
"terraform_version": "1.4.0",
|
||||
"values": {
|
||||
"root_module": {
|
||||
"resources": [
|
||||
{
|
||||
"address": "coder_agent.dev",
|
||||
"mode": "managed",
|
||||
"type": "coder_agent",
|
||||
"name": "dev",
|
||||
"provider_name": "registry.terraform.io/coder/coder",
|
||||
"schema_version": 0,
|
||||
"values": {
|
||||
"arch": "arm64",
|
||||
"auth": "token",
|
||||
"connection_timeout": 120,
|
||||
"dir": null,
|
||||
"env": null,
|
||||
"id": "c816f258-9140-44e9-8f9c-c67b6561106c",
|
||||
"init_script": "",
|
||||
"motd_file": null,
|
||||
"os": "windows",
|
||||
"shutdown_script": null,
|
||||
"startup_script": null,
|
||||
"token": "d8353b78-99d1-4ae0-b895-3dbf08df2a9a",
|
||||
"troubleshooting_url": null
|
||||
},
|
||||
"sensitive_values": {}
|
||||
},
|
||||
{
|
||||
"address": "data.coder_parameter.example",
|
||||
"mode": "data",
|
||||
|
@ -39,7 +15,9 @@
|
|||
"default": null,
|
||||
"description": null,
|
||||
"icon": null,
|
||||
"id": "7f0e325e-0016-4213-8239-c52c678a6a3c",
|
||||
"id": "30b8b963-684d-4c11-9230-a06b81473f6f",
|
||||
"legacy_variable": null,
|
||||
"legacy_variable_name": null,
|
||||
"mutable": false,
|
||||
"name": "Example",
|
||||
"option": [
|
||||
|
@ -56,6 +34,7 @@
|
|||
"value": "second"
|
||||
}
|
||||
],
|
||||
"optional": false,
|
||||
"type": "string",
|
||||
"validation": null,
|
||||
"value": ""
|
||||
|
@ -67,6 +46,57 @@
|
|||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"address": "data.coder_parameter.sample",
|
||||
"mode": "data",
|
||||
"type": "coder_parameter",
|
||||
"name": "sample",
|
||||
"provider_name": "registry.terraform.io/coder/coder",
|
||||
"schema_version": 0,
|
||||
"values": {
|
||||
"default": "ok",
|
||||
"description": "blah blah",
|
||||
"icon": null,
|
||||
"id": "c40e87d2-7694-40f7-8b7d-30dbf14dd0c0",
|
||||
"legacy_variable": null,
|
||||
"legacy_variable_name": null,
|
||||
"mutable": false,
|
||||
"name": "Sample",
|
||||
"option": null,
|
||||
"optional": true,
|
||||
"type": "string",
|
||||
"validation": null,
|
||||
"value": "ok"
|
||||
},
|
||||
"sensitive_values": {}
|
||||
},
|
||||
{
|
||||
"address": "coder_agent.dev",
|
||||
"mode": "managed",
|
||||
"type": "coder_agent",
|
||||
"name": "dev",
|
||||
"provider_name": "registry.terraform.io/coder/coder",
|
||||
"schema_version": 0,
|
||||
"values": {
|
||||
"arch": "arm64",
|
||||
"auth": "token",
|
||||
"connection_timeout": 120,
|
||||
"dir": null,
|
||||
"env": null,
|
||||
"id": "775b9977-421e-4d4d-8c02-dc38958259e3",
|
||||
"init_script": "",
|
||||
"login_before_ready": true,
|
||||
"motd_file": null,
|
||||
"os": "windows",
|
||||
"shutdown_script": null,
|
||||
"shutdown_script_timeout": 300,
|
||||
"startup_script": null,
|
||||
"startup_script_timeout": 300,
|
||||
"token": "927e1872-90d0-43a2-9a55-a8438ead0ad3",
|
||||
"troubleshooting_url": null
|
||||
},
|
||||
"sensitive_values": {}
|
||||
},
|
||||
{
|
||||
"address": "null_resource.dev",
|
||||
"mode": "managed",
|
||||
|
@ -75,7 +105,7 @@
|
|||
"provider_name": "registry.terraform.io/hashicorp/null",
|
||||
"schema_version": 0,
|
||||
"values": {
|
||||
"id": "8669777619875370025",
|
||||
"id": "3727779938861599093",
|
||||
"triggers": null
|
||||
},
|
||||
"sensitive_values": {},
|
||||
|
|
Loading…
Reference in New Issue