From a533bc8321f05a0e2d6b530bc711a14548296eac Mon Sep 17 00:00:00 2001
From: Ethan Dickson <ethan@coder.com>
Date: Thu, 31 Oct 2024 02:23:12 +0000
Subject: [PATCH] fix: skip validating unknown version names

---
 internal/provider/template_resource.go      | 31 +++++++-----
 internal/provider/template_resource_test.go | 56 +++++++++++++++++++++
 2 files changed, 74 insertions(+), 13 deletions(-)

diff --git a/internal/provider/template_resource.go b/internal/provider/template_resource.go
index d296df1..7c1bdd2 100644
--- a/internal/provider/template_resource.go
+++ b/internal/provider/template_resource.go
@@ -896,9 +896,27 @@ func (a *activeVersionValidator) ValidateList(ctx context.Context, req validator
 		return
 	}
 
+	// Check all versions have unique names
+	uniqueNames := make(map[string]struct{})
+	for _, version := range data {
+		if version.Name.IsNull() || version.Name.IsUnknown() {
+			continue
+		}
+		if _, ok := uniqueNames[version.Name.ValueString()]; ok {
+			resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Template version names must be unique. `%s` appears twice.", version.Name.ValueString()))
+			return
+		}
+		uniqueNames[version.Name.ValueString()] = struct{}{}
+	}
+
 	// Check if only one item in Version has active set to true
 	active := false
 	for _, version := range data {
+		// `active` is required, so if it's null or unknown, this is Terraform
+		// requesting an early validation.
+		if version.Active.IsNull() || version.Active.IsUnknown() {
+			return
+		}
 		if version.Active.ValueBool() {
 			if active {
 				resp.Diagnostics.AddError("Client Error", "Only one template version can be active at a time.")
@@ -910,19 +928,6 @@ func (a *activeVersionValidator) ValidateList(ctx context.Context, req validator
 	if !active {
 		resp.Diagnostics.AddError("Client Error", "At least one template version must be active.")
 	}
-
-	// Check all versions have unique names
-	uniqueNames := make(map[string]struct{})
-	for _, version := range data {
-		if version.Name.IsNull() {
-			continue
-		}
-		if _, ok := uniqueNames[version.Name.ValueString()]; ok {
-			resp.Diagnostics.AddError("Client Error", "Template version names must be unique.")
-			return
-		}
-		uniqueNames[version.Name.ValueString()] = struct{}{}
-	}
 }
 
 var _ validator.List = &activeVersionValidator{}
diff --git a/internal/provider/template_resource_test.go b/internal/provider/template_resource_test.go
index 82f19ac..acb07f2 100644
--- a/internal/provider/template_resource_test.go
+++ b/internal/provider/template_resource_test.go
@@ -648,6 +648,62 @@ func TestAccTemplateResourceAGPL(t *testing.T) {
 	})
 }
 
+func TestAccTemplateResourceVariables(t *testing.T) {
+	cfg := `
+provider coderd {
+	url   = "%s"
+	token = "%s"
+}
+
+data "coderd_organization" "default" {
+  is_default = true
+}
+
+variable "PRIOR_GIT_COMMIT_SHA" {
+  default = "abcdef"
+}
+
+variable "CURRENT_GIT_COMMIT_SHA" {
+  default = "ghijkl"
+}
+
+variable "ACTIVE" {
+  default = true
+}
+
+resource "coderd_template" "sample" {
+  name                  = "example-template"
+  versions = [
+    {
+      name = "${var.PRIOR_GIT_COMMIT_SHA}"
+      directory = "../../integration/template-test/example-template"
+      active    = var.ACTIVE
+    },
+    {
+      name = "${var.CURRENT_GIT_COMMIT_SHA}"
+      directory = "../../integration/template-test/example-template"
+      active    = false
+    }
+  ]
+}`
+
+	ctx := context.Background()
+	client := integration.StartCoder(ctx, t, "template_acc", false)
+
+	cfg = fmt.Sprintf(cfg, client.URL.String(), client.SessionToken())
+
+	resource.Test(t, resource.TestCase{
+		PreCheck:                 func() { testAccPreCheck(t) },
+		IsUnitTest:               true,
+		ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
+		Steps: []resource.TestStep{
+			{
+				Config: cfg,
+			},
+		},
+	})
+}
+
 type testAccTemplateResourceConfig struct {
 	URL   string
 	Token string