From f60246478ee805f6c114739a115d8e4187bb4478 Mon Sep 17 00:00:00 2001 From: Glenn Sarti Date: Mon, 18 Jul 2022 14:05:21 +0800 Subject: [PATCH] Update Run and Workspace Run Tasks for Pre-plan Run Tasks This commit updates the client for the new Pre-plan Run tasks: * New run statuses; FetchingCompleted, Queuing which are ephemeral and will rarely be seen. PrePlanRunning and PrePlanCompleted are for the pre-plan tasks * Add missing Run Status Time Stamps * New Task stage; PrePlan * Ability to set/update the stage for a Workspace Run Task. This is a beta feature and must be opted into. However it is optional and is not a breaking API change. * Adds additional Workspace Run Tasks tests which are gated behind the BETA flag. Note that the original tests still remain to affirm that this commit does not change any existing behaviour. --- CHANGELOG.md | 2 + run.go | 21 +++++-- task_stages.go | 1 + workspace_run_task.go | 4 ++ workspace_run_task_integration_test.go | 77 ++++++++++++++++++++++++++ 5 files changed, 99 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 40bcbf53a..7d8b9562f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ ## Enhancements * Adds new run creation attributes: `allow-empty-apply`, `terraform-version`, `plan-only` by @sebasslash [#482](https://github.com/hashicorp/go-tfe/pull/447) +* Adds additional Task Stage and Run Statuses for Pre-plan run tasks by @glennsarti [#469](https://github.com/hashicorp/go-tfe/pull/469) +* Adds `stage` field to the create and update methods for Workspace Run Tasks by @glennsarti [#469](https://github.com/hashicorp/go-tfe/pull/469) # v1.6.0 diff --git a/run.go b/run.go index ba8136332..19052ee6a 100644 --- a/run.go +++ b/run.go @@ -51,8 +51,8 @@ type RunStatus string // List all available run statuses. const ( RunApplied RunStatus = "applied" - RunApplyQueued RunStatus = "apply_queued" RunApplying RunStatus = "applying" + RunApplyQueued RunStatus = "apply_queued" RunCanceled RunStatus = "canceled" RunConfirmed RunStatus = "confirmed" RunCostEstimated RunStatus = "cost_estimated" @@ -60,17 +60,21 @@ const ( RunDiscarded RunStatus = "discarded" RunErrored RunStatus = "errored" RunFetching RunStatus = "fetching" + RunFetchingCompleted RunStatus = "fetching_completed" RunPending RunStatus = "pending" - RunPlanQueued RunStatus = "plan_queued" RunPlanned RunStatus = "planned" RunPlannedAndFinished RunStatus = "planned_and_finished" RunPlanning RunStatus = "planning" + RunPlanQueued RunStatus = "plan_queued" RunPolicyChecked RunStatus = "policy_checked" RunPolicyChecking RunStatus = "policy_checking" RunPolicyOverride RunStatus = "policy_override" RunPolicySoftFailed RunStatus = "policy_soft_failed" - RunPostPlanRunning RunStatus = "post_plan_running" RunPostPlanCompleted RunStatus = "post_plan_completed" + RunPostPlanRunning RunStatus = "post_plan_running" + RunPrePlanCompleted RunStatus = "pre_plan_completed" + RunPrePlanRunning RunStatus = "pre_plan_running" + RunQueuing RunStatus = "queuing" ) // RunSource represents a source type of a run. @@ -157,8 +161,8 @@ type RunPermissions struct { // RunStatusTimestamps holds the timestamps for individual run statuses. type RunStatusTimestamps struct { AppliedAt time.Time `jsonapi:"attr,applied-at,rfc3339"` - ApplyQueuedAt time.Time `jsonapi:"attr,apply-queued-at,rfc3339"` ApplyingAt time.Time `jsonapi:"attr,applying-at,rfc3339"` + ApplyQueuedAt time.Time `jsonapi:"attr,apply-queued-at,rfc3339"` CanceledAt time.Time `jsonapi:"attr,canceled-at,rfc3339"` ConfirmedAt time.Time `jsonapi:"attr,confirmed-at,rfc3339"` CostEstimatedAt time.Time `jsonapi:"attr,cost-estimated-at,rfc3339"` @@ -168,13 +172,18 @@ type RunStatusTimestamps struct { FetchedAt time.Time `jsonapi:"attr,fetched-at,rfc3339"` FetchingAt time.Time `jsonapi:"attr,fetching-at,rfc3339"` ForceCanceledAt time.Time `jsonapi:"attr,force-canceled-at,rfc3339"` - PlanQueueableAt time.Time `jsonapi:"attr,plan-queueable-at,rfc3339"` - PlanQueuedAt time.Time `jsonapi:"attr,plan-queued-at,rfc3339"` PlannedAndFinishedAt time.Time `jsonapi:"attr,planned-and-finished-at,rfc3339"` PlannedAt time.Time `jsonapi:"attr,planned-at,rfc3339"` PlanningAt time.Time `jsonapi:"attr,planning-at,rfc3339"` + PlanQueueableAt time.Time `jsonapi:"attr,plan-queueable-at,rfc3339"` + PlanQueuedAt time.Time `jsonapi:"attr,plan-queued-at,rfc3339"` PolicyCheckedAt time.Time `jsonapi:"attr,policy-checked-at,rfc3339"` PolicySoftFailedAt time.Time `jsonapi:"attr,policy-soft-failed-at,rfc3339"` + PostPlanCompletedAt time.Time `jsonapi:"attr,post-plan-completed-at,rfc3339"` + PostPlanRunningAt time.Time `jsonapi:"attr,post-plan-running-at,rfc3339"` + PrePlanCompletedAt time.Time `jsonapi:"attr,pre-plan-completed-at,rfc3339"` + PrePlanRunningAt time.Time `jsonapi:"attr,pre-plan-running-at,rfc3339"` + QueuingAt time.Time `jsonapi:"attr,queuing-at,rfc3339"` } // RunIncludeOpt represents the available options for include query params. diff --git a/task_stages.go b/task_stages.go index 4c659deb9..0fd337c6b 100644 --- a/task_stages.go +++ b/task_stages.go @@ -29,6 +29,7 @@ type taskStages struct { type Stage string const ( + PrePlan Stage = "pre_plan" PostPlan Stage = "post_plan" ) diff --git a/workspace_run_task.go b/workspace_run_task.go index 4dad5ecca..f7d655967 100644 --- a/workspace_run_task.go +++ b/workspace_run_task.go @@ -37,6 +37,7 @@ type workspaceRunTasks struct { type WorkspaceRunTask struct { ID string `jsonapi:"primary,workspace-tasks"` EnforcementLevel TaskEnforcementLevel `jsonapi:"attr,enforcement-level"` + Stage Stage `jsonapi:"attr,stage"` RunTask *RunTask `jsonapi:"relation,task"` Workspace *Workspace `jsonapi:"relation,workspace"` @@ -60,12 +61,15 @@ type WorkspaceRunTaskCreateOptions struct { EnforcementLevel TaskEnforcementLevel `jsonapi:"attr,enforcement-level"` // Required: The run task to attach to the workspace RunTask *RunTask `jsonapi:"relation,task"` + // Optional: The stage to run the task in. This is currently in BETA + Stage *Stage `jsonapi:"attr,stage,omitempty"` } // WorkspaceRunTaskUpdateOptions represent the set of options for updating a workspace run task. type WorkspaceRunTaskUpdateOptions struct { Type string `jsonapi:"primary,workspace-tasks"` EnforcementLevel TaskEnforcementLevel `jsonapi:"attr,enforcement-level,omitempty"` + Stage *Stage `jsonapi:"attr,stage,omitempty"` // The stage to run the task in. This is currently in BETA } // List all run tasks attached to a workspace diff --git a/workspace_run_task_integration_test.go b/workspace_run_task_integration_test.go index 1b9c54345..896096879 100644 --- a/workspace_run_task_integration_test.go +++ b/workspace_run_task_integration_test.go @@ -46,6 +46,47 @@ func TestWorkspaceRunTasksCreate(t *testing.T) { }) } +func TestWorkspaceRunTasksCreateBeta(t *testing.T) { + // Once Pre-Plan Tasks are generally available, this can replace the above TestWorkspaceRunTasksCreate + skipIfBeta(t) + skipIfFreeOnly(t) + + client := testClient(t) + ctx := context.Background() + + orgTest, orgTestCleanup := createOrganization(t, client) + defer orgTestCleanup() + + runTaskTest, runTaskTestCleanup := createRunTask(t, client, orgTest) + defer runTaskTestCleanup() + + wkspaceTest, wkspaceTestCleanup := createWorkspace(t, client, orgTest) + defer wkspaceTestCleanup() + + t.Run("attach run task to workspace", func(t *testing.T) { + s := PrePlan + wr, err := client.WorkspaceRunTasks.Create(ctx, wkspaceTest.ID, WorkspaceRunTaskCreateOptions{ + EnforcementLevel: Mandatory, + Stage: &s, + RunTask: runTaskTest, + }) + + require.NoError(t, err) + defer func() { + client.WorkspaceRunTasks.Delete(ctx, wkspaceTest.ID, wr.ID) + }() + + assert.NotEmpty(t, wr.ID) + assert.Equal(t, wr.EnforcementLevel, Mandatory) + assert.Equal(t, wr.Stage, s) + + t.Run("ensure run task is deserialized properly", func(t *testing.T) { + assert.NotNil(t, wr.RunTask) + assert.NotEmpty(t, wr.RunTask.ID) + }) + }) +} + func TestWorkspaceRunTasksList(t *testing.T) { skipIfFreeOnly(t) @@ -146,6 +187,42 @@ func TestWorkspaceRunTasksUpdate(t *testing.T) { }) } +func TestWorkspaceRunTasksUpdateBeta(t *testing.T) { + // Once Pre-Plan Tasks are generally available, this can replace the above TestWorkspaceRunTasksUpdate + skipIfBeta(t) + skipIfFreeOnly(t) + + client := testClient(t) + ctx := context.Background() + + orgTest, orgTestCleanup := createOrganization(t, client) + defer orgTestCleanup() + + wkspaceTest, wkspaceTestCleanup := createWorkspace(t, client, orgTest) + defer wkspaceTestCleanup() + + runTaskTest, runTaskTestCleanup := createRunTask(t, client, orgTest) + defer runTaskTestCleanup() + + wrTaskTest, wrTaskTestCleanup := createWorkspaceRunTask(t, client, wkspaceTest, runTaskTest) + defer wrTaskTestCleanup() + + t.Run("update task", func(t *testing.T) { + stage := PrePlan + wr, err := client.WorkspaceRunTasks.Update(ctx, wkspaceTest.ID, wrTaskTest.ID, WorkspaceRunTaskUpdateOptions{ + EnforcementLevel: Mandatory, + Stage: &stage, + }) + require.NoError(t, err) + + wr, err = client.WorkspaceRunTasks.Read(ctx, wkspaceTest.ID, wr.ID) + require.NoError(t, err) + + assert.Equal(t, wr.EnforcementLevel, Mandatory) + assert.Equal(t, wr.Stage, PrePlan) + }) +} + func TestWorkspaceRunTasksDelete(t *testing.T) { skipIfFreeOnly(t)