Skip to content

Commit

Permalink
Add stage to workspace run task resource and data source
Browse files Browse the repository at this point in the history
This commit adds the stage attribute to the Workspace Run Task
Resource and Data Source. Note that this is in beta for the
Resource.  This commit adds acceptance tests, and optionally
test the Beta features.

This commit also adds descriptions for the Workspace Run Task
attributes.
  • Loading branch information
glennsarti committed Aug 17, 2022
1 parent 2569514 commit 080f778
Show file tree
Hide file tree
Showing 8 changed files with 186 additions and 14 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -4,6 +4,7 @@ FEATURES:
* r/tfe_organization_run_task, d/tfe_organization_run_task: Add `description` attribute to organization run tasks. ([#585](https://github.com/hashicorp/terraform-provider-tfe/pull/585))
* r/tfe_workspace: Adds `tags_regex` attribute to `vcs_repo` for workspaces, enabling a workspace to trigger runs for matching Git tags. ([#549](https://github.com/hashicorp/terraform-provider-tfe/pull/549))
* r/agent_pool: Agent Pools can now be imported using `<ORGANIZATION NAME>/<AGENT POOL NAME>` ([#561](https://github.com/hashicorp/terraform-provider-tfe/pull/561))
* 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))

BUG FIXES:
* d/tfe_outputs: Fix a bug causing sensitive values to be missing from tfe_outputs ([#565](https://github.com/hashicorp/terraform-provider-tfe/pull/565))
Expand Down
22 changes: 16 additions & 6 deletions tfe/data_source_workspace_run_task.go
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
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
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
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
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
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
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

0 comments on commit 080f778

Please sign in to comment.