diff --git a/CHANGELOG.md b/CHANGELOG.md index e17c0c9dc..a67454a4a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ # Unreleased +## Enhancements +* 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 + ## Enhancements * Add `Name` field to `OAuthClient` by @barrettclark [#466](https://github.com/hashicorp/go-tfe/pull/466) * Add support for creating both public and private `RegistryModule` with no VCS connection by @Uk1288 [#460](https://github.com/hashicorp/go-tfe/pull/460) diff --git a/run.go b/run.go index 93b90d890..d06301f31 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. @@ -154,8 +158,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"` @@ -165,13 +169,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)