Skip to content
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

Add workspace run task stage property #555

Merged
merged 1 commit into from
Aug 18, 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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## Unreleased

FEATURES:
* r/tfe_workspace_run_task, d/tfe_workspace_run_task: Add `stage` attribute to workspace run tasks. ([#555](https://github.com/hashicorp/terraform-provider-tfe/pull/555))

## v0.36.0 (August 16th, 2022)

FEATURES:
Expand Down
22 changes: 16 additions & 6 deletions tfe/data_source_workspace_run_task.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,27 @@ func dataSourceTFEWorkspaceRunTask() *schema.Resource {

Schema: map[string]*schema.Schema{
"workspace_id": {
Type: schema.TypeString,
Required: true,
Description: "The id of the workspace.",
Type: schema.TypeString,
Required: true,
},

"task_id": {
Type: schema.TypeString,
Required: true,
Description: "The id of the run task.",
Type: schema.TypeString,
Required: true,
},

"enforcement_level": {
Type: schema.TypeString,
Computed: true,
Description: "The enforcement level of the task.",
Type: schema.TypeString,
Computed: true,
},

"stage": {
Description: "Which stage the task will run in.",
Type: schema.TypeString,
Computed: true,
},
},
}
Expand All @@ -47,6 +56,7 @@ func dataSourceTFEWorkspaceRunTaskRead(d *schema.ResourceData, meta interface{})
for _, wstask := range list.Items {
if wstask.RunTask.ID == taskID {
d.Set("enforcement_level", string(wstask.EnforcementLevel))
d.Set("stage", string(wstask.Stage))
d.SetId(wstask.ID)
return nil
}
Expand Down
1 change: 1 addition & 0 deletions tfe/data_source_workspace_run_task_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ func TestAccTFEWorkspaceRunTaskDataSource_basic(t *testing.T) {
Config: testAccTFEWorkspaceRunTaskDataSourceConfig(orgName, rInt, runTasksURL()),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr("data.tfe_workspace_run_task.foobar", "enforcement_level", "advisory"),
resource.TestCheckResourceAttrSet("data.tfe_workspace_run_task.foobar", "stage"),
resource.TestCheckResourceAttrSet("data.tfe_workspace_run_task.foobar", "id"),
resource.TestCheckResourceAttrSet("data.tfe_workspace_run_task.foobar", "task_id"),
resource.TestCheckResourceAttrSet("data.tfe_workspace_run_task.foobar", "workspace_id"),
Expand Down
73 changes: 66 additions & 7 deletions tfe/resource_tfe_workspace_run_task.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,36 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
)

func workspaceRunTaskEnforcementLevels() []string {
return []string{
string(tfe.Advisory),
string(tfe.Mandatory),
}
}

func workspaceRunTaskStages() []string {
return []string{
string(tfe.PrePlan),
string(tfe.PostPlan),
}
}

// Helper function to turn a slice of strings into an english sentence for documentation
func sentenceList(items []string, prefix string, suffix string, conjunction string) string {
var b strings.Builder
for i, v := range items {
fmt.Fprint(&b, prefix, v, suffix)
if i < len(items)-1 {
if i < len(items)-2 {
fmt.Fprint(&b, ", ")
} else {
fmt.Fprintf(&b, " %s ", conjunction)
}
}
}
return b.String()
}

func resourceTFEWorkspaceRunTask() *schema.Resource {
return &schema.Resource{
Create: resourceTFEWorkspaceRunTaskCreate,
Expand All @@ -22,25 +52,47 @@ func resourceTFEWorkspaceRunTask() *schema.Resource {

Schema: map[string]*schema.Schema{
"workspace_id": {
Type: schema.TypeString,
ForceNew: true,
Required: true,
Description: "The id of the workspace to associate the Run task to.",
Type: schema.TypeString,
ForceNew: true,
Required: true,
},

"task_id": {
Description: "The id of the Run task to associate to the Workspace.",

Type: schema.TypeString,
ForceNew: true,
Required: true,
},

"enforcement_level": {
Description: fmt.Sprintf("The enforcement level of the task. Valid values are %s.", sentenceList(
workspaceRunTaskEnforcementLevels(),
"`",
"`",
"and",
)),
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringInSlice(
[]string{
string(tfe.Advisory),
string(tfe.Mandatory),
},
workspaceRunTaskEnforcementLevels(),
false,
),
},

"stage": {
Description: fmt.Sprintf("This is currently in BETA. The stage to run the task in. Valid values are %s.", sentenceList(
workspaceRunTaskStages(),
"`",
"`",
"and",
)),
Type: schema.TypeString,
Optional: true,
Default: tfe.PostPlan,
ValidateFunc: validation.StringInSlice(
workspaceRunTaskStages(),
false,
),
},
Expand All @@ -65,10 +117,12 @@ func resourceTFEWorkspaceRunTaskCreate(d *schema.ResourceData, meta interface{})
return fmt.Errorf(
"Error retrieving workspace %s: %w", workspaceID, err)
}
stage := tfe.Stage(d.Get("stage").(string))

options := tfe.WorkspaceRunTaskCreateOptions{
RunTask: task,
EnforcementLevel: tfe.TaskEnforcementLevel(d.Get("enforcement_level").(string)),
Stage: &stage,
}

log.Printf("[DEBUG] Create task %s in workspace %s", task.ID, ws.ID)
Expand Down Expand Up @@ -108,6 +162,10 @@ func resourceTFEWorkspaceRunTaskUpdate(d *schema.ResourceData, meta interface{})
if d.HasChange("enforcement_level") {
options.EnforcementLevel = tfe.TaskEnforcementLevel(d.Get("enforcement_level").(string))
}
if d.HasChange("stage") {
stage := tfe.Stage(d.Get("stage").(string))
options.Stage = &stage
}

log.Printf("[DEBUG] Update configuration of task %s in workspace %s", d.Id(), workspaceID)
_, err := tfeClient.WorkspaceRunTasks.Update(ctx, workspaceID, d.Id(), options)
Expand Down Expand Up @@ -138,6 +196,7 @@ func resourceTFEWorkspaceRunTaskRead(d *schema.ResourceData, meta interface{}) e
d.Set("workspace_id", wstask.Workspace.ID)
d.Set("task_id", wstask.RunTask.ID)
d.Set("enforcement_level", string(wstask.EnforcementLevel))
d.Set("stage", string(wstask.Stage))

return nil
}
Expand Down
88 changes: 88 additions & 0 deletions tfe/resource_tfe_workspace_run_task_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,40 @@ func TestAccTFEWorkspaceRunTask_create(t *testing.T) {
})
}

func TestAccTFEWorkspaceRunTask_beta_create(t *testing.T) {
skipUnlessRunTasksDefined(t)
skipUnlessBeta(t)
skipIfFreeOnly(t) // Run Tasks requires TFE or a TFC paid/trial subscription

workspaceTask := &tfe.WorkspaceRunTask{}
rInt := rand.New(rand.NewSource(time.Now().UnixNano())).Int()
orgName := fmt.Sprintf("tst-terraform-%d", rInt)

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckTFEWorkspaceRunTaskDestroy,
Steps: []resource.TestStep{
testCheckCreateOrgWithRunTasks(orgName),
{
Config: testAccTFEWorkspaceRunTask_beta_basic(orgName, runTasksURL()),
Check: resource.ComposeTestCheckFunc(
testAccCheckTFEWorkspaceRunTaskExists("tfe_workspace_run_task.foobar", workspaceTask),
resource.TestCheckResourceAttr("tfe_workspace_run_task.foobar", "enforcement_level", "advisory"),
resource.TestCheckResourceAttr("tfe_workspace_run_task.foobar", "stage", "post_plan"),
),
},
{
Config: testAccTFEWorkspaceRunTask_beta_update(orgName, runTasksURL()),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("tfe_workspace_run_task.foobar", "enforcement_level", "mandatory"),
resource.TestCheckResourceAttr("tfe_workspace_run_task.foobar", "stage", "pre_plan"),
),
},
},
})
}

