From 979aeb5bfdeb58c8da278988fb3eeae4b90f511d Mon Sep 17 00:00:00 2001 From: Cian Johnston Date: Wed, 29 Oct 2025 21:01:40 +0000 Subject: [PATCH 01/14] chore(integration): fix failing coder-ai-task integration test (#456) --- integration/integration_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/integration/integration_test.go b/integration/integration_test.go index 4ff35e06..71e5256d 100644 --- a/integration/integration_test.go +++ b/integration/integration_test.go @@ -43,7 +43,7 @@ func TestIntegration(t *testing.T) { coderImg := os.Getenv("CODER_IMAGE") if coderImg == "" { - coderImg = "ghcr.io/coder/coder" + coderImg = "ghcr.io/coder/coder-preview" } coderVersion := os.Getenv("CODER_VERSION") @@ -215,10 +215,10 @@ func TestIntegration(t *testing.T) { name: "coder-ai-task", minVersion: "v2.26.0", expectedOutput: map[string]string{ - "ai_task.id": `^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$`, + "ai_task.id": `^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$`, "ai_task.prompt": "default", - "ai_task.app_id": `^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$`, - "app.id": `^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$`, + "ai_task.app_id": `^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$`, + "app.id": `^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$`, }, }, } { From a86ce822bdc80aaf10178f78e159359a28a4d9a9 Mon Sep 17 00:00:00 2001 From: Michael Patterson Date: Thu, 30 Oct 2025 09:43:21 -0500 Subject: [PATCH 02/14] chore(deps): update Go version to 1.24.6 (#453) * chore(deps): update Go version to 1.24.6 Update Go version from 1.24.2 to 1.24.6 to resolve vulnerability reports in transitive dependencies. This update addresses security issues in SQL and Git packages that, while not directly used by the provider, are causing artifact repository blocks. Fixes #452 * chore(deps): update Go version in release workflow Update Go version in release.yml to match go.mod version (1.24.6) --- .github/workflows/release.yml | 4 ++-- .github/workflows/test.yml | 6 +++--- go.mod | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d52ff5cd..4cc18ae2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -28,7 +28,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v6 with: - go-version: "1.24.2" + go-version: "1.24.6" id: go - name: Get dependencies @@ -86,7 +86,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v6 with: - go-version: "1.24.2" + go-version: "1.24.6" - name: Import GPG key id: import_gpg diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d93f59f7..1a909288 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -28,7 +28,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v6 with: - go-version: "1.24.2" + go-version: "1.24.6" id: go - name: Get dependencies @@ -104,7 +104,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v6 with: - go-version: "1.24.2" + go-version: "1.24.6" id: go - uses: hashicorp/setup-terraform@v3 @@ -137,7 +137,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v6 with: - go-version: "1.24.2" + go-version: "1.24.6" id: go - uses: hashicorp/setup-terraform@v3 diff --git a/go.mod b/go.mod index bee6e849..11bec153 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/coder/terraform-provider-coder/v2 -go 1.24.2 +go 1.24.6 require ( github.com/docker/docker v26.1.5+incompatible From fc9724be572ff7d97eb9d6af4ffd90c587a43e28 Mon Sep 17 00:00:00 2001 From: Danielle Maywood Date: Fri, 31 Oct 2025 10:32:46 +0000 Subject: [PATCH 03/14] fix: set default value for `coder_ai_task.prompt` to an empty string (#458) --- integration/integration_test.go | 2 +- provider/ai_task.go | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/integration/integration_test.go b/integration/integration_test.go index 71e5256d..9cba9b04 100644 --- a/integration/integration_test.go +++ b/integration/integration_test.go @@ -216,7 +216,7 @@ func TestIntegration(t *testing.T) { minVersion: "v2.26.0", expectedOutput: map[string]string{ "ai_task.id": `^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$`, - "ai_task.prompt": "default", + "ai_task.prompt": "", "ai_task.app_id": `^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$`, "app.id": `^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$`, }, diff --git a/provider/ai_task.go b/provider/ai_task.go index 6ceda464..71f7ef60 100644 --- a/provider/ai_task.go +++ b/provider/ai_task.go @@ -45,8 +45,6 @@ func aiTaskResource() *schema.Resource { if prompt := os.Getenv("CODER_TASK_PROMPT"); prompt != "" { resourceData.Set("prompt", prompt) - } else { - resourceData.Set("prompt", "default") } var ( From 1211f288075b8b04a30864833cf447f9a82ec8ba Mon Sep 17 00:00:00 2001 From: Danielle Maywood Date: Fri, 31 Oct 2025 11:32:50 +0000 Subject: [PATCH 04/14] feat: add `enabled` computed field to `coder_ai_task` (#451) As discussed, we want to enable a way for consumers to know if their template is being provisioned as a task or not. We know that if `CODER_TASK_ID` is set by the provisioner, it is being provisioned as a task, and not as workspace. We use this knowledge to set a computed field `enabled` to reflect this. --- docs/resources/ai_task.md | 1 + integration/coder-ai-task/main.tf | 9 ++--- integration/integration_test.go | 9 ++--- provider/ai_task.go | 16 +++++---- provider/ai_task_test.go | 58 +++++++++++++++++++++++++++++++ 5 files changed, 78 insertions(+), 15 deletions(-) diff --git a/docs/resources/ai_task.md b/docs/resources/ai_task.md index bd5cfcdd..80c3f419 100644 --- a/docs/resources/ai_task.md +++ b/docs/resources/ai_task.md @@ -22,6 +22,7 @@ Use this resource to define Coder tasks. ### Read-Only +- `enabled` (Boolean) True when executing in a Coder Task context, false when in a Coder Workspace context - `id` (String) A unique identifier for this resource. - `prompt` (String) The prompt text provided to the task by Coder. diff --git a/integration/coder-ai-task/main.tf b/integration/coder-ai-task/main.tf index 263d7298..aed9a796 100644 --- a/integration/coder-ai-task/main.tf +++ b/integration/coder-ai-task/main.tf @@ -41,10 +41,11 @@ resource "coder_ai_task" "task" { locals { # NOTE: these must all be strings in the output output = { - "ai_task.id" = coder_ai_task.task.id - "ai_task.app_id" = coder_ai_task.task.app_id - "ai_task.prompt" = coder_ai_task.task.prompt - "app.id" = coder_app.ai_interface.id + "ai_task.id" = coder_ai_task.task.id + "ai_task.app_id" = coder_ai_task.task.app_id + "ai_task.prompt" = coder_ai_task.task.prompt + "ai_task.enabled" = tostring(coder_ai_task.task.enabled) + "app.id" = coder_app.ai_interface.id } } diff --git a/integration/integration_test.go b/integration/integration_test.go index 9cba9b04..c86397da 100644 --- a/integration/integration_test.go +++ b/integration/integration_test.go @@ -215,10 +215,11 @@ func TestIntegration(t *testing.T) { name: "coder-ai-task", minVersion: "v2.26.0", expectedOutput: map[string]string{ - "ai_task.id": `^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$`, - "ai_task.prompt": "", - "ai_task.app_id": `^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$`, - "app.id": `^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$`, + "ai_task.id": `^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$`, + "ai_task.prompt": "", + "ai_task.app_id": `^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$`, + "ai_task.enabled": "false", + "app.id": `^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$`, }, }, } { diff --git a/provider/ai_task.go b/provider/ai_task.go index 71f7ef60..01baf9ea 100644 --- a/provider/ai_task.go +++ b/provider/ai_task.go @@ -32,15 +32,12 @@ func aiTaskResource() *schema.Resource { CreateContext: func(c context.Context, resourceData *schema.ResourceData, i any) diag.Diagnostics { var diags diag.Diagnostics - if idStr := os.Getenv("CODER_TASK_ID"); idStr != "" { - resourceData.SetId(idStr) + if id, err := uuid.Parse(os.Getenv("CODER_TASK_ID")); err == nil && id != uuid.Nil { + resourceData.SetId(id.String()) + resourceData.Set("enabled", true) } else { resourceData.SetId(uuid.NewString()) - - diags = append(diags, diag.Diagnostic{ - Severity: diag.Warning, - Summary: "`CODER_TASK_ID` should be set. If you are seeing this message, the version of the Coder Terraform provider you are using is likely too new for your current Coder version.", - }) + resourceData.Set("enabled", false) } if prompt := os.Getenv("CODER_TASK_PROMPT"); prompt != "" { @@ -110,6 +107,11 @@ func aiTaskResource() *schema.Resource { ValidateFunc: validation.IsUUID, ConflictsWith: []string{"sidebar_app"}, }, + "enabled": { + Type: schema.TypeBool, + Description: "True when executing in a Coder Task context, false when in a Coder Workspace context", + Computed: true, + }, }, } } diff --git a/provider/ai_task_test.go b/provider/ai_task_test.go index d7357646..3108fb9d 100644 --- a/provider/ai_task_test.go +++ b/provider/ai_task_test.go @@ -9,6 +9,62 @@ import ( "github.com/stretchr/testify/require" ) +func TestAITask_Enabled(t *testing.T) { + t.Run("EnabledWhenTask", func(t *testing.T) { + t.Setenv("CODER_TASK_ID", "7d8d4c2e-fb57-44f9-a183-22509819c2e7") + + resource.Test(t, resource.TestCase{ + ProviderFactories: coderFactory(), + IsUnitTest: true, + Steps: []resource.TestStep{{ + Config: ` + provider "coder" { + } + resource "coder_ai_task" "test" { + app_id = "9a3ff7b4-4b3f-48c6-8d3a-a8118ac921fc" + } + `, + Check: func(state *terraform.State) error { + require.Len(t, state.Modules, 1) + resource := state.Modules[0].Resources["coder_ai_task.test"] + require.NotNil(t, resource) + + require.Equal(t, "true", resource.Primary.Attributes["enabled"]) + + return nil + }, + }}, + }) + }) + + t.Run("DisabledWhenWorkspace", func(t *testing.T) { + t.Setenv("CODER_TASK_ID", "") + + resource.Test(t, resource.TestCase{ + ProviderFactories: coderFactory(), + IsUnitTest: true, + Steps: []resource.TestStep{{ + Config: ` + provider "coder" { + } + resource "coder_ai_task" "test" { + app_id = "9a3ff7b4-4b3f-48c6-8d3a-a8118ac921fc" + } + `, + Check: func(state *terraform.State) error { + require.Len(t, state.Modules, 1) + resource := state.Modules[0].Resources["coder_ai_task.test"] + require.NotNil(t, resource) + + require.Equal(t, "false", resource.Primary.Attributes["enabled"]) + + return nil + }, + }}, + }) + }) +} + func TestAITask(t *testing.T) { t.Setenv("CODER_TASK_ID", "7d8d4c2e-fb57-44f9-a183-22509819c2e7") t.Setenv("CODER_TASK_PROMPT", "some task prompt") @@ -35,6 +91,7 @@ func TestAITask(t *testing.T) { "id", "prompt", "app_id", + "enabled", } { value := resource.Primary.Attributes[key] require.NotNil(t, value) @@ -97,6 +154,7 @@ func TestAITask(t *testing.T) { "id", "prompt", "app_id", + "enabled", } { value := resource.Primary.Attributes[key] require.NotNil(t, value) From e0b1ec1db3b93bfc3c9f1ee1ecf4a6c825d4310a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 31 Oct 2025 16:56:56 +0500 Subject: [PATCH 05/14] build(deps): Bump goreleaser/goreleaser-action from 6.3.0 to 6.4.0 (#427) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4cc18ae2..d7e1201d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -97,7 +97,7 @@ jobs: passphrase: ${{ secrets.PASSPHRASE }} - name: Run GoReleaser - uses: goreleaser/goreleaser-action@v6.3.0 + uses: goreleaser/goreleaser-action@v6.4.0 with: version: '~> v2' args: release --clean From 5fe8d857e52a2bcc84ae10d46a85491361fe2d63 Mon Sep 17 00:00:00 2001 From: Cian Johnston Date: Tue, 4 Nov 2025 10:20:05 +0000 Subject: [PATCH 06/14] feat: add coder_task data source (#460) Adds a `coder_task` data source to support use cases that would otherwise cause a cycle error. --- docs/data-sources/task.md | 43 ++++++++++ .../data-sources/coder_task/data-source.tf | 14 ++++ integration/coder-ai-task/main.tf | 6 ++ integration/integration_test.go | 4 +- provider/ai_task.go | 40 +++++++++ provider/ai_task_test.go | 81 +++++++++++++++++++ provider/helpers/validation.go | 2 +- provider/provider.go | 1 + provider/provider_test.go | 3 +- provider/script_test.go | 8 +- 10 files changed, 195 insertions(+), 7 deletions(-) create mode 100644 docs/data-sources/task.md create mode 100644 examples/data-sources/coder_task/data-source.tf diff --git a/docs/data-sources/task.md b/docs/data-sources/task.md new file mode 100644 index 00000000..43396eae --- /dev/null +++ b/docs/data-sources/task.md @@ -0,0 +1,43 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "coder_task Data Source - terraform-provider-coder" +subcategory: "" +description: |- + Use this data source to read information about Coder Tasks. +--- + +# coder_task (Data Source) + +Use this data source to read information about Coder Tasks. + +## Example Usage + +```terraform +provider "coder" {} + +data "coder_workspace" "me" {} +data "coder_task" "me" {} + +resource "coder_ai_task" "task" { + count = data.coder_task.me.enabled ? data.coder_workspace.me.start_count : 0 + app_id = module.example-agent.task_app_id +} + +module "example-agent" { + count = data.coder_task.me.enabled ? data.coder_workspace.me.start_count : 0 + prompt = data.coder_ai_task.me.prompt +} +``` + + +## Schema + +### Read-Only + +- `enabled` (Boolean) True when executing in a Coder Task context, false when in a Coder Workspace context. + + -> The `enabled` field is only populated in Coder v2.28 and later. +- `id` (String) The UUID of the task, if executing in a Coder Task context. Empty in a Coder Workspace context. +- `prompt` (String) The prompt text provided to the task by Coder, if executing in a Coder Task context. Empty in a Coder Workspace context. + + -> The `prompt` field is only populated in Coder v2.28 and later. diff --git a/examples/data-sources/coder_task/data-source.tf b/examples/data-sources/coder_task/data-source.tf new file mode 100644 index 00000000..af2098e1 --- /dev/null +++ b/examples/data-sources/coder_task/data-source.tf @@ -0,0 +1,14 @@ +provider "coder" {} + +data "coder_workspace" "me" {} +data "coder_task" "me" {} + +resource "coder_ai_task" "task" { + count = data.coder_task.me.enabled ? data.coder_workspace.me.start_count : 0 + app_id = module.example-agent.task_app_id +} + +module "example-agent" { + count = data.coder_task.me.enabled ? data.coder_workspace.me.start_count : 0 + prompt = data.coder_ai_task.me.prompt +} diff --git a/integration/coder-ai-task/main.tf b/integration/coder-ai-task/main.tf index aed9a796..50e5289d 100644 --- a/integration/coder-ai-task/main.tf +++ b/integration/coder-ai-task/main.tf @@ -32,6 +32,8 @@ data "coder_parameter" "ai_prompt" { mutable = true } +data "coder_task" "me" {} + resource "coder_ai_task" "task" { sidebar_app { id = coder_app.ai_interface.id @@ -46,6 +48,10 @@ locals { "ai_task.prompt" = coder_ai_task.task.prompt "ai_task.enabled" = tostring(coder_ai_task.task.enabled) "app.id" = coder_app.ai_interface.id + + "task.id" = data.coder_task.me.id + "task.prompt" = data.coder_task.me.prompt + "task.enabled" = tostring(data.coder_task.me.enabled) } } diff --git a/integration/integration_test.go b/integration/integration_test.go index c86397da..bc6fac96 100644 --- a/integration/integration_test.go +++ b/integration/integration_test.go @@ -220,10 +220,12 @@ func TestIntegration(t *testing.T) { "ai_task.app_id": `^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$`, "ai_task.enabled": "false", "app.id": `^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$`, + "task.id": `^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$`, + "task.prompt": "", + "task.enabled": "false", }, }, } { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() if coderVersion != "latest" && semver.Compare(coderVersion, tt.minVersion) < 0 { diff --git a/provider/ai_task.go b/provider/ai_task.go index 01baf9ea..281299b3 100644 --- a/provider/ai_task.go +++ b/provider/ai_task.go @@ -115,3 +115,43 @@ func aiTaskResource() *schema.Resource { }, } } + +func taskDatasource() *schema.Resource { + return &schema.Resource{ + Description: "Use this data source to read information about Coder Tasks.", + ReadContext: func(ctx context.Context, rd *schema.ResourceData, i interface{}) diag.Diagnostics { + diags := diag.Diagnostics{} + + idStr := os.Getenv("CODER_TASK_ID") + if idStr == "" || idStr == uuid.Nil.String() { + rd.SetId(uuid.NewString()) + _ = rd.Set("enabled", false) + } else if _, err := uuid.Parse(idStr); err == nil { + rd.SetId(idStr) + _ = rd.Set("enabled", true) + } else { // invalid UUID + diags = append(diags, errorAsDiagnostics(err)...) + } + + _ = rd.Set("prompt", os.Getenv("CODER_TASK_PROMPT")) + return diags + }, + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The UUID of the task, if executing in a Coder Task context. Empty in a Coder Workspace context.", + }, + "prompt": { + Type: schema.TypeString, + Computed: true, + Description: "The prompt text provided to the task by Coder, if executing in a Coder Task context. Empty in a Coder Workspace context.\n\n -> The `prompt` field is only populated in Coder v2.28 and later.", + }, + "enabled": { + Type: schema.TypeBool, + Computed: true, + Description: "True when executing in a Coder Task context, false when in a Coder Workspace context.\n\n -> The `enabled` field is only populated in Coder v2.28 and later.", + }, + }, + } +} diff --git a/provider/ai_task_test.go b/provider/ai_task_test.go index 3108fb9d..a67ba060 100644 --- a/provider/ai_task_test.go +++ b/provider/ai_task_test.go @@ -4,6 +4,7 @@ import ( "regexp" "testing" + "github.com/google/uuid" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "github.com/stretchr/testify/require" @@ -214,3 +215,83 @@ func TestAITask(t *testing.T) { }) }) } + +func TestTaskDatasource(t *testing.T) { + t.Run("Exists", func(t *testing.T) { + t.Setenv("CODER_TASK_ID", "7d8d4c2e-fb57-44f9-a183-22509819c2e7") + t.Setenv("CODER_TASK_PROMPT", "some task prompt") + resource.Test(t, resource.TestCase{ + ProviderFactories: coderFactory(), + IsUnitTest: true, + Steps: []resource.TestStep{{ + Config: ` + provider "coder" {} + data "coder_task" "me" {} + `, + Check: func(s *terraform.State) error { + require.Len(t, s.Modules, 1) + require.Len(t, s.Modules[0].Resources, 1) + resource := s.Modules[0].Resources["data.coder_task.me"] + require.NotNil(t, resource) + + taskID := resource.Primary.Attributes["id"] + require.Equal(t, "7d8d4c2e-fb57-44f9-a183-22509819c2e7", taskID) + + taskPromptValue := resource.Primary.Attributes["prompt"] + require.Equal(t, "some task prompt", taskPromptValue) + + enabledValue := resource.Primary.Attributes["enabled"] + require.Equal(t, "true", enabledValue) + return nil + }, + }}, + }) + }) + + t.Run("NotExists", func(t *testing.T) { + resource.Test(t, resource.TestCase{ + ProviderFactories: coderFactory(), + IsUnitTest: true, + Steps: []resource.TestStep{{ + Config: ` + provider "coder" {} + data "coder_task" "me" {} + `, + Check: func(s *terraform.State) error { + require.Len(t, s.Modules, 1) + require.Len(t, s.Modules[0].Resources, 1) + resource := s.Modules[0].Resources["data.coder_task.me"] + require.NotNil(t, resource) + + taskID := resource.Primary.Attributes["id"] + require.NotEmpty(t, taskID) + require.NotEqual(t, uuid.Nil.String(), taskID) + _, err := uuid.Parse(taskID) + require.NoError(t, err) + + taskPromptValue := resource.Primary.Attributes["prompt"] + require.Empty(t, taskPromptValue) + + enabledValue := resource.Primary.Attributes["enabled"] + require.Equal(t, "false", enabledValue) + return nil + }, + }}, + }) + }) + + t.Run("InvalidTaskID", func(t *testing.T) { + t.Setenv("CODER_TASK_ID", "not a valid UUID") + resource.Test(t, resource.TestCase{ + ProviderFactories: coderFactory(), + IsUnitTest: true, + Steps: []resource.TestStep{{ + Config: ` + provider "coder" {} + data "coder_task" "me" {} + `, + ExpectError: regexp.MustCompile(`invalid UUID`), + }}, + }) + }) +} diff --git a/provider/helpers/validation.go b/provider/helpers/validation.go index 9cc21b89..e58a3b03 100644 --- a/provider/helpers/validation.go +++ b/provider/helpers/validation.go @@ -17,6 +17,6 @@ func ValidateURL(value any, label string) ([]string, []error) { if _, err := url.Parse(val); err != nil { return nil, []error{err} } - + return nil, nil } diff --git a/provider/provider.go b/provider/provider.go index 2b6409ba..7e4451b8 100644 --- a/provider/provider.go +++ b/provider/provider.go @@ -64,6 +64,7 @@ func New() *schema.Provider { "coder_external_auth": externalAuthDataSource(), "coder_workspace_owner": workspaceOwnerDataSource(), "coder_workspace_preset": workspacePresetDataSource(), + "coder_task": taskDatasource(), }, ResourcesMap: map[string]*schema.Resource{ "coder_agent": agentResource(), diff --git a/provider/provider_test.go b/provider/provider_test.go index 4bf98b32..606ae72b 100644 --- a/provider/provider_test.go +++ b/provider/provider_test.go @@ -37,7 +37,8 @@ func TestProviderEmpty(t *testing.T) { } data "coder_parameter" "param" { name = "hey" - }`, + } + data "coder_task" "me" {}`, Check: func(state *terraform.State) error { return nil }, diff --git a/provider/script_test.go b/provider/script_test.go index 64808372..8e6221f1 100644 --- a/provider/script_test.go +++ b/provider/script_test.go @@ -131,10 +131,10 @@ func TestValidateCronExpression(t *testing.T) { t.Parallel() tests := []struct { - name string - cronExpr string - expectWarnings bool - expectErrors bool + name string + cronExpr string + expectWarnings bool + expectErrors bool warningContains string }{ { From 297687916cce0bc942ef85063485f77b33292ddd Mon Sep 17 00:00:00 2001 From: Danielle Maywood Date: Tue, 4 Nov 2025 05:40:19 -0500 Subject: [PATCH 07/14] docs(coder_ai_task): add min coder version for `prompt` and `enabled` (#459) * docs(coder_ai_task): add min coder version for `prompt` and `enabled` * indent callouts --------- Co-authored-by: Cian Johnston --- docs/resources/ai_task.md | 6 +++++- provider/ai_task.go | 4 ++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/resources/ai_task.md b/docs/resources/ai_task.md index 80c3f419..3619c680 100644 --- a/docs/resources/ai_task.md +++ b/docs/resources/ai_task.md @@ -22,10 +22,14 @@ Use this resource to define Coder tasks. ### Read-Only -- `enabled` (Boolean) True when executing in a Coder Task context, false when in a Coder Workspace context +- `enabled` (Boolean) True when executing in a Coder Task context, false when in a Coder Workspace context. + + -> The `enabled` field is only populated in Coder v2.28 and later. - `id` (String) A unique identifier for this resource. - `prompt` (String) The prompt text provided to the task by Coder. + -> The `prompt` field is only populated in Coder v2.28 and later. + ### Nested Schema for `sidebar_app` diff --git a/provider/ai_task.go b/provider/ai_task.go index 281299b3..1bb6cf65 100644 --- a/provider/ai_task.go +++ b/provider/ai_task.go @@ -95,7 +95,7 @@ func aiTaskResource() *schema.Resource { }, "prompt": { Type: schema.TypeString, - Description: "The prompt text provided to the task by Coder.", + Description: "The prompt text provided to the task by Coder.\n\n -> The `prompt` field is only populated in Coder v2.28 and later.", Computed: true, }, "app_id": { @@ -109,7 +109,7 @@ func aiTaskResource() *schema.Resource { }, "enabled": { Type: schema.TypeBool, - Description: "True when executing in a Coder Task context, false when in a Coder Workspace context", + Description: "True when executing in a Coder Task context, false when in a Coder Workspace context.\n\n -> The `enabled` field is only populated in Coder v2.28 and later.", Computed: true, }, }, From 5c4def2ee8c73b210c9e345bba86263bfdc66437 Mon Sep 17 00:00:00 2001 From: Cian Johnston Date: Wed, 5 Nov 2025 09:59:42 +0000 Subject: [PATCH 08/14] chore(README.md): add note regarding multiple tags (#461) --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4ae9be15..cff57558 100644 --- a/README.md +++ b/README.md @@ -87,15 +87,21 @@ To run these integration tests locally: > For example, `CODER_IMAGE=example.com/repo/coder CODER_VERSION=foobar make test-integration`. ### How to create a new release + > [!Warning] -> Before creating a new release, make sure you have pulled the latest commit from the main branch i.e. `git pull origin main` +> +> - Before creating a new release, make sure you have pulled the latest commit from the main branch i.e. `git pull origin main` +> - If you have already published a previous tag, make sure you do not tag the same commit with the new tag. +> See: [goreleaser-action/512](https://github.com/goreleaser/goreleaser-action/issues/512) 1. Create a new tag with a version number (following semantic versioning): + ```console git tag -a v2.1.2 -m "v2.1.2" ``` 2. Push the tag to the remote repository: + ```console git push origin tag v2.1.2 ``` From c822a5f1bee83226e6ab548157ae17a9c7353e77 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 Nov 2025 09:16:26 +0000 Subject: [PATCH 09/14] build(deps): Bump golang.org/x/mod from 0.29.0 to 0.30.0 (#463) Bumps [golang.org/x/mod](https://github.com/golang/mod) from 0.29.0 to 0.30.0. - [Commits](https://github.com/golang/mod/compare/v0.29.0...v0.30.0) --- updated-dependencies: - dependency-name: golang.org/x/mod dependency-version: 0.30.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 12 ++++++------ go.sum | 24 ++++++++++++------------ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/go.mod b/go.mod index 11bec153..f5fdb42d 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/robfig/cron/v3 v3.0.1 github.com/stretchr/testify v1.11.0 golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 - golang.org/x/mod v0.29.0 + golang.org/x/mod v0.30.0 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 ) @@ -78,13 +78,13 @@ require ( go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.27.0 // indirect go.opentelemetry.io/otel/metric v1.37.0 // indirect go.opentelemetry.io/otel/trace v1.37.0 // indirect - golang.org/x/crypto v0.42.0 // indirect - golang.org/x/net v0.44.0 // indirect + golang.org/x/crypto v0.43.0 // indirect + golang.org/x/net v0.46.0 // indirect golang.org/x/sync v0.17.0 // indirect - golang.org/x/sys v0.36.0 // indirect - golang.org/x/text v0.29.0 // indirect + golang.org/x/sys v0.37.0 // indirect + golang.org/x/text v0.30.0 // indirect golang.org/x/time v0.5.0 // indirect - golang.org/x/tools v0.37.0 // indirect + golang.org/x/tools v0.38.0 // indirect google.golang.org/appengine v1.6.8 // indirect google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect google.golang.org/grpc v1.75.1 // indirect diff --git a/go.sum b/go.sum index c4d9af40..66c0f1b4 100644 --- a/go.sum +++ b/go.sum @@ -226,23 +226,23 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI= -golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8= +golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04= +golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0= golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY= golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA= -golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w= +golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= +golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.44.0 h1:evd8IRDyfNBMBTTY5XRF1vaZlD+EmWx6x8PkhR04H/I= -golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= +golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4= +golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -264,16 +264,16 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k= -golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= +golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk= -golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4= +golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= +golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -281,8 +281,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE= -golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w= +golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ= +golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= From 60377bb12b7593f11f23a986e8a386d5566a0718 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 28 Nov 2025 15:26:57 +0500 Subject: [PATCH 10/14] build(deps): Bump actions/checkout from 5 to 6 (#468) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 4 ++-- .github/workflows/test.yml | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d7e1201d..8481aa8d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -20,7 +20,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out code into the Go module directory - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Check Go Versions run: ./scripts/check_go_version.sh @@ -75,7 +75,7 @@ jobs: needs: test steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Check Go Versions run: ./scripts/check_go_version.sh diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1a909288..0141f75e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -20,7 +20,7 @@ jobs: timeout-minutes: 5 steps: - name: Check out code into the Go module directory - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Check Go Versions run: ./scripts/check_go_version.sh @@ -96,7 +96,7 @@ jobs: - "1.11.*" steps: - name: Check out code into the Go module directory - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Check Go Versions run: ./scripts/check_go_version.sh @@ -129,7 +129,7 @@ jobs: timeout-minutes: 5 steps: - name: Check out code into the Go module directory - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Check Go Versions run: ./scripts/check_go_version.sh From dd6246532b4f0047c0125bdcd70f6e900ca69d65 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 28 Nov 2025 15:27:15 +0500 Subject: [PATCH 11/14] build(deps): Bump golang.org/x/crypto from 0.43.0 to 0.45.0 (#467) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 10 +++++----- go.sum | 20 ++++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/go.mod b/go.mod index f5fdb42d..1aada9b0 100644 --- a/go.mod +++ b/go.mod @@ -78,11 +78,11 @@ require ( go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.27.0 // indirect go.opentelemetry.io/otel/metric v1.37.0 // indirect go.opentelemetry.io/otel/trace v1.37.0 // indirect - golang.org/x/crypto v0.43.0 // indirect - golang.org/x/net v0.46.0 // indirect - golang.org/x/sync v0.17.0 // indirect - golang.org/x/sys v0.37.0 // indirect - golang.org/x/text v0.30.0 // indirect + golang.org/x/crypto v0.45.0 // indirect + golang.org/x/net v0.47.0 // indirect + golang.org/x/sync v0.18.0 // indirect + golang.org/x/sys v0.38.0 // indirect + golang.org/x/text v0.31.0 // indirect golang.org/x/time v0.5.0 // indirect golang.org/x/tools v0.38.0 // indirect google.golang.org/appengine v1.6.8 // indirect diff --git a/go.sum b/go.sum index 66c0f1b4..a4781272 100644 --- a/go.sum +++ b/go.sum @@ -226,8 +226,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04= -golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0= +golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= +golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY= golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -241,15 +241,15 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4= -golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= +golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= +golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= -golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= +golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -264,16 +264,16 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= -golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= +golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= -golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= +golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= +golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= From 9cfd35f441fa567150ecd5aa97c5f854a2800182 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 28 Nov 2025 15:27:47 +0500 Subject: [PATCH 12/14] build(deps): Bump github.com/hashicorp/terraform-plugin-log (#465) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 1aada9b0..30280981 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/docker/docker v26.1.5+incompatible github.com/google/uuid v1.6.0 github.com/hashicorp/go-cty v1.5.0 - github.com/hashicorp/terraform-plugin-log v0.9.0 + github.com/hashicorp/terraform-plugin-log v0.10.0 github.com/hashicorp/terraform-plugin-sdk/v2 v2.38.1 github.com/masterminds/semver v1.5.0 github.com/mitchellh/mapstructure v1.5.0 diff --git a/go.sum b/go.sum index a4781272..5bd42620 100644 --- a/go.sum +++ b/go.sum @@ -107,8 +107,8 @@ github.com/hashicorp/terraform-json v0.27.1 h1:zWhEracxJW6lcjt/JvximOYyc12pS/gaK github.com/hashicorp/terraform-json v0.27.1/go.mod h1:GzPLJ1PLdUG5xL6xn1OXWIjteQRT2CNT9o/6A9mi9hE= github.com/hashicorp/terraform-plugin-go v0.29.0 h1:1nXKl/nSpaYIUBU1IG/EsDOX0vv+9JxAltQyDMpq5mU= github.com/hashicorp/terraform-plugin-go v0.29.0/go.mod h1:vYZbIyvxyy0FWSmDHChCqKvI40cFTDGSb3D8D70i9GM= -github.com/hashicorp/terraform-plugin-log v0.9.0 h1:i7hOA+vdAItN1/7UrfBqBwvYPQ9TFvymaRGZED3FCV0= -github.com/hashicorp/terraform-plugin-log v0.9.0/go.mod h1:rKL8egZQ/eXSyDqzLUuwUYLVdlYeamldAHSxjUFADow= +github.com/hashicorp/terraform-plugin-log v0.10.0 h1:eu2kW6/QBVdN4P3Ju2WiB2W3ObjkAsyfBsL3Wh1fj3g= +github.com/hashicorp/terraform-plugin-log v0.10.0/go.mod h1:/9RR5Cv2aAbrqcTSdNmY1NRHP4E3ekrXRGjqORpXyB0= github.com/hashicorp/terraform-plugin-sdk/v2 v2.38.1 h1:mlAq/OrMlg04IuJT7NpefI1wwtdpWudnEmjuQs04t/4= github.com/hashicorp/terraform-plugin-sdk/v2 v2.38.1/go.mod h1:GQhpKVvvuwzD79e8/NZ+xzj+ZpWovdPAe8nfV/skwNU= github.com/hashicorp/terraform-registry-address v0.4.0 h1:S1yCGomj30Sao4l5BMPjTGZmCNzuv7/GDTDX99E9gTk= From aee79c41a4e4f6770db90291dffe01c53667d8dc Mon Sep 17 00:00:00 2001 From: Kris Page Date: Fri, 28 Nov 2025 10:29:20 +0000 Subject: [PATCH 13/14] fix: typo in data coder_external_auth example and docs (#420) --- docs/data-sources/external_auth.md | 2 +- examples/data-sources/coder_external_auth/data-source.tf | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/data-sources/external_auth.md b/docs/data-sources/external_auth.md index d1e6d649..4337301b 100644 --- a/docs/data-sources/external_auth.md +++ b/docs/data-sources/external_auth.md @@ -21,7 +21,7 @@ data "coder_external_auth" "github" { } data "coder_external_auth" "azure-identity" { - id = "azure-identiy" + id = "azure-identity" optional = true } ``` diff --git a/examples/data-sources/coder_external_auth/data-source.tf b/examples/data-sources/coder_external_auth/data-source.tf index 330ff216..06436086 100644 --- a/examples/data-sources/coder_external_auth/data-source.tf +++ b/examples/data-sources/coder_external_auth/data-source.tf @@ -6,6 +6,6 @@ data "coder_external_auth" "github" { } data "coder_external_auth" "azure-identity" { - id = "azure-identiy" + id = "azure-identity" optional = true } From 76bda72ec5f47be88edd6d0c1347802609b1d041 Mon Sep 17 00:00:00 2001 From: Jake Howell Date: Sat, 29 Nov 2025 21:47:34 +1100 Subject: [PATCH 14/14] feat: add confliction with `subdomain` (#469) * feat: add confliction with `subdomain` * fix: provide correct error * feat: implement testing suite * chore: remove unnecessary test suite * fix: resolve `app.md` lint * chore: resolve `app.go` description * Revert "chore: remove unnecessary test suite" This reverts commit 3d63e36fbc23ecc7cdb314fce3052c052741cb77. * chore: remove unused comments * chore: rename `Command` to `ConflictsWith` * feat: implement extensive test case * fix: convert to using dummy values * chore: remove duplicate testcase * chore: update wording to `Conflicts with subdomain.` --- docs/resources/app.md | 2 +- provider/app.go | 5 +- provider/app_test.go | 150 ++++++++++++++++++++++++++++++++++++------ 3 files changed, 133 insertions(+), 24 deletions(-) diff --git a/docs/resources/app.md b/docs/resources/app.md index 35a9951b..67efb5fc 100644 --- a/docs/resources/app.md +++ b/docs/resources/app.md @@ -61,7 +61,7 @@ resource "coder_app" "vim" { ### Optional -- `command` (String) A command to run in a terminal opening this app. In the web, this will open in a new tab. In the CLI, this will SSH and execute the command. Either `command` or `url` may be specified, but not both. +- `command` (String) A command to run in a terminal opening this app. In the web, this will open in a new tab. In the CLI, this will SSH and execute the command. Either `command` or `url` may be specified, but not both. Conflicts with `subdomain`. - `display_name` (String) A display name to identify the app. Defaults to the slug. - `external` (Boolean) Specifies whether `url` is opened on the client machine instead of proxied through the workspace. - `group` (String) The name of a group that this app belongs to. diff --git a/provider/app.go b/provider/app.go index dd0428a1..fb567573 100644 --- a/provider/app.go +++ b/provider/app.go @@ -85,8 +85,9 @@ func appResource() *schema.Resource { Type: schema.TypeString, Description: "A command to run in a terminal opening this app. In the web, " + "this will open in a new tab. In the CLI, this will SSH and execute the command. " + - "Either `command` or `url` may be specified, but not both.", - ConflictsWith: []string{"url"}, + "Either `command` or `url` may be specified, but not both. " + + "Conflicts with `subdomain`.", + ConflictsWith: []string{"url", "subdomain"}, Optional: true, ForceNew: true, }, diff --git a/provider/app_test.go b/provider/app_test.go index b8d4c8e7..17b3dce4 100644 --- a/provider/app_test.go +++ b/provider/app_test.go @@ -109,25 +109,6 @@ func TestApp(t *testing.T) { } `, external: true, - }, { - name: "ConflictsWithSubdomain", - config: ` - provider "coder" {} - resource "coder_agent" "dev" { - os = "linux" - arch = "amd64" - } - resource "coder_app" "test" { - agent_id = coder_agent.dev.id - slug = "test" - display_name = "Testing" - url = "https://google.com" - external = true - subdomain = true - open_in = "slim-window" - } - `, - expectError: regexp.MustCompile("conflicts with subdomain"), }} for _, tc := range cases { tc := tc @@ -564,8 +545,6 @@ func TestApp(t *testing.T) { } for _, c := range cases { - c := c - t.Run(c.name, func(t *testing.T) { t.Parallel() @@ -596,4 +575,133 @@ func TestApp(t *testing.T) { }) } }) + + t.Run("ConflictsWith", func(t *testing.T) { + t.Parallel() + + type healthcheck struct { + url string + interval int + threshold int + } + + dummyURL := "https://google.com" + dummyCommand := "read -p \\\"Workspace spawned. Press enter to continue...\\\"" + dummyExternal := true + dummySubdomain := true + dummyHealthcheck := healthcheck{ + url: "https://google.com", + interval: 5, + threshold: 6, + } + dummyShare := "owner" + + cases := []struct { + name string + url string + command string + subdomain bool + healthcheck healthcheck + external bool + share string + expectError *regexp.Regexp + }{ + { + name: "CommandAndSubdomain", + command: dummyCommand, + subdomain: dummySubdomain, + expectError: regexp.MustCompile("conflicts with subdomain"), + }, + { + name: "URLAndCommand", + url: dummyURL, + command: dummyCommand, + expectError: regexp.MustCompile("conflicts with command"), + }, + { + name: "HealthcheckAndCommand", + healthcheck: dummyHealthcheck, + command: dummyCommand, + expectError: regexp.MustCompile("conflicts with command"), + }, + { + name: "ExternalAndHealthcheck", + external: dummyExternal, + healthcheck: dummyHealthcheck, + expectError: regexp.MustCompile("conflicts with healthcheck"), + }, + { + name: "ExternalAndCommand", + external: dummyExternal, + command: dummyCommand, + expectError: regexp.MustCompile("conflicts with command"), + }, + { + name: "ExternalAndSubdomain", + external: dummyExternal, + subdomain: dummySubdomain, + expectError: regexp.MustCompile("conflicts with subdomain"), + }, + { + name: "ExternalAndShare", + external: dummyExternal, + share: dummyShare, + expectError: regexp.MustCompile("conflicts with share"), + }, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + t.Parallel() + + extraLines := []string{} + if c.command != "" { + extraLines = append(extraLines, fmt.Sprintf("command = %q", c.command)) + } + if c.subdomain { + extraLines = append(extraLines, "subdomain = true") + } + if c.external { + extraLines = append(extraLines, "external = true") + } + if c.url != "" { + extraLines = append(extraLines, fmt.Sprintf("url = %q", c.url)) + } + if c.healthcheck != (healthcheck{}) { + extraLines = append(extraLines, fmt.Sprintf(`healthcheck { + url = %q + interval = %d + threshold = %d + }`, c.healthcheck.url, c.healthcheck.interval, c.healthcheck.threshold)) + } + if c.share != "" { + extraLines = append(extraLines, fmt.Sprintf("share = %q", c.share)) + } + + config := fmt.Sprintf(` + provider "coder" {} + resource "coder_agent" "dev" { + os = "linux" + arch = "amd64" + } + resource "coder_app" "code-server" { + agent_id = coder_agent.dev.id + slug = "code-server" + display_name = "Testing" + open_in = "slim-window" + %s + } + `, strings.Join(extraLines, "\n ")) + + resource.Test(t, resource.TestCase{ + ProviderFactories: coderFactory(), + IsUnitTest: true, + Steps: []resource.TestStep{{ + Config: config, + ExpectError: c.expectError, + }}, + }) + }) + } + }) }