vendor latest go-tfe
Signed-off-by: Paul Thrasher <pthrasher@hashicorp.com>
This commit is contained in:
parent
d3fc3dee6e
commit
d2eaffabea
|
@ -21,6 +21,7 @@ import (
|
||||||
type mockClient struct {
|
type mockClient struct {
|
||||||
Applies *mockApplies
|
Applies *mockApplies
|
||||||
ConfigurationVersions *mockConfigurationVersions
|
ConfigurationVersions *mockConfigurationVersions
|
||||||
|
CostEstimates *mockCostEstimates
|
||||||
Organizations *mockOrganizations
|
Organizations *mockOrganizations
|
||||||
Plans *mockPlans
|
Plans *mockPlans
|
||||||
PolicyChecks *mockPolicyChecks
|
PolicyChecks *mockPolicyChecks
|
||||||
|
@ -730,6 +731,11 @@ func (m *mockRuns) Create(ctx context.Context, options tfe.RunCreateOptions) (*t
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ce, err := m.client.CostEstimates.create(options.ConfigurationVersion.ID, options.Workspace.ID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
p, err := m.client.Plans.create(options.ConfigurationVersion.ID, options.Workspace.ID)
|
p, err := m.client.Plans.create(options.ConfigurationVersion.ID, options.Workspace.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -744,6 +750,7 @@ func (m *mockRuns) Create(ctx context.Context, options tfe.RunCreateOptions) (*t
|
||||||
ID: generateID("run-"),
|
ID: generateID("run-"),
|
||||||
Actions: &tfe.RunActions{IsCancelable: true},
|
Actions: &tfe.RunActions{IsCancelable: true},
|
||||||
Apply: a,
|
Apply: a,
|
||||||
|
CostEstimate: ce,
|
||||||
HasChanges: false,
|
HasChanges: false,
|
||||||
Permissions: &tfe.RunPermissions{},
|
Permissions: &tfe.RunPermissions{},
|
||||||
Plan: p,
|
Plan: p,
|
||||||
|
@ -1043,6 +1050,14 @@ func (m *mockWorkspaces) Read(ctx context.Context, organization, workspace strin
|
||||||
return w, nil
|
return w, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *mockWorkspaces) ReadByID(ctx context.Context, workspaceID string) (*tfe.Workspace, error) {
|
||||||
|
w, ok := m.workspaceIDs[workspaceID]
|
||||||
|
if !ok {
|
||||||
|
return nil, tfe.ErrResourceNotFound
|
||||||
|
}
|
||||||
|
return w, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (m *mockWorkspaces) Update(ctx context.Context, organization, workspace string, options tfe.WorkspaceUpdateOptions) (*tfe.Workspace, error) {
|
func (m *mockWorkspaces) Update(ctx context.Context, organization, workspace string, options tfe.WorkspaceUpdateOptions) (*tfe.Workspace, error) {
|
||||||
w, ok := m.workspaceNames[workspace]
|
w, ok := m.workspaceNames[workspace]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -1065,6 +1080,28 @@ func (m *mockWorkspaces) Update(ctx context.Context, organization, workspace str
|
||||||
return w, nil
|
return w, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *mockWorkspaces) UpdateByID(ctx context.Context, workspaceID string, options tfe.WorkspaceUpdateOptions) (*tfe.Workspace, error) {
|
||||||
|
w, ok := m.workspaceIDs[workspaceID]
|
||||||
|
if !ok {
|
||||||
|
return nil, tfe.ErrResourceNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
if options.Name != nil {
|
||||||
|
w.Name = *options.Name
|
||||||
|
}
|
||||||
|
if options.TerraformVersion != nil {
|
||||||
|
w.TerraformVersion = *options.TerraformVersion
|
||||||
|
}
|
||||||
|
if options.WorkingDirectory != nil {
|
||||||
|
w.WorkingDirectory = *options.WorkingDirectory
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(m.workspaceNames, w.Name)
|
||||||
|
m.workspaceNames[w.Name] = w
|
||||||
|
|
||||||
|
return w, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (m *mockWorkspaces) Delete(ctx context.Context, organization, workspace string) error {
|
func (m *mockWorkspaces) Delete(ctx context.Context, organization, workspace string) error {
|
||||||
if w, ok := m.workspaceNames[workspace]; ok {
|
if w, ok := m.workspaceNames[workspace]; ok {
|
||||||
delete(m.workspaceIDs, w.ID)
|
delete(m.workspaceIDs, w.ID)
|
||||||
|
@ -1073,6 +1110,14 @@ func (m *mockWorkspaces) Delete(ctx context.Context, organization, workspace str
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *mockWorkspaces) DeleteByID(ctx context.Context, workspaceID string) error {
|
||||||
|
if w, ok := m.workspaceIDs[workspaceID]; ok {
|
||||||
|
delete(m.workspaceIDs, w.Name)
|
||||||
|
}
|
||||||
|
delete(m.workspaceIDs, workspaceID)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (m *mockWorkspaces) RemoveVCSConnection(ctx context.Context, organization, workspace string) (*tfe.Workspace, error) {
|
func (m *mockWorkspaces) RemoveVCSConnection(ctx context.Context, organization, workspace string) (*tfe.Workspace, error) {
|
||||||
w, ok := m.workspaceNames[workspace]
|
w, ok := m.workspaceNames[workspace]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -1082,6 +1127,15 @@ func (m *mockWorkspaces) RemoveVCSConnection(ctx context.Context, organization,
|
||||||
return w, nil
|
return w, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *mockWorkspaces) RemoveVCSConnectionByID(ctx context.Context, workspaceID string) (*tfe.Workspace, error) {
|
||||||
|
w, ok := m.workspaceIDs[workspaceID]
|
||||||
|
if !ok {
|
||||||
|
return nil, tfe.ErrResourceNotFound
|
||||||
|
}
|
||||||
|
w.VCSRepo = nil
|
||||||
|
return w, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (m *mockWorkspaces) Lock(ctx context.Context, workspaceID string, options tfe.WorkspaceLockOptions) (*tfe.Workspace, error) {
|
func (m *mockWorkspaces) Lock(ctx context.Context, workspaceID string, options tfe.WorkspaceLockOptions) (*tfe.Workspace, error) {
|
||||||
w, ok := m.workspaceIDs[workspaceID]
|
w, ok := m.workspaceIDs[workspaceID]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|
|
@ -59,7 +59,7 @@ func TestRemote_planBasic(t *testing.T) {
|
||||||
t.Fatalf("expected remote backend header in output: %s", output)
|
t.Fatalf("expected remote backend header in output: %s", output)
|
||||||
}
|
}
|
||||||
if !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
|
if !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
|
||||||
t.Fatalf("expected plan summery in output: %s", output)
|
t.Fatalf("expected plan summary in output: %s", output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,7 +113,7 @@ func TestRemote_planLongLine(t *testing.T) {
|
||||||
t.Fatalf("expected remote backend header in output: %s", output)
|
t.Fatalf("expected remote backend header in output: %s", output)
|
||||||
}
|
}
|
||||||
if !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
|
if !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
|
||||||
t.Fatalf("expected plan summery in output: %s", output)
|
t.Fatalf("expected plan summary in output: %s", output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -374,7 +374,7 @@ func TestRemote_planNoChanges(t *testing.T) {
|
||||||
|
|
||||||
output := b.CLI.(*cli.MockUi).OutputWriter.String()
|
output := b.CLI.(*cli.MockUi).OutputWriter.String()
|
||||||
if !strings.Contains(output, "No changes. Infrastructure is up-to-date.") {
|
if !strings.Contains(output, "No changes. Infrastructure is up-to-date.") {
|
||||||
t.Fatalf("expected no changes in plan summery: %s", output)
|
t.Fatalf("expected no changes in plan summary: %s", output)
|
||||||
}
|
}
|
||||||
if !strings.Contains(output, "Sentinel Result: true") {
|
if !strings.Contains(output, "Sentinel Result: true") {
|
||||||
t.Fatalf("expected policy check result in output: %s", output)
|
t.Fatalf("expected policy check result in output: %s", output)
|
||||||
|
@ -415,7 +415,7 @@ func TestRemote_planForceLocal(t *testing.T) {
|
||||||
t.Fatalf("unexpected remote backend header in output: %s", output)
|
t.Fatalf("unexpected remote backend header in output: %s", output)
|
||||||
}
|
}
|
||||||
if !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
|
if !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
|
||||||
t.Fatalf("expected plan summery in output: %s", output)
|
t.Fatalf("expected plan summary in output: %s", output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -446,7 +446,7 @@ func TestRemote_planWithoutOperationsEntitlement(t *testing.T) {
|
||||||
t.Fatalf("unexpected remote backend header in output: %s", output)
|
t.Fatalf("unexpected remote backend header in output: %s", output)
|
||||||
}
|
}
|
||||||
if !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
|
if !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
|
||||||
t.Fatalf("expected plan summery in output: %s", output)
|
t.Fatalf("expected plan summary in output: %s", output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -491,7 +491,7 @@ func TestRemote_planWorkspaceWithoutOperations(t *testing.T) {
|
||||||
t.Fatalf("unexpected remote backend header in output: %s", output)
|
t.Fatalf("unexpected remote backend header in output: %s", output)
|
||||||
}
|
}
|
||||||
if !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
|
if !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
|
||||||
t.Fatalf("expected plan summery in output: %s", output)
|
t.Fatalf("expected plan summary in output: %s", output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -562,7 +562,7 @@ func TestRemote_planLockTimeout(t *testing.T) {
|
||||||
t.Fatalf("expected lock timout error in output: %s", output)
|
t.Fatalf("expected lock timout error in output: %s", output)
|
||||||
}
|
}
|
||||||
if strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
|
if strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
|
||||||
t.Fatalf("unexpected plan summery in output: %s", output)
|
t.Fatalf("unexpected plan summary in output: %s", output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -654,7 +654,7 @@ func TestRemote_planWithWorkingDirectory(t *testing.T) {
|
||||||
t.Fatalf("expected remote backend header in output: %s", output)
|
t.Fatalf("expected remote backend header in output: %s", output)
|
||||||
}
|
}
|
||||||
if !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
|
if !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
|
||||||
t.Fatalf("expected plan summery in output: %s", output)
|
t.Fatalf("expected plan summary in output: %s", output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -709,7 +709,7 @@ func TestRemote_planWithWorkingDirectoryFromCurrentPath(t *testing.T) {
|
||||||
t.Fatalf("expected remote backend header in output: %s", output)
|
t.Fatalf("expected remote backend header in output: %s", output)
|
||||||
}
|
}
|
||||||
if !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
|
if !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
|
||||||
t.Fatalf("expected plan summery in output: %s", output)
|
t.Fatalf("expected plan summary in output: %s", output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -777,7 +777,7 @@ func TestRemote_planPolicyPass(t *testing.T) {
|
||||||
t.Fatalf("expected policy check result in output: %s", output)
|
t.Fatalf("expected policy check result in output: %s", output)
|
||||||
}
|
}
|
||||||
if !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
|
if !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
|
||||||
t.Fatalf("expected plan summery in output: %s", output)
|
t.Fatalf("expected plan summary in output: %s", output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -816,7 +816,7 @@ func TestRemote_planPolicyHardFail(t *testing.T) {
|
||||||
t.Fatalf("expected policy check result in output: %s", output)
|
t.Fatalf("expected policy check result in output: %s", output)
|
||||||
}
|
}
|
||||||
if !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
|
if !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
|
||||||
t.Fatalf("expected plan summery in output: %s", output)
|
t.Fatalf("expected plan summary in output: %s", output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -855,7 +855,7 @@ func TestRemote_planPolicySoftFail(t *testing.T) {
|
||||||
t.Fatalf("expected policy check result in output: %s", output)
|
t.Fatalf("expected policy check result in output: %s", output)
|
||||||
}
|
}
|
||||||
if !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
|
if !strings.Contains(output, "1 to add, 0 to change, 0 to destroy") {
|
||||||
t.Fatalf("expected plan summery in output: %s", output)
|
t.Fatalf("expected plan summary in output: %s", output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -115,6 +115,7 @@ func testBackend(t *testing.T, obj cty.Value) (*Remote, func()) {
|
||||||
b.CLI = cli.NewMockUi()
|
b.CLI = cli.NewMockUi()
|
||||||
b.client.Applies = mc.Applies
|
b.client.Applies = mc.Applies
|
||||||
b.client.ConfigurationVersions = mc.ConfigurationVersions
|
b.client.ConfigurationVersions = mc.ConfigurationVersions
|
||||||
|
b.client.CostEstimates = mc.CostEstimates
|
||||||
b.client.Organizations = mc.Organizations
|
b.client.Organizations = mc.Organizations
|
||||||
b.client.Plans = mc.Plans
|
b.client.Plans = mc.Plans
|
||||||
b.client.PolicyChecks = mc.PolicyChecks
|
b.client.PolicyChecks = mc.PolicyChecks
|
||||||
|
|
|
@ -136,6 +136,7 @@ tests:
|
||||||
$ export TFE_ADDRESS=https://tfe.local
|
$ export TFE_ADDRESS=https://tfe.local
|
||||||
$ export TFE_TOKEN=xxxxxxxxxxxxxxxxxxx
|
$ export TFE_TOKEN=xxxxxxxxxxxxxxxxxxx
|
||||||
$ export GITHUB_TOKEN=xxxxxxxxxxxxxxxx
|
$ export GITHUB_TOKEN=xxxxxxxxxxxxxxxx
|
||||||
|
$ export GITHUB_IDENTIFIER=xxxxxxxxxxx
|
||||||
```
|
```
|
||||||
|
|
||||||
In order for the tests relating to queuing and capacity to pass, FRQ should be
|
In order for the tests relating to queuing and capacity to pass, FRQ should be
|
||||||
|
|
|
@ -1,121 +0,0 @@
|
||||||
package tfe
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"net/url"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Compile-time proof of interface implementation.
|
|
||||||
var _ CostEstimations = (*costEstimations)(nil)
|
|
||||||
|
|
||||||
// CostEstimations describes all the costEstimation related methods that
|
|
||||||
// the Terraform Enterprise API supports.
|
|
||||||
//
|
|
||||||
// TFE API docs: https://www.terraform.io/docs/enterprise/api/ (TBD)
|
|
||||||
type CostEstimations interface {
|
|
||||||
// Read a costEstimation by its ID.
|
|
||||||
Read(ctx context.Context, costEstimationID string) (*CostEstimation, error)
|
|
||||||
|
|
||||||
// Logs retrieves the logs of a costEstimation.
|
|
||||||
Logs(ctx context.Context, costEstimationID string) (io.Reader, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// costEstimations implements CostEstimations.
|
|
||||||
type costEstimations struct {
|
|
||||||
client *Client
|
|
||||||
}
|
|
||||||
|
|
||||||
// CostEstimationStatus represents a costEstimation state.
|
|
||||||
type CostEstimationStatus string
|
|
||||||
|
|
||||||
//List all available costEstimation statuses.
|
|
||||||
const (
|
|
||||||
CostEstimationCanceled CostEstimationStatus = "canceled"
|
|
||||||
CostEstimationErrored CostEstimationStatus = "errored"
|
|
||||||
CostEstimationFinished CostEstimationStatus = "finished"
|
|
||||||
CostEstimationQueued CostEstimationStatus = "queued"
|
|
||||||
)
|
|
||||||
|
|
||||||
// CostEstimation represents a Terraform Enterprise costEstimation.
|
|
||||||
type CostEstimation struct {
|
|
||||||
ID string `jsonapi:"primary,cost-estimations"`
|
|
||||||
ErrorMessage string `jsonapi:"attr,error-message"`
|
|
||||||
Status CostEstimationStatus `jsonapi:"attr,status"`
|
|
||||||
StatusTimestamps *CostEstimationStatusTimestamps `jsonapi:"attr,status-timestamps"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// CostEstimationStatusTimestamps holds the timestamps for individual costEstimation statuses.
|
|
||||||
type CostEstimationStatusTimestamps struct {
|
|
||||||
CanceledAt time.Time `json:"canceled-at"`
|
|
||||||
ErroredAt time.Time `json:"errored-at"`
|
|
||||||
FinishedAt time.Time `json:"finished-at"`
|
|
||||||
QueuedAt time.Time `json:"queued-at"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read a costEstimation by its ID.
|
|
||||||
func (s *costEstimations) Read(ctx context.Context, costEstimationID string) (*CostEstimation, error) {
|
|
||||||
if !validStringID(&costEstimationID) {
|
|
||||||
return nil, errors.New("invalid value for cost estimation ID")
|
|
||||||
}
|
|
||||||
|
|
||||||
u := fmt.Sprintf("cost-estimations/%s", url.QueryEscape(costEstimationID))
|
|
||||||
req, err := s.client.newRequest("GET", u, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
ce := &CostEstimation{}
|
|
||||||
err = s.client.do(ctx, req, ce)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return ce, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Logs retrieves the logs of a costEstimation.
|
|
||||||
func (s *costEstimations) Logs(ctx context.Context, costEstimationID string) (io.Reader, error) {
|
|
||||||
if !validStringID(&costEstimationID) {
|
|
||||||
return nil, errors.New("invalid value for cost estimation ID")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Loop until the context is canceled or the cost estimation is finished
|
|
||||||
// running. The cost estimation logs are not streamed and so only available
|
|
||||||
// once the estimation is finished.
|
|
||||||
for {
|
|
||||||
// Get the costEstimation to make sure it exists.
|
|
||||||
ce, err := s.Read(ctx, costEstimationID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
switch ce.Status {
|
|
||||||
case CostEstimationQueued:
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
return nil, ctx.Err()
|
|
||||||
case <-time.After(500 * time.Millisecond):
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
u := fmt.Sprintf("cost-estimations/%s/output", url.QueryEscape(costEstimationID))
|
|
||||||
req, err := s.client.newRequest("GET", u, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
logs := bytes.NewBuffer(nil)
|
|
||||||
err = s.client.do(ctx, req, logs)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return logs, nil
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -55,6 +55,9 @@ type Plan struct {
|
||||||
ResourceDestructions int `jsonapi:"attr,resource-destructions"`
|
ResourceDestructions int `jsonapi:"attr,resource-destructions"`
|
||||||
Status PlanStatus `jsonapi:"attr,status"`
|
Status PlanStatus `jsonapi:"attr,status"`
|
||||||
StatusTimestamps *PlanStatusTimestamps `jsonapi:"attr,status-timestamps"`
|
StatusTimestamps *PlanStatusTimestamps `jsonapi:"attr,status-timestamps"`
|
||||||
|
|
||||||
|
// Relations
|
||||||
|
Exports []*PlanExport `jsonapi:"relation,exports"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// PlanStatusTimestamps holds the timestamps for individual plan statuses.
|
// PlanStatusTimestamps holds the timestamps for individual plan statuses.
|
||||||
|
|
|
@ -0,0 +1,175 @@
|
||||||
|
package tfe
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Compile-time proof of interface implementation.
|
||||||
|
var _ PlanExports = (*planExports)(nil)
|
||||||
|
|
||||||
|
// PlanExports describes all the plan export related methods that the Terraform
|
||||||
|
// Enterprise API supports.
|
||||||
|
//
|
||||||
|
// TFE API docs: https://www.terraform.io/docs/enterprise/api/plan-exports.html
|
||||||
|
type PlanExports interface {
|
||||||
|
// Export a plan by its ID with the given options.
|
||||||
|
Create(ctx context.Context, options PlanExportCreateOptions) (*PlanExport, error)
|
||||||
|
|
||||||
|
// Read a plan export by its ID.
|
||||||
|
Read(ctx context.Context, planExportID string) (*PlanExport, error)
|
||||||
|
|
||||||
|
// Delete a plan export by its ID.
|
||||||
|
Delete(ctx context.Context, planExportID string) error
|
||||||
|
|
||||||
|
// Download the data of an plan export.
|
||||||
|
Download(ctx context.Context, planExportID string) ([]byte, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// planExports implements PlanExports.
|
||||||
|
type planExports struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// PlanExportDataType represents the type of data exported from a plan.
|
||||||
|
type PlanExportDataType string
|
||||||
|
|
||||||
|
// List all available plan export data types.
|
||||||
|
const (
|
||||||
|
PlanExportSentinelMockBundleV0 PlanExportDataType = "sentinel-mock-bundle-v0"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PlanExportStatus represents a plan export state.
|
||||||
|
type PlanExportStatus string
|
||||||
|
|
||||||
|
// List all available plan export statuses.
|
||||||
|
const (
|
||||||
|
PlanExportCanceled PlanExportStatus = "canceled"
|
||||||
|
PlanExportErrored PlanExportStatus = "errored"
|
||||||
|
PlanExportExpired PlanExportStatus = "expired"
|
||||||
|
PlanExportFinished PlanExportStatus = "finished"
|
||||||
|
PlanExportPending PlanExportStatus = "pending"
|
||||||
|
PlanExportQueued PlanExportStatus = "queued"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PlanExportStatusTimestamps holds the timestamps for plan export statuses.
|
||||||
|
type PlanExportStatusTimestamps struct {
|
||||||
|
CanceledAt time.Time `json:"canceled-at"`
|
||||||
|
ErroredAt time.Time `json:"errored-at"`
|
||||||
|
ExpiredAt time.Time `json:"expired-at"`
|
||||||
|
FinishedAt time.Time `json:"finished-at"`
|
||||||
|
QueuedAt time.Time `json:"queued-at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PlanExport represents an export of Terraform Enterprise plan data.
|
||||||
|
type PlanExport struct {
|
||||||
|
ID string `jsonapi:"primary,plan-exports"`
|
||||||
|
DataType PlanExportDataType `jsonapi:"attr,data-type"`
|
||||||
|
Status PlanExportStatus `jsonapi:"attr,status"`
|
||||||
|
StatusTimestamps *PlanExportStatusTimestamps `jsonapi:"attr,status-timestamps"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PlanExportCreateOptions represents the options for exporting data from a plan.
|
||||||
|
type PlanExportCreateOptions struct {
|
||||||
|
// For internal use only!
|
||||||
|
ID string `jsonapi:"primary,plan-exports"`
|
||||||
|
|
||||||
|
// The plan to export.
|
||||||
|
Plan *Plan `jsonapi:"relation,plan"`
|
||||||
|
|
||||||
|
// The name of the policy set.
|
||||||
|
DataType *PlanExportDataType `jsonapi:"attr,data-type"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o PlanExportCreateOptions) valid() error {
|
||||||
|
if o.Plan == nil {
|
||||||
|
return errors.New("plan is required")
|
||||||
|
}
|
||||||
|
if o.DataType == nil {
|
||||||
|
return errors.New("data type is required")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *planExports) Create(ctx context.Context, options PlanExportCreateOptions) (*PlanExport, 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", "plan-exports", &options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
pe := &PlanExport{}
|
||||||
|
err = s.client.do(ctx, req, pe)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return pe, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read a plan export by its ID.
|
||||||
|
func (s *planExports) Read(ctx context.Context, planExportID string) (*PlanExport, error) {
|
||||||
|
if !validStringID(&planExportID) {
|
||||||
|
return nil, errors.New("invalid value for plan export ID")
|
||||||
|
}
|
||||||
|
|
||||||
|
u := fmt.Sprintf("plan-exports/%s", url.QueryEscape(planExportID))
|
||||||
|
req, err := s.client.newRequest("GET", u, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
pe := &PlanExport{}
|
||||||
|
err = s.client.do(ctx, req, pe)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return pe, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete a plan export by ID.
|
||||||
|
func (s *planExports) Delete(ctx context.Context, planExportID string) error {
|
||||||
|
if !validStringID(&planExportID) {
|
||||||
|
return errors.New("invalid value for plan export ID")
|
||||||
|
}
|
||||||
|
|
||||||
|
u := fmt.Sprintf("plan-exports/%s", url.QueryEscape(planExportID))
|
||||||
|
req, err := s.client.newRequest("DELETE", u, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.client.do(ctx, req, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Download a plan export's data. Data is exported in a .tar.gz format.
|
||||||
|
func (s *planExports) Download(ctx context.Context, planExportID string) ([]byte, error) {
|
||||||
|
if !validStringID(&planExportID) {
|
||||||
|
return nil, errors.New("invalid value for plan export ID")
|
||||||
|
}
|
||||||
|
|
||||||
|
u := fmt.Sprintf("plan-exports/%s/download", url.QueryEscape(planExportID))
|
||||||
|
req, err := s.client.newRequest("GET", u, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
err = s.client.do(ctx, req, &buf)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf.Bytes(), nil
|
||||||
|
}
|
|
@ -28,10 +28,12 @@ type PolicySets interface {
|
||||||
// Update an existing policy set.
|
// Update an existing policy set.
|
||||||
Update(ctx context.Context, policySetID string, options PolicySetUpdateOptions) (*PolicySet, error)
|
Update(ctx context.Context, policySetID string, options PolicySetUpdateOptions) (*PolicySet, error)
|
||||||
|
|
||||||
// Add policies to a policy set.
|
// Add policies to a policy set. This function can only be used when
|
||||||
|
// there is no VCS repository associated with the policy set.
|
||||||
AddPolicies(ctx context.Context, policySetID string, options PolicySetAddPoliciesOptions) error
|
AddPolicies(ctx context.Context, policySetID string, options PolicySetAddPoliciesOptions) error
|
||||||
|
|
||||||
// Remove policies from a policy set.
|
// Remove policies from a policy set. This function can only be used
|
||||||
|
// when there is no VCS repository associated with the policy set.
|
||||||
RemovePolicies(ctx context.Context, policySetID string, options PolicySetRemovePoliciesOptions) error
|
RemovePolicies(ctx context.Context, policySetID string, options PolicySetRemovePoliciesOptions) error
|
||||||
|
|
||||||
// Add workspaces to a policy set.
|
// Add workspaces to a policy set.
|
||||||
|
@ -61,7 +63,9 @@ type PolicySet struct {
|
||||||
Name string `jsonapi:"attr,name"`
|
Name string `jsonapi:"attr,name"`
|
||||||
Description string `jsonapi:"attr,description"`
|
Description string `jsonapi:"attr,description"`
|
||||||
Global bool `jsonapi:"attr,global"`
|
Global bool `jsonapi:"attr,global"`
|
||||||
|
PoliciesPath string `jsonapi:"attr,policies-path"`
|
||||||
PolicyCount int `jsonapi:"attr,policy-count"`
|
PolicyCount int `jsonapi:"attr,policy-count"`
|
||||||
|
VCSRepo *VCSRepo `jsonapi:"attr,vcs-repo"`
|
||||||
WorkspaceCount int `jsonapi:"attr,workspace-count"`
|
WorkspaceCount int `jsonapi:"attr,workspace-count"`
|
||||||
CreatedAt time.Time `jsonapi:"attr,created-at,iso8601"`
|
CreatedAt time.Time `jsonapi:"attr,created-at,iso8601"`
|
||||||
UpdatedAt time.Time `jsonapi:"attr,updated-at,iso8601"`
|
UpdatedAt time.Time `jsonapi:"attr,updated-at,iso8601"`
|
||||||
|
@ -115,9 +119,21 @@ type PolicySetCreateOptions struct {
|
||||||
// Whether or not the policy set is global.
|
// Whether or not the policy set is global.
|
||||||
Global *bool `jsonapi:"attr,global,omitempty"`
|
Global *bool `jsonapi:"attr,global,omitempty"`
|
||||||
|
|
||||||
|
// The sub-path within the attached VCS repository to ingress. All
|
||||||
|
// files and directories outside of this sub-path will be ignored.
|
||||||
|
// This option may only be specified when a VCS repo is present.
|
||||||
|
PoliciesPath *string `jsonapi:"attr,policies-path,omitempty"`
|
||||||
|
|
||||||
// The initial members of the policy set.
|
// The initial members of the policy set.
|
||||||
Policies []*Policy `jsonapi:"relation,policies,omitempty"`
|
Policies []*Policy `jsonapi:"relation,policies,omitempty"`
|
||||||
|
|
||||||
|
// VCS repository information. When present, the policies and
|
||||||
|
// configuration will be sourced from the specified VCS repository
|
||||||
|
// instead of being defined within the policy set itself. Note that
|
||||||
|
// this option is mutually exclusive with the Policies option and
|
||||||
|
// both cannot be used at the same time.
|
||||||
|
VCSRepo *VCSRepoOptions `jsonapi:"attr,vcs-repo,omitempty"`
|
||||||
|
|
||||||
// The initial list of workspaces for which the policy set should be enforced.
|
// The initial list of workspaces for which the policy set should be enforced.
|
||||||
Workspaces []*Workspace `jsonapi:"relation,workspaces,omitempty"`
|
Workspaces []*Workspace `jsonapi:"relation,workspaces,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,7 +102,7 @@ type Run struct {
|
||||||
// Relations
|
// Relations
|
||||||
Apply *Apply `jsonapi:"relation,apply"`
|
Apply *Apply `jsonapi:"relation,apply"`
|
||||||
ConfigurationVersion *ConfigurationVersion `jsonapi:"relation,configuration-version"`
|
ConfigurationVersion *ConfigurationVersion `jsonapi:"relation,configuration-version"`
|
||||||
CostEstimation *CostEstimation `jsonapi:"relation,cost-estimation"`
|
CostEstimate *CostEstimate `jsonapi:"relation,cost-estimate"`
|
||||||
Plan *Plan `jsonapi:"relation,plan"`
|
Plan *Plan `jsonapi:"relation,plan"`
|
||||||
PolicyChecks []*PolicyCheck `jsonapi:"relation,policy-checks"`
|
PolicyChecks []*PolicyCheck `jsonapi:"relation,policy-checks"`
|
||||||
Workspace *Workspace `jsonapi:"relation,workspace"`
|
Workspace *Workspace `jsonapi:"relation,workspace"`
|
||||||
|
|
|
@ -32,6 +32,8 @@ const (
|
||||||
DefaultAddress = "https://app.terraform.io"
|
DefaultAddress = "https://app.terraform.io"
|
||||||
// DefaultBasePath on which the API is served.
|
// DefaultBasePath on which the API is served.
|
||||||
DefaultBasePath = "/api/v2/"
|
DefaultBasePath = "/api/v2/"
|
||||||
|
// No-op API endpoint used to configure the rate limiter
|
||||||
|
PingEndpoint = "ping"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -106,13 +108,14 @@ type Client struct {
|
||||||
|
|
||||||
Applies Applies
|
Applies Applies
|
||||||
ConfigurationVersions ConfigurationVersions
|
ConfigurationVersions ConfigurationVersions
|
||||||
CostEstimations CostEstimations
|
CostEstimates CostEstimates
|
||||||
NotificationConfigurations NotificationConfigurations
|
NotificationConfigurations NotificationConfigurations
|
||||||
OAuthClients OAuthClients
|
OAuthClients OAuthClients
|
||||||
OAuthTokens OAuthTokens
|
OAuthTokens OAuthTokens
|
||||||
Organizations Organizations
|
Organizations Organizations
|
||||||
OrganizationTokens OrganizationTokens
|
OrganizationTokens OrganizationTokens
|
||||||
Plans Plans
|
Plans Plans
|
||||||
|
PlanExports PlanExports
|
||||||
Policies Policies
|
Policies Policies
|
||||||
PolicyChecks PolicyChecks
|
PolicyChecks PolicyChecks
|
||||||
PolicySets PolicySets
|
PolicySets PolicySets
|
||||||
|
@ -196,13 +199,14 @@ func NewClient(cfg *Config) (*Client, error) {
|
||||||
// Create the services.
|
// Create the services.
|
||||||
client.Applies = &applies{client: client}
|
client.Applies = &applies{client: client}
|
||||||
client.ConfigurationVersions = &configurationVersions{client: client}
|
client.ConfigurationVersions = &configurationVersions{client: client}
|
||||||
client.CostEstimations = &costEstimations{client: client}
|
client.CostEstimates = &costEstimates{client: client}
|
||||||
client.NotificationConfigurations = ¬ificationConfigurations{client: client}
|
client.NotificationConfigurations = ¬ificationConfigurations{client: client}
|
||||||
client.OAuthClients = &oAuthClients{client: client}
|
client.OAuthClients = &oAuthClients{client: client}
|
||||||
client.OAuthTokens = &oAuthTokens{client: client}
|
client.OAuthTokens = &oAuthTokens{client: client}
|
||||||
client.Organizations = &organizations{client: client}
|
client.Organizations = &organizations{client: client}
|
||||||
client.OrganizationTokens = &organizationTokens{client: client}
|
client.OrganizationTokens = &organizationTokens{client: client}
|
||||||
client.Plans = &plans{client: client}
|
client.Plans = &plans{client: client}
|
||||||
|
client.PlanExports = &planExports{client: client}
|
||||||
client.Policies = &policies{client: client}
|
client.Policies = &policies{client: client}
|
||||||
client.PolicyChecks = &policyChecks{client: client}
|
client.PolicyChecks = &policyChecks{client: client}
|
||||||
client.PolicySets = &policySets{client: client}
|
client.PolicySets = &policySets{client: client}
|
||||||
|
@ -291,7 +295,11 @@ func rateLimitBackoff(min, max time.Duration, attemptNum int, resp *http.Respons
|
||||||
// configureLimiter configures the rate limiter.
|
// configureLimiter configures the rate limiter.
|
||||||
func (c *Client) configureLimiter() error {
|
func (c *Client) configureLimiter() error {
|
||||||
// Create a new request.
|
// Create a new request.
|
||||||
req, err := http.NewRequest("GET", c.baseURL.String(), nil)
|
u, err := c.baseURL.Parse(PingEndpoint)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
req, err := http.NewRequest("GET", u.String(), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,6 +40,11 @@ func NotificationDestination(v NotificationDestinationType) *NotificationDestina
|
||||||
return &v
|
return &v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PlanExportType returns a pointer to the given plan export data type.
|
||||||
|
func PlanExportType(v PlanExportDataType) *PlanExportDataType {
|
||||||
|
return &v
|
||||||
|
}
|
||||||
|
|
||||||
// ServiceProvider returns a pointer to the given service provider type.
|
// ServiceProvider returns a pointer to the given service provider type.
|
||||||
func ServiceProvider(v ServiceProviderType) *ServiceProviderType {
|
func ServiceProvider(v ServiceProviderType) *ServiceProviderType {
|
||||||
return &v
|
return &v
|
||||||
|
|
|
@ -25,15 +25,27 @@ type Workspaces interface {
|
||||||
// Read a workspace by its name.
|
// Read a workspace by its name.
|
||||||
Read(ctx context.Context, organization string, workspace string) (*Workspace, error)
|
Read(ctx context.Context, organization string, workspace string) (*Workspace, error)
|
||||||
|
|
||||||
|
// ReadByID reads a workspace by its ID.
|
||||||
|
ReadByID(ctx context.Context, workspaceID string) (*Workspace, error)
|
||||||
|
|
||||||
// Update settings of an existing workspace.
|
// Update settings of an existing workspace.
|
||||||
Update(ctx context.Context, organization string, workspace string, options WorkspaceUpdateOptions) (*Workspace, error)
|
Update(ctx context.Context, organization string, workspace string, options WorkspaceUpdateOptions) (*Workspace, error)
|
||||||
|
|
||||||
|
// UpdateByID updates the settings of an existing workspace.
|
||||||
|
UpdateByID(ctx context.Context, workspaceID string, options WorkspaceUpdateOptions) (*Workspace, error)
|
||||||
|
|
||||||
// Delete a workspace by its name.
|
// Delete a workspace by its name.
|
||||||
Delete(ctx context.Context, organization string, workspace string) error
|
Delete(ctx context.Context, organization string, workspace string) error
|
||||||
|
|
||||||
|
// DeleteByID deletes a workspace by its ID.
|
||||||
|
DeleteByID(ctx context.Context, workspaceID string) error
|
||||||
|
|
||||||
// RemoveVCSConnection from a workspace.
|
// RemoveVCSConnection from a workspace.
|
||||||
RemoveVCSConnection(ctx context.Context, organization, workspace string) (*Workspace, error)
|
RemoveVCSConnection(ctx context.Context, organization, workspace string) (*Workspace, error)
|
||||||
|
|
||||||
|
// RemoveVCSConnectionByID removes a VCS connection from a workspace.
|
||||||
|
RemoveVCSConnectionByID(ctx context.Context, workspaceID string) (*Workspace, error)
|
||||||
|
|
||||||
// Lock a workspace by its ID.
|
// Lock a workspace by its ID.
|
||||||
Lock(ctx context.Context, workspaceID string, options WorkspaceLockOptions) (*Workspace, error)
|
Lock(ctx context.Context, workspaceID string, options WorkspaceLockOptions) (*Workspace, error)
|
||||||
|
|
||||||
|
@ -69,6 +81,7 @@ type Workspace struct {
|
||||||
CanQueueDestroyPlan bool `jsonapi:"attr,can-queue-destroy-plan"`
|
CanQueueDestroyPlan bool `jsonapi:"attr,can-queue-destroy-plan"`
|
||||||
CreatedAt time.Time `jsonapi:"attr,created-at,iso8601"`
|
CreatedAt time.Time `jsonapi:"attr,created-at,iso8601"`
|
||||||
Environment string `jsonapi:"attr,environment"`
|
Environment string `jsonapi:"attr,environment"`
|
||||||
|
FileTriggersEnabled bool `jsonapi:"attr,file-triggers-enabled"`
|
||||||
Locked bool `jsonapi:"attr,locked"`
|
Locked bool `jsonapi:"attr,locked"`
|
||||||
MigrationEnvironment string `jsonapi:"attr,migration-environment"`
|
MigrationEnvironment string `jsonapi:"attr,migration-environment"`
|
||||||
Name string `jsonapi:"attr,name"`
|
Name string `jsonapi:"attr,name"`
|
||||||
|
@ -76,6 +89,7 @@ type Workspace struct {
|
||||||
Permissions *WorkspacePermissions `jsonapi:"attr,permissions"`
|
Permissions *WorkspacePermissions `jsonapi:"attr,permissions"`
|
||||||
QueueAllRuns bool `jsonapi:"attr,queue-all-runs"`
|
QueueAllRuns bool `jsonapi:"attr,queue-all-runs"`
|
||||||
TerraformVersion string `jsonapi:"attr,terraform-version"`
|
TerraformVersion string `jsonapi:"attr,terraform-version"`
|
||||||
|
TriggerPrefixes []string `jsonapi:"attr,trigger-prefixes"`
|
||||||
VCSRepo *VCSRepo `jsonapi:"attr,vcs-repo"`
|
VCSRepo *VCSRepo `jsonapi:"attr,vcs-repo"`
|
||||||
WorkingDirectory string `jsonapi:"attr,working-directory"`
|
WorkingDirectory string `jsonapi:"attr,working-directory"`
|
||||||
|
|
||||||
|
@ -149,6 +163,12 @@ type WorkspaceCreateOptions struct {
|
||||||
// Whether to automatically apply changes when a Terraform plan is successful.
|
// Whether to automatically apply changes when a Terraform plan is successful.
|
||||||
AutoApply *bool `jsonapi:"attr,auto-apply,omitempty"`
|
AutoApply *bool `jsonapi:"attr,auto-apply,omitempty"`
|
||||||
|
|
||||||
|
// Whether to filter runs based on the changed files in a VCS push. If
|
||||||
|
// enabled, the working directory and trigger prefixes describe a set of
|
||||||
|
// paths which must contain changes for a VCS push to trigger a run. If
|
||||||
|
// disabled, any push will trigger a run.
|
||||||
|
FileTriggersEnabled *bool `jsonapi:"attr,file-triggers-enabled,omitempty"`
|
||||||
|
|
||||||
// The legacy TFE environment to use as the source of the migration, in the
|
// The legacy TFE environment to use as the source of the migration, in the
|
||||||
// form organization/environment. Omit this unless you are migrating a legacy
|
// form organization/environment. Omit this unless you are migrating a legacy
|
||||||
// environment.
|
// environment.
|
||||||
|
@ -167,6 +187,10 @@ type WorkspaceCreateOptions struct {
|
||||||
// workspace, the latest version is selected unless otherwise specified.
|
// workspace, the latest version is selected unless otherwise specified.
|
||||||
TerraformVersion *string `jsonapi:"attr,terraform-version,omitempty"`
|
TerraformVersion *string `jsonapi:"attr,terraform-version,omitempty"`
|
||||||
|
|
||||||
|
// List of repository-root-relative paths which list all locations to be
|
||||||
|
// tracked for changes. See FileTriggersEnabled above for more details.
|
||||||
|
TriggerPrefixes []string `jsonapi:"attr,trigger-prefixes,omitempty"`
|
||||||
|
|
||||||
// Settings for the workspace's VCS repository. If omitted, the workspace is
|
// Settings for the workspace's VCS repository. If omitted, the workspace is
|
||||||
// created without a VCS repo. If included, you must specify at least the
|
// created without a VCS repo. If included, you must specify at least the
|
||||||
// oauth-token-id and identifier keys below.
|
// oauth-token-id and identifier keys below.
|
||||||
|
@ -251,6 +275,27 @@ func (s *workspaces) Read(ctx context.Context, organization, workspace string) (
|
||||||
return w, nil
|
return w, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ReadByID reads a workspace by its ID.
|
||||||
|
func (s *workspaces) ReadByID(ctx context.Context, workspaceID string) (*Workspace, error) {
|
||||||
|
if !validStringID(&workspaceID) {
|
||||||
|
return nil, errors.New("invalid value for workspace ID")
|
||||||
|
}
|
||||||
|
|
||||||
|
u := fmt.Sprintf("workspaces/%s", url.QueryEscape(workspaceID))
|
||||||
|
req, err := s.client.newRequest("GET", u, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
w := &Workspace{}
|
||||||
|
err = s.client.do(ctx, req, w)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return w, nil
|
||||||
|
}
|
||||||
|
|
||||||
// WorkspaceUpdateOptions represents the options for updating a workspace.
|
// WorkspaceUpdateOptions represents the options for updating a workspace.
|
||||||
type WorkspaceUpdateOptions struct {
|
type WorkspaceUpdateOptions struct {
|
||||||
// For internal use only!
|
// For internal use only!
|
||||||
|
@ -265,6 +310,12 @@ type WorkspaceUpdateOptions struct {
|
||||||
// API and UI.
|
// API and UI.
|
||||||
Name *string `jsonapi:"attr,name,omitempty"`
|
Name *string `jsonapi:"attr,name,omitempty"`
|
||||||
|
|
||||||
|
// Whether to filter runs based on the changed files in a VCS push. If
|
||||||
|
// enabled, the working directory and trigger prefixes describe a set of
|
||||||
|
// paths which must contain changes for a VCS push to trigger a run. If
|
||||||
|
// disabled, any push will trigger a run.
|
||||||
|
FileTriggersEnabled *bool `jsonapi:"attr,file-triggers-enabled,omitempty"`
|
||||||
|
|
||||||
// Whether to queue all runs. Unless this is set to true, runs triggered by
|
// Whether to queue all runs. Unless this is set to true, runs triggered by
|
||||||
// a webhook will not be queued until at least one run is manually queued.
|
// a webhook will not be queued until at least one run is manually queued.
|
||||||
QueueAllRuns *bool `jsonapi:"attr,queue-all-runs,omitempty"`
|
QueueAllRuns *bool `jsonapi:"attr,queue-all-runs,omitempty"`
|
||||||
|
@ -272,6 +323,10 @@ type WorkspaceUpdateOptions struct {
|
||||||
// The version of Terraform to use for this workspace.
|
// The version of Terraform to use for this workspace.
|
||||||
TerraformVersion *string `jsonapi:"attr,terraform-version,omitempty"`
|
TerraformVersion *string `jsonapi:"attr,terraform-version,omitempty"`
|
||||||
|
|
||||||
|
// List of repository-root-relative paths which list all locations to be
|
||||||
|
// tracked for changes. See FileTriggersEnabled above for more details.
|
||||||
|
TriggerPrefixes []string `jsonapi:"attr,trigger-prefixes,omitempty"`
|
||||||
|
|
||||||
// To delete a workspace's existing VCS repo, specify null instead of an
|
// To delete a workspace's existing VCS repo, specify null instead of an
|
||||||
// object. To modify a workspace's existing VCS repo, include whichever of
|
// object. To modify a workspace's existing VCS repo, include whichever of
|
||||||
// the keys below you wish to modify. To add a new VCS repo to a workspace
|
// the keys below you wish to modify. To add a new VCS repo to a workspace
|
||||||
|
@ -317,6 +372,30 @@ func (s *workspaces) Update(ctx context.Context, organization, workspace string,
|
||||||
return w, nil
|
return w, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateByID updates the settings of an existing workspace.
|
||||||
|
func (s *workspaces) UpdateByID(ctx context.Context, workspaceID string, options WorkspaceUpdateOptions) (*Workspace, error) {
|
||||||
|
if !validStringID(&workspaceID) {
|
||||||
|
return nil, errors.New("invalid value for workspace ID")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure we don't send a user provided ID.
|
||||||
|
options.ID = ""
|
||||||
|
|
||||||
|
u := fmt.Sprintf("workspaces/%s", url.QueryEscape(workspaceID))
|
||||||
|
req, err := s.client.newRequest("PATCH", u, &options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
w := &Workspace{}
|
||||||
|
err = s.client.do(ctx, req, w)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return w, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Delete a workspace by its name.
|
// Delete a workspace by its name.
|
||||||
func (s *workspaces) Delete(ctx context.Context, organization, workspace string) error {
|
func (s *workspaces) Delete(ctx context.Context, organization, workspace string) error {
|
||||||
if !validStringID(&organization) {
|
if !validStringID(&organization) {
|
||||||
|
@ -339,6 +418,21 @@ func (s *workspaces) Delete(ctx context.Context, organization, workspace string)
|
||||||
return s.client.do(ctx, req, nil)
|
return s.client.do(ctx, req, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeleteByID deletes a workspace by its ID.
|
||||||
|
func (s *workspaces) DeleteByID(ctx context.Context, workspaceID string) error {
|
||||||
|
if !validStringID(&workspaceID) {
|
||||||
|
return errors.New("invalid value for workspace ID")
|
||||||
|
}
|
||||||
|
|
||||||
|
u := fmt.Sprintf("workspaces/%s", url.QueryEscape(workspaceID))
|
||||||
|
req, err := s.client.newRequest("DELETE", u, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.client.do(ctx, req, nil)
|
||||||
|
}
|
||||||
|
|
||||||
// workspaceRemoveVCSConnectionOptions
|
// workspaceRemoveVCSConnectionOptions
|
||||||
type workspaceRemoveVCSConnectionOptions struct {
|
type workspaceRemoveVCSConnectionOptions struct {
|
||||||
ID string `jsonapi:"primary,workspaces"`
|
ID string `jsonapi:"primary,workspaces"`
|
||||||
|
@ -374,6 +468,28 @@ func (s *workspaces) RemoveVCSConnection(ctx context.Context, organization, work
|
||||||
return w, nil
|
return w, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RemoveVCSConnectionByID removes a VCS connection from a workspace.
|
||||||
|
func (s *workspaces) RemoveVCSConnectionByID(ctx context.Context, workspaceID string) (*Workspace, error) {
|
||||||
|
if !validStringID(&workspaceID) {
|
||||||
|
return nil, errors.New("invalid value for workspace ID")
|
||||||
|
}
|
||||||
|
|
||||||
|
u := fmt.Sprintf("workspaces/%s", url.QueryEscape(workspaceID))
|
||||||
|
|
||||||
|
req, err := s.client.newRequest("PATCH", u, &workspaceRemoveVCSConnectionOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
w := &Workspace{}
|
||||||
|
err = s.client.do(ctx, req, w)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return w, nil
|
||||||
|
}
|
||||||
|
|
||||||
// WorkspaceLockOptions represents the options for locking a workspace.
|
// WorkspaceLockOptions represents the options for locking a workspace.
|
||||||
type WorkspaceLockOptions struct {
|
type WorkspaceLockOptions struct {
|
||||||
// Specifies the reason for locking the workspace.
|
// Specifies the reason for locking the workspace.
|
||||||
|
|
Loading…
Reference in New Issue