func TestAccTFEWorkspaceRunTask_import(t *testing.T) {
skipUnlessRunTasksDefined(t)
skipIfFreeOnly(t) // Run Tasks requires TFE or a TFC paid/trial subscription
Expand Down Expand Up @@ -175,3 +209,57 @@ resource "tfe_workspace_run_task" "foobar" {
}
`, orgName, runTaskURL)
}

func testAccTFEWorkspaceRunTask_beta_basic(orgName, runTaskURL string) string {
return fmt.Sprintf(`
resource "tfe_organization" "foobar" {
name = "%s"
email = "admin@company.com"
}

resource "tfe_organization_run_task" "foobar" {
organization = tfe_organization.foobar.id
url = "%s"
name = "foobar-task"
}

resource "tfe_workspace" "foobar" {
name = "workspace-test"
organization = tfe_organization.foobar.id
}

resource "tfe_workspace_run_task" "foobar" {
workspace_id = resource.tfe_workspace.foobar.id
task_id = resource.tfe_organization_run_task.foobar.id
enforcement_level = "advisory"
stage = "post_plan"
}
`, orgName, runTaskURL)
}

func testAccTFEWorkspaceRunTask_beta_update(orgName, runTaskURL string) string {
return fmt.Sprintf(`
resource "tfe_organization" "foobar" {
name = "%s"
email = "admin@company.com"
}

resource "tfe_organization_run_task" "foobar" {
organization = tfe_organization.foobar.id
url = "%s"
name = "foobar-task"
}

resource "tfe_workspace" "foobar" {
name = "workspace-test"
organization = tfe_organization.foobar.id
}

resource "tfe_workspace_run_task" "foobar" {
workspace_id = resource.tfe_workspace.foobar.id
task_id = resource.tfe_organization_run_task.foobar.id
enforcement_level = "mandatory"
stage = "pre_plan"
}
`, orgName, runTaskURL)
}
11 changes: 11 additions & 0 deletions tfe/testing.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@ func skipUnlessRunTasksDefined(t *testing.T) {
}
}

func skipUnlessBeta(t *testing.T) {
if !betaFeaturesEnabled() {
t.Skip("Skipping test related to a Terraform Cloud/Enterprise beta feature. Set ENABLE_BETA=1 to run.")
}
}

func enterpriseEnabled() bool {
return os.Getenv("ENABLE_TFE") == "1"
}
Expand All @@ -79,6 +85,11 @@ func runTasksURL() string {
return os.Getenv(RunTasksURLEnvName)
}

// Checks to see if ENABLE_BETA is set to 1, thereby enabling tests for beta features.
func betaFeaturesEnabled() bool {
return os.Getenv("ENABLE_BETA") == "1"
}

// Most tests rely on terraform-plugin-sdk/helper/resource.Test to run. That test helper ensures
// that TF_ACC=1 or else it skips. In some rare cases, however, tests do not use the SDK helper and
// are acceptance tests.
Expand Down
3 changes: 2 additions & 1 deletion website/docs/d/workspace_run_task.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ data "tfe_workspace_run_task" "foobar" {

The following arguments are supported:

* `task_id` - (Required) The id of the Run task.
* `task_id` - (Required) The id of the run task.
* `workspace_id` - (Required) The id of the workspace.

## Attributes Reference
Expand All @@ -34,3 +34,4 @@ In addition to all arguments above, the following attributes are exported:

* `enforcement_level` - The enforcement level of the task.
* `id` - The ID of the Workspace Run task.
* `stage` - Which stage the task will run in.
1 change: 1 addition & 0 deletions website/docs/r/workspace_run_task.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ The following arguments are supported:
* `enforcement_level` - (Required) The enforcement level of the task. Valid values are `advisory` and `mandatory`.
* `task_id` - (Required) The id of the Run task to associate to the Workspace.
* `workspace_id` - (Required) The id of the workspace to associate the Run task to.
* `stage` - (Optional) This is currently in BETA. The stage to run the task in. Valid values are `pre-plan` and `post-plan`.

## Attributes Reference

Expand Down