terraform/vendor/github.com/hashicorp/go-tfe/run.go

323 lines
9.9 KiB
Go

package tfe
import (
"context"
"errors"
"fmt"
"net/url"
"time"
)
// Compile-time proof of interface implementation.
var _ Runs = (*runs)(nil)
// Runs describes all the run related methods that the Terraform Enterprise
// API supports.
//
// TFE API docs: https://www.terraform.io/docs/enterprise/api/run.html
type Runs interface {
// List all the runs of the given workspace.
List(ctx context.Context, workspaceID string, options RunListOptions) (*RunList, error)
// Create a new run with the given options.
Create(ctx context.Context, options RunCreateOptions) (*Run, error)
// Read a run by its ID.
Read(ctx context.Context, runID string) (*Run, error)
// Apply a run by its ID.
Apply(ctx context.Context, runID string, options RunApplyOptions) error
// Cancel a run by its ID.
Cancel(ctx context.Context, runID string, options RunCancelOptions) error
// Force-cancel a run by its ID.
ForceCancel(ctx context.Context, runID string, options RunForceCancelOptions) error
// Discard a run by its ID.
Discard(ctx context.Context, runID string, options RunDiscardOptions) error
}
// runs implements Runs.
type runs struct {
client *Client
}
// RunStatus represents a run state.
type RunStatus string
//List all available run statuses.
const (
RunApplied RunStatus = "applied"
RunApplyQueued RunStatus = "apply_queued"
RunApplying RunStatus = "applying"
RunCanceled RunStatus = "canceled"
RunConfirmed RunStatus = "confirmed"
RunCostEstimated RunStatus = "cost_estimated"
RunCostEstimating RunStatus = "cost_estimating"
RunDiscarded RunStatus = "discarded"
RunErrored RunStatus = "errored"
RunPending RunStatus = "pending"
RunPlanQueued RunStatus = "plan_queued"
RunPlanned RunStatus = "planned"
RunPlannedAndFinished RunStatus = "planned_and_finished"
RunPlanning RunStatus = "planning"
RunPolicyChecked RunStatus = "policy_checked"
RunPolicyChecking RunStatus = "policy_checking"
RunPolicyOverride RunStatus = "policy_override"
RunPolicySoftFailed RunStatus = "policy_soft_failed"
)
// RunSource represents a source type of a run.
type RunSource string
// List all available run sources.
const (
RunSourceAPI RunSource = "tfe-api"
RunSourceConfigurationVersion RunSource = "tfe-configuration-version"
RunSourceUI RunSource = "tfe-ui"
)
// RunList represents a list of runs.
type RunList struct {
*Pagination
Items []*Run
}
// Run represents a Terraform Enterprise run.
type Run struct {
ID string `jsonapi:"primary,runs"`
Actions *RunActions `jsonapi:"attr,actions"`
CreatedAt time.Time `jsonapi:"attr,created-at,iso8601"`
ForceCancelAvailableAt time.Time `jsonapi:"attr,force-cancel-available-at,iso8601"`
HasChanges bool `jsonapi:"attr,has-changes"`
IsDestroy bool `jsonapi:"attr,is-destroy"`
Message string `jsonapi:"attr,message"`
Permissions *RunPermissions `jsonapi:"attr,permissions"`
PositionInQueue int `jsonapi:"attr,position-in-queue"`
Source RunSource `jsonapi:"attr,source"`
Status RunStatus `jsonapi:"attr,status"`
StatusTimestamps *RunStatusTimestamps `jsonapi:"attr,status-timestamps"`
// Relations
Apply *Apply `jsonapi:"relation,apply"`
ConfigurationVersion *ConfigurationVersion `jsonapi:"relation,configuration-version"`
CostEstimate *CostEstimate `jsonapi:"relation,cost-estimate"`
Plan *Plan `jsonapi:"relation,plan"`
PolicyChecks []*PolicyCheck `jsonapi:"relation,policy-checks"`
Workspace *Workspace `jsonapi:"relation,workspace"`
}
// RunActions represents the run actions.
type RunActions struct {
IsCancelable bool `json:"is-cancelable"`
IsConfirmable bool `json:"is-confirmable"`
IsDiscardable bool `json:"is-discardable"`
IsForceCancelable bool `json:"is-force-cancelable"`
}
// RunPermissions represents the run permissions.
type RunPermissions struct {
CanApply bool `json:"can-apply"`
CanCancel bool `json:"can-cancel"`
CanDiscard bool `json:"can-discard"`
CanForceCancel bool `json:"can-force-cancel"`
CanForceExecute bool `json:"can-force-execute"`
}
// RunStatusTimestamps holds the timestamps for individual run statuses.
type RunStatusTimestamps struct {
ErroredAt time.Time `json:"errored-at"`
FinishedAt time.Time `json:"finished-at"`
QueuedAt time.Time `json:"queued-at"`
StartedAt time.Time `json:"started-at"`
ApplyingAt time.Time `json:"applying-at"`
AppliedAt time.Time `json:"applied-at"`
PlanningAt time.Time `json:"planning-at"`
PlannedAt time.Time `json:"planned-at"`
PlannedAndFinishedAt time.Time `json:"planned-and-finished-at"`
PlanQueuabledAt time.Time `json:"plan-queueable-at"`
}
// RunListOptions represents the options for listing runs.
type RunListOptions struct {
ListOptions
}
// List all the runs of the given workspace.
func (s *runs) List(ctx context.Context, workspaceID string, options RunListOptions) (*RunList, error) {
if !validStringID(&workspaceID) {
return nil, errors.New("invalid value for workspace ID")
}
u := fmt.Sprintf("workspaces/%s/runs", url.QueryEscape(workspaceID))
req, err := s.client.newRequest("GET", u, &options)
if err != nil {
return nil, err
}
rl := &RunList{}
err = s.client.do(ctx, req, rl)
if err != nil {
return nil, err
}
return rl, nil
}
// RunCreateOptions represents the options for creating a new run.
type RunCreateOptions struct {
// For internal use only!
ID string `jsonapi:"primary,runs"`
// Specifies if this plan is a destroy plan, which will destroy all
// provisioned resources.
IsDestroy *bool `jsonapi:"attr,is-destroy,omitempty"`
// Specifies the message to be associated with this run.
Message *string `jsonapi:"attr,message,omitempty"`
// Specifies the configuration version to use for this run. If the
// configuration version object is omitted, the run will be created using the
// workspace's latest configuration version.
ConfigurationVersion *ConfigurationVersion `jsonapi:"relation,configuration-version"`
// Specifies the workspace where the run will be executed.
Workspace *Workspace `jsonapi:"relation,workspace"`
}
func (o RunCreateOptions) valid() error {
if o.Workspace == nil {
return errors.New("workspace is required")
}
return nil
}
// Create a new run with the given options.
func (s *runs) Create(ctx context.Context, options RunCreateOptions) (*Run, error) {
if err := options.valid(); err != nil {
return nil, err
}
// Make sure we don't send a user provided ID.
options.ID = ""
req, err := s.client.newRequest("POST", "runs", &options)
if err != nil {
return nil, err
}
r := &Run{}
err = s.client.do(ctx, req, r)
if err != nil {
return nil, err
}
return r, nil
}
// Read a run by its ID.
func (s *runs) Read(ctx context.Context, runID string) (*Run, error) {
if !validStringID(&runID) {
return nil, errors.New("invalid value for run ID")
}
u := fmt.Sprintf("runs/%s", url.QueryEscape(runID))
req, err := s.client.newRequest("GET", u, nil)
if err != nil {
return nil, err
}
r := &Run{}
err = s.client.do(ctx, req, r)
if err != nil {
return nil, err
}
return r, nil
}
// RunApplyOptions represents the options for applying a run.
type RunApplyOptions struct {
// An optional comment about the run.
Comment *string `json:"comment,omitempty"`
}
// Apply a run by its ID.
func (s *runs) Apply(ctx context.Context, runID string, options RunApplyOptions) error {
if !validStringID(&runID) {
return errors.New("invalid value for run ID")
}
u := fmt.Sprintf("runs/%s/actions/apply", url.QueryEscape(runID))
req, err := s.client.newRequest("POST", u, &options)
if err != nil {
return err
}
return s.client.do(ctx, req, nil)
}
// RunCancelOptions represents the options for canceling a run.
type RunCancelOptions struct {
// An optional explanation for why the run was canceled.
Comment *string `json:"comment,omitempty"`
}
// Cancel a run by its ID.
func (s *runs) Cancel(ctx context.Context, runID string, options RunCancelOptions) error {
if !validStringID(&runID) {
return errors.New("invalid value for run ID")
}
u := fmt.Sprintf("runs/%s/actions/cancel", url.QueryEscape(runID))
req, err := s.client.newRequest("POST", u, &options)
if err != nil {
return err
}
return s.client.do(ctx, req, nil)
}
// RunForceCancelOptions represents the options for force-canceling a run.
type RunForceCancelOptions struct {
// An optional comment explaining the reason for the force-cancel.
Comment *string `json:"comment,omitempty"`
}
// ForceCancel is used to forcefully cancel a run by its ID.
func (s *runs) ForceCancel(ctx context.Context, runID string, options RunForceCancelOptions) error {
if !validStringID(&runID) {
return errors.New("invalid value for run ID")
}
u := fmt.Sprintf("runs/%s/actions/force-cancel", url.QueryEscape(runID))
req, err := s.client.newRequest("POST", u, &options)
if err != nil {
return err
}
return s.client.do(ctx, req, nil)
}
// RunDiscardOptions represents the options for discarding a run.
type RunDiscardOptions struct {
// An optional explanation for why the run was discarded.
Comment *string `json:"comment,omitempty"`
}
// Discard a run by its ID.
func (s *runs) Discard(ctx context.Context, runID string, options RunDiscardOptions) error {
if !validStringID(&runID) {
return errors.New("invalid value for run ID")
}
u := fmt.Sprintf("runs/%s/actions/discard", url.QueryEscape(runID))
req, err := s.client.newRequest("POST", u, &options)
if err != nil {
return err
}
return s.client.do(ctx, req, nil)
}