diff --git a/vendor/github.com/hashicorp/go-tfe/apply.go b/vendor/github.com/hashicorp/go-tfe/apply.go new file mode 100644 index 000000000..753410189 --- /dev/null +++ b/vendor/github.com/hashicorp/go-tfe/apply.go @@ -0,0 +1,131 @@ +package tfe + +import ( + "context" + "errors" + "fmt" + "io" + "net/url" + "time" +) + +// Compile-time proof of interface implementation. +var _ Applies = (*applies)(nil) + +// Applies describes all the apply related methods that the Terraform +// Enterprise API supports. +// +// TFE API docs: https://www.terraform.io/docs/enterprise/api/apply.html +type Applies interface { + // Read an apply by its ID. + Read(ctx context.Context, applyID string) (*Apply, error) + + // Logs retrieves the logs of an apply. + Logs(ctx context.Context, applyID string) (io.Reader, error) +} + +// applies implements Applys. +type applies struct { + client *Client +} + +// ApplyStatus represents an apply state. +type ApplyStatus string + +//List all available apply statuses. +const ( + ApplyCanceled ApplyStatus = "canceled" + ApplyCreated ApplyStatus = "created" + ApplyErrored ApplyStatus = "errored" + ApplyFinished ApplyStatus = "finished" + ApplyMFAWaiting ApplyStatus = "mfa_waiting" + ApplyPending ApplyStatus = "pending" + ApplyQueued ApplyStatus = "queued" + ApplyRunning ApplyStatus = "running" +) + +// Apply represents a Terraform Enterprise apply. +type Apply struct { + ID string `jsonapi:"primary,applies"` + LogReadURL string `jsonapi:"attr,log-read-url"` + ResourceAdditions int `jsonapi:"attr,resource-additions"` + ResourceChanges int `jsonapi:"attr,resource-changes"` + ResourceDestructions int `jsonapi:"attr,resource-destructions"` + Status ApplyStatus `jsonapi:"attr,status"` + StatusTimestamps *ApplyStatusTimestamps `jsonapi:"attr,status-timestamps"` +} + +// ApplyStatusTimestamps holds the timestamps for individual apply statuses. +type ApplyStatusTimestamps struct { + CanceledAt time.Time `json:"canceled-at"` + ErroredAt time.Time `json:"errored-at"` + FinishedAt time.Time `json:"finished-at"` + ForceCanceledAt time.Time `json:"force-canceled-at"` + QueuedAt time.Time `json:"queued-at"` + StartedAt time.Time `json:"started-at"` +} + +// Read an apply by its ID. +func (s *applies) Read(ctx context.Context, applyID string) (*Apply, error) { + if !validStringID(&applyID) { + return nil, errors.New("Invalid value for apply ID") + } + + u := fmt.Sprintf("applies/%s", url.QueryEscape(applyID)) + req, err := s.client.newRequest("GET", u, nil) + if err != nil { + return nil, err + } + + a := &Apply{} + err = s.client.do(ctx, req, a) + if err != nil { + return nil, err + } + + return a, nil +} + +// Logs retrieves the logs of an apply. +func (s *applies) Logs(ctx context.Context, applyID string) (io.Reader, error) { + if !validStringID(&applyID) { + return nil, errors.New("Invalid value for apply ID") + } + + // Get the apply to make sure it exists. + a, err := s.Read(ctx, applyID) + if err != nil { + return nil, err + } + + // Return an error if the log URL is empty. + if a.LogReadURL == "" { + return nil, fmt.Errorf("Apply %s does not have a log URL", applyID) + } + + u, err := url.Parse(a.LogReadURL) + if err != nil { + return nil, fmt.Errorf("Invalid log URL: %v", err) + } + + done := func() (bool, error) { + a, err := s.Read(ctx, a.ID) + if err != nil { + return false, err + } + + switch a.Status { + case ApplyCanceled, ApplyErrored, ApplyFinished: + return true, nil + default: + return false, nil + } + } + + return &LogReader{ + client: s.client, + ctx: ctx, + done: done, + logURL: u, + }, nil +} diff --git a/vendor/github.com/hashicorp/go-tfe/logreader.go b/vendor/github.com/hashicorp/go-tfe/logreader.go new file mode 100644 index 000000000..00bce1c67 --- /dev/null +++ b/vendor/github.com/hashicorp/go-tfe/logreader.go @@ -0,0 +1,91 @@ +package tfe + +import ( + "context" + "fmt" + "io" + "net/http" + "net/url" + "time" +) + +// LogReader implements io.Reader for streaming logs. +type LogReader struct { + client *Client + ctx context.Context + done func() (bool, error) + logURL *url.URL + offset int64 +} + +func (r *LogReader) Read(l []byte) (int, error) { + if written, err := r.read(l); err != io.ErrNoProgress { + return written, err + } + + // Loop until we can any data, the context is canceled or the + // run is finsished. If we would return right away without any + // data, we could and up causing a io.ErrNoProgress error. + for { + select { + case <-r.ctx.Done(): + return 0, r.ctx.Err() + case <-time.After(500 * time.Millisecond): + if written, err := r.read(l); err != io.ErrNoProgress { + return written, err + } + } + } +} + +func (r *LogReader) read(l []byte) (int, error) { + // Update the query string. + r.logURL.RawQuery = fmt.Sprintf("limit=%d&offset=%d", len(l), r.offset) + + // Create a new request. + req, err := http.NewRequest("GET", r.logURL.String(), nil) + if err != nil { + return 0, err + } + req = req.WithContext(r.ctx) + + // Retrieve the next chunk. + resp, err := r.client.http.Do(req) + if err != nil { + return 0, err + } + defer resp.Body.Close() + + // Basic response checking. + if err := checkResponseCode(resp); err != nil { + return 0, err + } + + // Read the retrieved chunk. + written, err := resp.Body.Read(l) + if err != nil && err != io.EOF { + // Ignore io.EOF errors returned when reading from the response + // body as this indicates the end of the chunk and not the end + // of the logfile. + return written, err + } + + // Check if we need to continue the loop and wait 500 miliseconds + // before checking if there is a new chunk available or that the + // run is finished and we are done reading all chunks. + if written == 0 { + done, err := r.done() + if err != nil { + return 0, err + } + if done { + return 0, io.EOF + } + return 0, io.ErrNoProgress + } + + // Update the offset for the next read. + r.offset += int64(written) + + return written, nil +} diff --git a/vendor/github.com/hashicorp/go-tfe/oauth_client.go b/vendor/github.com/hashicorp/go-tfe/oauth_client.go index 146bf7f9b..be31fd8e3 100644 --- a/vendor/github.com/hashicorp/go-tfe/oauth_client.go +++ b/vendor/github.com/hashicorp/go-tfe/oauth_client.go @@ -17,8 +17,17 @@ var _ OAuthClients = (*oAuthClients)(nil) // TFE API docs: // https://www.terraform.io/docs/enterprise/api/oauth-clients.html type OAuthClients interface { - // Create a VCS connection between an organization and a VCS provider. + // List all the OAuth clients for a given organization. + List(ctx context.Context, organization string, options OAuthClientListOptions) (*OAuthClientList, error) + + // Create an OAuth client to connect an organization and a VCS provider. Create(ctx context.Context, organization string, options OAuthClientCreateOptions) (*OAuthClient, error) + + // Read an OAuth client by its ID. + Read(ctx context.Context, oAuthClientID string) (*OAuthClient, error) + + // Delete an OAuth client by its ID. + Delete(ctx context.Context, oAuthClientID string) error } // oAuthClients implements OAuthClients. @@ -40,6 +49,12 @@ const ( ServiceProviderGitlabEE ServiceProviderType = "gitlab_enterprise_edition" ) +// OAuthClientList represents a list of OAuth clients. +type OAuthClientList struct { + *Pagination + Items []*OAuthClient +} + // OAuthClient represents a connection between an organization and a VCS // provider. type OAuthClient struct { @@ -56,7 +71,34 @@ type OAuthClient struct { // Relations Organization *Organization `jsonapi:"relation,organization"` - OAuthToken []*OAuthToken `jsonapi:"relation,oauth-token"` + OAuthTokens []*OAuthToken `jsonapi:"relation,oauth-tokens"` +} + +// OAuthClientListOptions represents the options for listing +// OAuth clients. +type OAuthClientListOptions struct { + ListOptions +} + +// List all the OAuth clients for a given organization. +func (s *oAuthClients) List(ctx context.Context, organization string, options OAuthClientListOptions) (*OAuthClientList, error) { + if !validStringID(&organization) { + return nil, errors.New("Invalid value for organization") + } + + u := fmt.Sprintf("organizations/%s/oauth-clients", url.QueryEscape(organization)) + req, err := s.client.newRequest("GET", u, &options) + if err != nil { + return nil, err + } + + ocl := &OAuthClientList{} + err = s.client.do(ctx, req, ocl) + if err != nil { + return nil, err + } + + return ocl, nil } // OAuthClientCreateOptions represents the options for creating an OAuth client. @@ -70,11 +112,8 @@ type OAuthClientCreateOptions struct { // The homepage of your VCS provider. HTTPURL *string `jsonapi:"attr,http-url"` - // The key you were given by your VCS provider. - Key *string `jsonapi:"attr,key"` - - // The secret you were given by your VCS provider. - Secret *string `jsonapi:"attr,secret"` + // The token string you were given by your VCS provider. + OAuthToken *string `jsonapi:"attr,oauth-token-string"` // The VCS provider being connected with. ServiceProvider *ServiceProviderType `jsonapi:"attr,service-provider"` @@ -87,11 +126,8 @@ func (o OAuthClientCreateOptions) valid() error { if !validString(o.HTTPURL) { return errors.New("HTTPURL is required") } - if !validString(o.Key) { - return errors.New("Key is required") - } - if !validString(o.Secret) { - return errors.New("Secret is required") + if !validString(o.OAuthToken) { + return errors.New("OAuthToken is required") } if o.ServiceProvider == nil { return errors.New("ServiceProvider is required") @@ -99,7 +135,7 @@ func (o OAuthClientCreateOptions) valid() error { return nil } -// Create a VCS connection between an organization and a VCS provider. +// Create an OAuth client to connect an organization and a VCS provider. func (s *oAuthClients) Create(ctx context.Context, organization string, options OAuthClientCreateOptions) (*OAuthClient, error) { if !validStringID(&organization) { return nil, errors.New("Invalid value for organization") @@ -125,3 +161,39 @@ func (s *oAuthClients) Create(ctx context.Context, organization string, options return oc, nil } + +// Read an OAuth client by its ID. +func (s *oAuthClients) Read(ctx context.Context, oAuthClientID string) (*OAuthClient, error) { + if !validStringID(&oAuthClientID) { + return nil, errors.New("Invalid value for OAuth client ID") + } + + u := fmt.Sprintf("oauth-clients/%s", url.QueryEscape(oAuthClientID)) + req, err := s.client.newRequest("GET", u, nil) + if err != nil { + return nil, err + } + + oc := &OAuthClient{} + err = s.client.do(ctx, req, oc) + if err != nil { + return nil, err + } + + return oc, err +} + +// Delete an OAuth client by its ID. +func (s *oAuthClients) Delete(ctx context.Context, oAuthClientID string) error { + if !validStringID(&oAuthClientID) { + return errors.New("Invalid value for OAuth client ID") + } + + u := fmt.Sprintf("oauth-clients/%s", url.QueryEscape(oAuthClientID)) + req, err := s.client.newRequest("DELETE", u, nil) + if err != nil { + return err + } + + return s.client.do(ctx, req, nil) +} diff --git a/vendor/github.com/hashicorp/go-tfe/oauth_token.go b/vendor/github.com/hashicorp/go-tfe/oauth_token.go index b2b7d42ee..2367a1e3b 100644 --- a/vendor/github.com/hashicorp/go-tfe/oauth_token.go +++ b/vendor/github.com/hashicorp/go-tfe/oauth_token.go @@ -17,8 +17,16 @@ var _ OAuthTokens = (*oAuthTokens)(nil) // TFE API docs: // https://www.terraform.io/docs/enterprise/api/oauth-tokens.html type OAuthTokens interface { - // List all the OAuth Tokens for a given organization. + // List all the OAuth tokens for a given organization. List(ctx context.Context, organization string, options OAuthTokenListOptions) (*OAuthTokenList, error) + // Read a OAuth token by its ID. + Read(ctx context.Context, oAuthTokenID string) (*OAuthToken, error) + + // Update an existing OAuth token. + Update(ctx context.Context, oAuthTokenID string, options OAuthTokenUpdateOptions) (*OAuthToken, error) + + // Delete a OAuth token by its ID. + Delete(ctx context.Context, oAuthTokenID string) error } // oAuthTokens implements OAuthTokens. @@ -71,3 +79,72 @@ func (s *oAuthTokens) List(ctx context.Context, organization string, options OAu return otl, nil } + +// Read an OAuth token by its ID. +func (s *oAuthTokens) Read(ctx context.Context, oAuthTokenID string) (*OAuthToken, error) { + if !validStringID(&oAuthTokenID) { + return nil, errors.New("Invalid value for OAuth token ID") + } + + u := fmt.Sprintf("oauth-tokens/%s", url.QueryEscape(oAuthTokenID)) + req, err := s.client.newRequest("GET", u, nil) + if err != nil { + return nil, err + } + + ot := &OAuthToken{} + err = s.client.do(ctx, req, ot) + if err != nil { + return nil, err + } + + return ot, err +} + +// OAuthTokenUpdateOptions represents the options for updating an OAuth token. +type OAuthTokenUpdateOptions struct { + // For internal use only! + ID string `jsonapi:"primary,oauth-tokens"` + + // A private SSH key to be used for git clone operations. + PrivateSSHKey *string `jsonapi:"attr,ssh-key"` +} + +// Update an existing OAuth token. +func (s *oAuthTokens) Update(ctx context.Context, oAuthTokenID string, options OAuthTokenUpdateOptions) (*OAuthToken, error) { + if !validStringID(&oAuthTokenID) { + return nil, errors.New("Invalid value for OAuth token ID") + } + + // Make sure we don't send a user provided ID. + options.ID = "" + + u := fmt.Sprintf("oauth-tokens/%s", url.QueryEscape(oAuthTokenID)) + req, err := s.client.newRequest("PATCH", u, &options) + if err != nil { + return nil, err + } + + ot := &OAuthToken{} + err = s.client.do(ctx, req, ot) + if err != nil { + return nil, err + } + + return ot, err +} + +// Delete an OAuth token by its ID. +func (s *oAuthTokens) Delete(ctx context.Context, oAuthTokenID string) error { + if !validStringID(&oAuthTokenID) { + return errors.New("Invalid value for OAuth token ID") + } + + u := fmt.Sprintf("oauth-tokens/%s", url.QueryEscape(oAuthTokenID)) + req, err := s.client.newRequest("DELETE", u, nil) + if err != nil { + return err + } + + return s.client.do(ctx, req, nil) +} diff --git a/vendor/github.com/hashicorp/go-tfe/plan.go b/vendor/github.com/hashicorp/go-tfe/plan.go index 72ca5f8e8..9ac989b38 100644 --- a/vendor/github.com/hashicorp/go-tfe/plan.go +++ b/vendor/github.com/hashicorp/go-tfe/plan.go @@ -5,7 +5,6 @@ import ( "errors" "fmt" "io" - "net/http" "net/url" "time" ) @@ -47,23 +46,24 @@ const ( // Plan represents a Terraform Enterprise plan. type Plan struct { - ID string `jsonapi:"primary,plans"` - HasChanges bool `jsonapi:"attr,has-changes"` - LogReadURL string `jsonapi:"attr,log-read-url"` - Status PlanStatus `jsonapi:"attr,status"` - StatusTimestamps *PlanStatusTimestamps `jsonapi:"attr,status-timestamps"` + ID string `jsonapi:"primary,plans"` + HasChanges bool `jsonapi:"attr,has-changes"` + LogReadURL string `jsonapi:"attr,log-read-url"` + ResourceAdditions int `jsonapi:"attr,resource-additions"` + ResourceChanges int `jsonapi:"attr,resource-changes"` + ResourceDestructions int `jsonapi:"attr,resource-destructions"` + Status PlanStatus `jsonapi:"attr,status"` + StatusTimestamps *PlanStatusTimestamps `jsonapi:"attr,status-timestamps"` } // PlanStatusTimestamps holds the timestamps for individual plan statuses. type PlanStatusTimestamps struct { - CanceledAt time.Time `json:"canceled-at"` - CreatedAt time.Time `json:"created-at"` - ErroredAt time.Time `json:"errored-at"` - FinishedAt time.Time `json:"finished-at"` - MFAWaitingAt time.Time `json:"mfa_waiting-at"` - PendingAt time.Time `json:"pending-at"` - QueuedAt time.Time `json:"queued-at"` - RunningAt time.Time `json:"running-at"` + CanceledAt time.Time `json:"canceled-at"` + ErroredAt time.Time `json:"errored-at"` + FinishedAt time.Time `json:"finished-at"` + ForceCanceledAt time.Time `json:"force-canceled-at"` + QueuedAt time.Time `json:"queued-at"` + StartedAt time.Time `json:"started-at"` } // Read a plan by its ID. @@ -109,98 +109,24 @@ func (s *plans) Logs(ctx context.Context, planID string) (io.Reader, error) { return nil, fmt.Errorf("Invalid log URL: %v", err) } + done := func() (bool, error) { + p, err := s.Read(ctx, p.ID) + if err != nil { + return false, err + } + + switch p.Status { + case PlanCanceled, PlanErrored, PlanFinished: + return true, nil + default: + return false, nil + } + } + return &LogReader{ client: s.client, ctx: ctx, + done: done, logURL: u, - plan: p, }, nil } - -// LogReader implements io.Reader for streaming plan logs. -type LogReader struct { - client *Client - ctx context.Context - logURL *url.URL - offset int64 - plan *Plan - reads uint64 -} - -func (r *LogReader) Read(l []byte) (int, error) { - if written, err := r.read(l); err != io.ErrNoProgress { - return written, err - } - - // Loop until we can any data, the context is canceled or the plan - // is finsished running. If we would return right away without any - // data, we could and up causing a io.ErrNoProgress error. - for { - select { - case <-r.ctx.Done(): - return 0, r.ctx.Err() - case <-time.After(500 * time.Millisecond): - if written, err := r.read(l); err != io.ErrNoProgress { - return written, err - } - } - } -} - -func (r *LogReader) read(l []byte) (int, error) { - // Update the query string. - r.logURL.RawQuery = fmt.Sprintf("limit=%d&offset=%d", len(l), r.offset) - - // Create a new request. - req, err := http.NewRequest("GET", r.logURL.String(), nil) - if err != nil { - return 0, err - } - req = req.WithContext(r.ctx) - - // Retrieve the next chunk. - resp, err := r.client.http.Do(req) - if err != nil { - return 0, err - } - defer resp.Body.Close() - - // Basic response checking. - if err := checkResponseCode(resp); err != nil { - return 0, err - } - - // Read the retrieved chunk. - written, err := resp.Body.Read(l) - if err != nil && err != io.EOF { - // Ignore io.EOF errors returned when reading from the response - // body as this indicates the end of the chunk and not the end - // of the logfile. - return written, err - } - - // Check if we need to continue the loop and wait 500 miliseconds - // before checking if there is a new chunk available or that the - // plan is finished and we are done reading all chunks. - if written == 0 { - if r.reads%2 == 0 { - r.plan, err = r.client.Plans.Read(r.ctx, r.plan.ID) - if err != nil { - return 0, err - } - } - - switch r.plan.Status { - case PlanCanceled, PlanErrored, PlanFinished: - return 0, io.EOF - default: - r.reads++ - return 0, io.ErrNoProgress - } - } - - // Update the offset for the next read. - r.offset += int64(written) - - return written, nil -} diff --git a/vendor/github.com/hashicorp/go-tfe/policy_check.go b/vendor/github.com/hashicorp/go-tfe/policy_check.go index e138d2692..6b0d6b2a3 100644 --- a/vendor/github.com/hashicorp/go-tfe/policy_check.go +++ b/vendor/github.com/hashicorp/go-tfe/policy_check.go @@ -1,9 +1,11 @@ package tfe import ( + "bytes" "context" "errors" "fmt" + "io" "net/url" "time" ) @@ -20,8 +22,14 @@ type PolicyChecks interface { // List all policy checks of the given run. List(ctx context.Context, runID string, options PolicyCheckListOptions) (*PolicyCheckList, error) + // Read a policy check by its ID. + Read(ctx context.Context, policyCheckID string) (*PolicyCheck, error) + // Override a soft-mandatory or warning policy. Override(ctx context.Context, policyCheckID string) (*PolicyCheck, error) + + // Logs retrieves the logs of a policy check. + Logs(ctx context.Context, policyCheckID string) (io.Reader, error) } // policyChecks implements PolicyChecks. @@ -64,7 +72,7 @@ type PolicyCheck struct { Actions *PolicyActions `jsonapi:"attr,actions"` Permissions *PolicyPermissions `jsonapi:"attr,permissions"` Result *PolicyResult `jsonapi:"attr,result"` - Scope PolicyScope `jsonapi:"attr,source"` + Scope PolicyScope `jsonapi:"attr,scope"` Status PolicyStatus `jsonapi:"attr,status"` StatusTimestamps *PolicyStatusTimestamps `jsonapi:"attr,status-timestamps"` } @@ -127,6 +135,27 @@ func (s *policyChecks) List(ctx context.Context, runID string, options PolicyChe return pcl, nil } +// Read a policy check by its ID. +func (s *policyChecks) Read(ctx context.Context, policyCheckID string) (*PolicyCheck, error) { + if !validStringID(&policyCheckID) { + return nil, errors.New("Invalid value for policy check ID") + } + + u := fmt.Sprintf("policy-checks/%s", url.QueryEscape(policyCheckID)) + req, err := s.client.newRequest("GET", u, nil) + if err != nil { + return nil, err + } + + pc := &PolicyCheck{} + err = s.client.do(ctx, req, pc) + if err != nil { + return nil, err + } + + return pc, nil +} + // Override a soft-mandatory or warning policy. func (s *policyChecks) Override(ctx context.Context, policyCheckID string) (*PolicyCheck, error) { if !validStringID(&policyCheckID) { @@ -147,3 +176,44 @@ func (s *policyChecks) Override(ctx context.Context, policyCheckID string) (*Pol return pc, nil } + +// Logs retrieves the logs of a policy check. +func (s *policyChecks) Logs(ctx context.Context, policyCheckID string) (io.Reader, error) { + if !validStringID(&policyCheckID) { + return nil, errors.New("Invalid value for policy check ID") + } + + // Loop until the context is canceled or the policy check is finished + // running. The policy check logs are not streamed and so only available + // once the check is finished. + for { + pc, err := s.Read(ctx, policyCheckID) + if err != nil { + return nil, err + } + + switch pc.Status { + case PolicyPending, PolicyQueued: + select { + case <-ctx.Done(): + return nil, ctx.Err() + case <-time.After(500 * time.Millisecond): + continue + } + } + + u := fmt.Sprintf("policy-checks/%s/output", url.QueryEscape(policyCheckID)) + 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 + } +} diff --git a/vendor/github.com/hashicorp/go-tfe/run.go b/vendor/github.com/hashicorp/go-tfe/run.go index 9011a8378..a9918bafe 100644 --- a/vendor/github.com/hashicorp/go-tfe/run.go +++ b/vendor/github.com/hashicorp/go-tfe/run.go @@ -89,15 +89,17 @@ type Run struct { StatusTimestamps *RunStatusTimestamps `jsonapi:"attr,status-timestamps"` // Relations + Apply *Apply `jsonapi:"relation,apply"` ConfigurationVersion *ConfigurationVersion `jsonapi:"relation,configuration-version"` 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"` - IsComfirmable bool `json:"is-comfirmable"` + IsConfirmable bool `json:"is-confirmable"` IsDiscardable bool `json:"is-discardable"` } diff --git a/vendor/github.com/hashicorp/go-tfe/tfe.go b/vendor/github.com/hashicorp/go-tfe/tfe.go index 87eeb57cb..06cede595 100644 --- a/vendor/github.com/hashicorp/go-tfe/tfe.go +++ b/vendor/github.com/hashicorp/go-tfe/tfe.go @@ -58,7 +58,7 @@ func DefaultConfig() *Config { Address: os.Getenv("TFE_ADDRESS"), BasePath: DefaultBasePath, Token: os.Getenv("TFE_TOKEN"), - HTTPClient: cleanhttp.DefaultClient(), + HTTPClient: cleanhttp.DefaultPooledClient(), } // Set the default address if none is given. @@ -77,6 +77,7 @@ type Client struct { http *http.Client userAgent string + Applies Applies ConfigurationVersions ConfigurationVersions OAuthClients OAuthClients OAuthTokens OAuthTokens @@ -142,6 +143,7 @@ func NewClient(cfg *Config) (*Client, error) { } // Create the services. + client.Applies = &applies{client: client} client.ConfigurationVersions = &configurationVersions{client: client} client.OAuthClients = &oAuthClients{client: client} client.OAuthTokens = &oAuthTokens{client: client} diff --git a/vendor/github.com/hashicorp/go-tfe/variable.go b/vendor/github.com/hashicorp/go-tfe/variable.go index 0374cc789..ba28404c9 100644 --- a/vendor/github.com/hashicorp/go-tfe/variable.go +++ b/vendor/github.com/hashicorp/go-tfe/variable.go @@ -21,6 +21,9 @@ type Variables interface { // Create is used to create a new variable. Create(ctx context.Context, options VariableCreateOptions) (*Variable, error) + // Read a variable by its ID. + Read(ctx context.Context, variableID string) (*Variable, error) + // Update values of an existing variable. Update(ctx context.Context, variableID string, options VariableUpdateOptions) (*Variable, error) @@ -161,6 +164,27 @@ func (s *variables) Create(ctx context.Context, options VariableCreateOptions) ( return v, nil } +// Read a variable by its ID. +func (s *variables) Read(ctx context.Context, variableID string) (*Variable, error) { + if !validStringID(&variableID) { + return nil, errors.New("Invalid value for variable ID") + } + + u := fmt.Sprintf("vars/%s", url.QueryEscape(variableID)) + req, err := s.client.newRequest("GET", u, nil) + if err != nil { + return nil, err + } + + v := &Variable{} + err = s.client.do(ctx, req, v) + if err != nil { + return nil, err + } + + return v, err +} + // VariableUpdateOptions represents the options for updating a variable. type VariableUpdateOptions struct { // For internal use only! diff --git a/vendor/vendor.json b/vendor/vendor.json index a356d23b6..5b40b950a 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -1804,10 +1804,10 @@ "revisionTime": "2018-07-12T07:51:27Z" }, { - "checksumSHA1": "Xo/jovk4kg+1xHsdyfTtBhcLkXo=", + "checksumSHA1": "V2A92CHPEiPIsU4Wepl0ukznka8=", "path": "github.com/hashicorp/go-tfe", - "revision": "6781009f2a64d61df9aff58f17427f0ef43abad0", - "revisionTime": "2018-09-08T08:19:18Z" + "revision": "cca0c15746d89219f9732f6c07d267827fef25cd", + "revisionTime": "2018-09-20T19:42:22Z" }, { "checksumSHA1": "85XUnluYJL7F55ptcwdmN8eSOsk=",