diff --git a/backend/remote/backend.go b/backend/remote/backend.go index 59ba777f2..5c00edd2f 100644 --- a/backend/remote/backend.go +++ b/backend/remote/backend.go @@ -336,13 +336,13 @@ func (b *Remote) states() ([]string, error) { } options := tfe.WorkspaceListOptions{} - ws, err := b.client.Workspaces.List(context.Background(), b.organization, options) + wl, err := b.client.Workspaces.List(context.Background(), b.organization, options) if err != nil { return nil, err } var names []string - for _, w := range ws { + for _, w := range wl.Items { if b.workspace != "" && w.Name == b.workspace { names = append(names, backend.DefaultStateName) continue diff --git a/backend/remote/backend_mock.go b/backend/remote/backend_mock.go index e51682eb7..673b5c81c 100644 --- a/backend/remote/backend_mock.go +++ b/backend/remote/backend_mock.go @@ -51,12 +51,21 @@ func newMockConfigurationVersions(client *mockClient) *mockConfigurationVersions } } -func (m *mockConfigurationVersions) List(ctx context.Context, workspaceID string, options tfe.ConfigurationVersionListOptions) ([]*tfe.ConfigurationVersion, error) { - var cvs []*tfe.ConfigurationVersion +func (m *mockConfigurationVersions) List(ctx context.Context, workspaceID string, options tfe.ConfigurationVersionListOptions) (*tfe.ConfigurationVersionList, error) { + cvl := &tfe.ConfigurationVersionList{} for _, cv := range m.configVersions { - cvs = append(cvs, cv) + cvl.Items = append(cvl.Items, cv) } - return cvs, nil + + cvl.Pagination = &tfe.Pagination{ + CurrentPage: 1, + NextPage: 1, + PreviousPage: 1, + TotalPages: 1, + TotalCount: len(cvl.Items), + } + + return cvl, nil } func (m *mockConfigurationVersions) Create(ctx context.Context, workspaceID string, options tfe.ConfigurationVersionCreateOptions) (*tfe.ConfigurationVersion, error) { @@ -105,12 +114,21 @@ func newMockOrganizations(client *mockClient) *mockOrganizations { } } -func (m *mockOrganizations) List(ctx context.Context, options tfe.OrganizationListOptions) ([]*tfe.Organization, error) { - var orgs []*tfe.Organization +func (m *mockOrganizations) List(ctx context.Context, options tfe.OrganizationListOptions) (*tfe.OrganizationList, error) { + orgl := &tfe.OrganizationList{} for _, org := range m.organizations { - orgs = append(orgs, org) + orgl.Items = append(orgl.Items, org) } - return orgs, nil + + orgl.Pagination = &tfe.Pagination{ + CurrentPage: 1, + NextPage: 1, + PreviousPage: 1, + TotalPages: 1, + TotalCount: len(orgl.Items), + } + + return orgl, nil } func (m *mockOrganizations) Create(ctx context.Context, options tfe.OrganizationCreateOptions) (*tfe.Organization, error) { @@ -230,16 +248,26 @@ func newMockRuns(client *mockClient) *mockRuns { } } -func (m *mockRuns) List(ctx context.Context, workspaceID string, options tfe.RunListOptions) ([]*tfe.Run, error) { +func (m *mockRuns) List(ctx context.Context, workspaceID string, options tfe.RunListOptions) (*tfe.RunList, error) { w, ok := m.client.Workspaces.workspaceIDs[workspaceID] if !ok { return nil, tfe.ErrResourceNotFound } - var rs []*tfe.Run + + rl := &tfe.RunList{} for _, r := range m.workspaces[w.ID] { - rs = append(rs, r) + rl.Items = append(rl.Items, r) } - return rs, nil + + rl.Pagination = &tfe.Pagination{ + CurrentPage: 1, + NextPage: 1, + PreviousPage: 1, + TotalPages: 1, + TotalCount: len(rl.Items), + } + + return rl, nil } func (m *mockRuns) Create(ctx context.Context, options tfe.RunCreateOptions) (*tfe.Run, error) { @@ -296,12 +324,21 @@ func newMockStateVersions(client *mockClient) *mockStateVersions { } } -func (m *mockStateVersions) List(ctx context.Context, options tfe.StateVersionListOptions) ([]*tfe.StateVersion, error) { - var svs []*tfe.StateVersion +func (m *mockStateVersions) List(ctx context.Context, options tfe.StateVersionListOptions) (*tfe.StateVersionList, error) { + svl := &tfe.StateVersionList{} for _, sv := range m.stateVersions { - svs = append(svs, sv) + svl.Items = append(svl.Items, sv) } - return svs, nil + + svl.Pagination = &tfe.Pagination{ + CurrentPage: 1, + NextPage: 1, + PreviousPage: 1, + TotalPages: 1, + TotalCount: len(svl.Items), + } + + return svl, nil } func (m *mockStateVersions) Create(ctx context.Context, workspaceID string, options tfe.StateVersionCreateOptions) (*tfe.StateVersion, error) { @@ -375,12 +412,21 @@ func newMockWorkspaces(client *mockClient) *mockWorkspaces { } } -func (m *mockWorkspaces) List(ctx context.Context, organization string, options tfe.WorkspaceListOptions) ([]*tfe.Workspace, error) { - var ws []*tfe.Workspace +func (m *mockWorkspaces) List(ctx context.Context, organization string, options tfe.WorkspaceListOptions) (*tfe.WorkspaceList, error) { + wl := &tfe.WorkspaceList{} for _, w := range m.workspaceIDs { - ws = append(ws, w) + wl.Items = append(wl.Items, w) } - return ws, nil + + wl.Pagination = &tfe.Pagination{ + CurrentPage: 1, + NextPage: 1, + PreviousPage: 1, + TotalPages: 1, + TotalCount: len(wl.Items), + } + + return wl, nil } func (m *mockWorkspaces) Create(ctx context.Context, organization string, options tfe.WorkspaceCreateOptions) (*tfe.Workspace, error) { diff --git a/vendor/github.com/hashicorp/go-tfe/configuration_version.go b/vendor/github.com/hashicorp/go-tfe/configuration_version.go index 97d934719..168c1c6dd 100644 --- a/vendor/github.com/hashicorp/go-tfe/configuration_version.go +++ b/vendor/github.com/hashicorp/go-tfe/configuration_version.go @@ -21,7 +21,7 @@ var _ ConfigurationVersions = (*configurationVersions)(nil) // https://www.terraform.io/docs/enterprise/api/configuration-versions.html type ConfigurationVersions interface { // List returns all configuration versions of a workspace. - List(ctx context.Context, workspaceID string, options ConfigurationVersionListOptions) ([]*ConfigurationVersion, error) + List(ctx context.Context, workspaceID string, options ConfigurationVersionListOptions) (*ConfigurationVersionList, error) // Create is used to create a new configuration version. The created // configuration version will be usable once data is uploaded to it. @@ -63,6 +63,12 @@ const ( ConfigurationSourceTerraform ConfigurationSource = "terraform" ) +// ConfigurationVersionList represents a list of configuration versions. +type ConfigurationVersionList struct { + *Pagination + Items []*ConfigurationVersion +} + // ConfigurationVersion is a representation of an uploaded or ingressed // Terraform configuration in TFE. A workspace must have at least one // configuration version before any runs may be queued on it. @@ -93,7 +99,7 @@ type ConfigurationVersionListOptions struct { } // List returns all configuration versions of a workspace. -func (s *configurationVersions) List(ctx context.Context, workspaceID string, options ConfigurationVersionListOptions) ([]*ConfigurationVersion, error) { +func (s *configurationVersions) List(ctx context.Context, workspaceID string, options ConfigurationVersionListOptions) (*ConfigurationVersionList, error) { if !validStringID(&workspaceID) { return nil, errors.New("Invalid value for workspace ID") } @@ -104,13 +110,13 @@ func (s *configurationVersions) List(ctx context.Context, workspaceID string, op return nil, err } - var cvs []*ConfigurationVersion - err = s.client.do(ctx, req, &cvs) + cvl := &ConfigurationVersionList{} + err = s.client.do(ctx, req, cvl) if err != nil { return nil, err } - return cvs, nil + return cvl, nil } // ConfigurationVersionCreateOptions represents the options for creating a diff --git a/vendor/github.com/hashicorp/go-tfe/oauth_token.go b/vendor/github.com/hashicorp/go-tfe/oauth_token.go index c247338cb..b2b7d42ee 100644 --- a/vendor/github.com/hashicorp/go-tfe/oauth_token.go +++ b/vendor/github.com/hashicorp/go-tfe/oauth_token.go @@ -18,7 +18,7 @@ var _ OAuthTokens = (*oAuthTokens)(nil) // https://www.terraform.io/docs/enterprise/api/oauth-tokens.html type OAuthTokens interface { // List all the OAuth Tokens for a given organization. - List(ctx context.Context, organization string) ([]*OAuthToken, error) + List(ctx context.Context, organization string, options OAuthTokenListOptions) (*OAuthTokenList, error) } // oAuthTokens implements OAuthTokens. @@ -26,6 +26,12 @@ type oAuthTokens struct { client *Client } +// OAuthTokenList represents a list of OAuth tokens. +type OAuthTokenList struct { + *Pagination + Items []*OAuthToken +} + // OAuthToken represents a VCS configuration including the associated // OAuth token type OAuthToken struct { @@ -39,23 +45,29 @@ type OAuthToken struct { OAuthClient *OAuthClient `jsonapi:"relation,oauth-client"` } -// List all the OAuth Tokens for a given organization. -func (s *oAuthTokens) List(ctx context.Context, organization string) ([]*OAuthToken, error) { +// OAuthTokenListOptions represents the options for listing +// OAuth tokens. +type OAuthTokenListOptions struct { + ListOptions +} + +// List all the OAuth tokens for a given organization. +func (s *oAuthTokens) List(ctx context.Context, organization string, options OAuthTokenListOptions) (*OAuthTokenList, error) { if !validStringID(&organization) { return nil, errors.New("Invalid value for organization") } u := fmt.Sprintf("organizations/%s/oauth-tokens", url.QueryEscape(organization)) - req, err := s.client.newRequest("GET", u, nil) + req, err := s.client.newRequest("GET", u, &options) if err != nil { return nil, err } - var ots []*OAuthToken - err = s.client.do(ctx, req, &ots) + otl := &OAuthTokenList{} + err = s.client.do(ctx, req, otl) if err != nil { return nil, err } - return ots, nil + return otl, nil } diff --git a/vendor/github.com/hashicorp/go-tfe/organization.go b/vendor/github.com/hashicorp/go-tfe/organization.go index 69b6f2441..69200df38 100644 --- a/vendor/github.com/hashicorp/go-tfe/organization.go +++ b/vendor/github.com/hashicorp/go-tfe/organization.go @@ -18,7 +18,7 @@ var _ Organizations = (*organizations)(nil) // https://www.terraform.io/docs/enterprise/api/organizations.html type Organizations interface { // List all the organizations visible to the current user. - List(ctx context.Context, options OrganizationListOptions) ([]*Organization, error) + List(ctx context.Context, options OrganizationListOptions) (*OrganizationList, error) // Create a new organization with the given options. Create(ctx context.Context, options OrganizationCreateOptions) (*Organization, error) @@ -58,6 +58,12 @@ const ( EnterprisePlanTrial EnterprisePlanType = "trial" ) +// OrganizationList represents a list of organizations. +type OrganizationList struct { + *Pagination + Items []*Organization +} + // Organization represents a Terraform Enterprise organization. type Organization struct { Name string `jsonapi:"primary,organizations"` @@ -93,19 +99,19 @@ type OrganizationListOptions struct { } // List all the organizations visible to the current user. -func (s *organizations) List(ctx context.Context, options OrganizationListOptions) ([]*Organization, error) { +func (s *organizations) List(ctx context.Context, options OrganizationListOptions) (*OrganizationList, error) { req, err := s.client.newRequest("GET", "organizations", &options) if err != nil { return nil, err } - var orgs []*Organization - err = s.client.do(ctx, req, &orgs) + orgl := &OrganizationList{} + err = s.client.do(ctx, req, orgl) if err != nil { return nil, err } - return orgs, nil + return orgl, nil } // OrganizationCreateOptions represents the options for creating an organization. diff --git a/vendor/github.com/hashicorp/go-tfe/organization_token.go b/vendor/github.com/hashicorp/go-tfe/organization_token.go index 8d32b01ca..33368da0b 100644 --- a/vendor/github.com/hashicorp/go-tfe/organization_token.go +++ b/vendor/github.com/hashicorp/go-tfe/organization_token.go @@ -20,6 +20,9 @@ type OrganizationTokens interface { // Generate a new organization token, replacing any existing token. Generate(ctx context.Context, organization string) (*OrganizationToken, error) + // Read an organization token. + Read(ctx context.Context, organization string) (*OrganizationToken, error) + // Delete an organization token. Delete(ctx context.Context, organization string) error } @@ -59,6 +62,27 @@ func (s *organizationTokens) Generate(ctx context.Context, organization string) return ot, err } +// Read an organization token. +func (s *organizationTokens) Read(ctx context.Context, organization string) (*OrganizationToken, error) { + if !validStringID(&organization) { + return nil, errors.New("Invalid value for organization") + } + + u := fmt.Sprintf("organizations/%s/authentication-token", url.QueryEscape(organization)) + req, err := s.client.newRequest("GET", u, nil) + if err != nil { + return nil, err + } + + ot := &OrganizationToken{} + err = s.client.do(ctx, req, ot) + if err != nil { + return nil, err + } + + return ot, err +} + // Delete an organization token. func (s *organizationTokens) Delete(ctx context.Context, organization string) error { if !validStringID(&organization) { diff --git a/vendor/github.com/hashicorp/go-tfe/plan.go b/vendor/github.com/hashicorp/go-tfe/plan.go index f50be213f..72ca5f8e8 100644 --- a/vendor/github.com/hashicorp/go-tfe/plan.go +++ b/vendor/github.com/hashicorp/go-tfe/plan.go @@ -170,10 +170,19 @@ func (r *LogReader) read(l []byte) (int, error) { 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 resp.ContentLength == 0 { + if written == 0 { if r.reads%2 == 0 { r.plan, err = r.client.Plans.Read(r.ctx, r.plan.ID) if err != nil { @@ -190,17 +199,8 @@ func (r *LogReader) read(l []byte) (int, error) { } } - // Read the retrieved chunk. - written, err := resp.Body.Read(l) - if 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. - err = nil - } - // Update the offset for the next read. r.offset += int64(written) - return written, err + return written, nil } diff --git a/vendor/github.com/hashicorp/go-tfe/policy.go b/vendor/github.com/hashicorp/go-tfe/policy.go index 70a96b848..80926af37 100644 --- a/vendor/github.com/hashicorp/go-tfe/policy.go +++ b/vendor/github.com/hashicorp/go-tfe/policy.go @@ -1,6 +1,7 @@ package tfe import ( + "bytes" "context" "errors" "fmt" @@ -17,7 +18,7 @@ var _ Policies = (*policies)(nil) // TFE API docs: https://www.terraform.io/docs/enterprise/api/policies.html type Policies interface { // List all the policies for a given organization - List(ctx context.Context, organization string, options PolicyListOptions) ([]*Policy, error) + List(ctx context.Context, organization string, options PolicyListOptions) (*PolicyList, error) // Create a policy and associate it with an organization. Create(ctx context.Context, organization string, options PolicyCreateOptions) (*Policy, error) @@ -25,14 +26,17 @@ type Policies interface { // Read a policy by its ID. Read(ctx context.Context, policyID string) (*Policy, error) - // Upload the policy content of the policy. - Upload(ctx context.Context, policyID string, content []byte) error - // Update an existing policy. Update(ctx context.Context, policyID string, options PolicyUpdateOptions) (*Policy, error) // Delete a policy by its ID. Delete(ctx context.Context, policyID string) error + + // Upload the policy content of the policy. + Upload(ctx context.Context, policyID string, content []byte) error + + // Upload the policy content of the policy. + Download(ctx context.Context, policyID string) ([]byte, error) } // policies implements Policies. @@ -50,6 +54,12 @@ const ( EnforcementSoft EnforcementLevel = "soft-mandatory" ) +// PolicyList represents a list of policies.. +type PolicyList struct { + *Pagination + Items []*Policy +} + // Policy represents a Terraform Enterprise policy. type Policy struct { ID string `jsonapi:"primary,policies"` @@ -70,7 +80,7 @@ type PolicyListOptions struct { } // List all the policies for a given organization -func (s *policies) List(ctx context.Context, organization string, options PolicyListOptions) ([]*Policy, error) { +func (s *policies) List(ctx context.Context, organization string, options PolicyListOptions) (*PolicyList, error) { if !validStringID(&organization) { return nil, errors.New("Invalid value for organization") } @@ -81,13 +91,13 @@ func (s *policies) List(ctx context.Context, organization string, options Policy return nil, err } - var ps []*Policy - err = s.client.do(ctx, req, &ps) + pl := &PolicyList{} + err = s.client.do(ctx, req, pl) if err != nil { return nil, err } - return ps, nil + return pl, nil } // PolicyCreateOptions represents the options for creating a new policy. @@ -177,21 +187,6 @@ func (s *policies) Read(ctx context.Context, policyID string) (*Policy, error) { return p, err } -// Upload the policy content of the policy. -func (s *policies) Upload(ctx context.Context, policyID string, content []byte) error { - if !validStringID(&policyID) { - return errors.New("Invalid value for policy ID") - } - - u := fmt.Sprintf("policies/%s/upload", url.QueryEscape(policyID)) - req, err := s.client.newRequest("PUT", u, content) - if err != nil { - return err - } - - return s.client.do(ctx, req, nil) -} - // PolicyUpdateOptions represents the options for updating a policy. type PolicyUpdateOptions struct { // For internal use only! @@ -249,3 +244,39 @@ func (s *policies) Delete(ctx context.Context, policyID string) error { return s.client.do(ctx, req, nil) } + +// Upload the policy content of the policy. +func (s *policies) Upload(ctx context.Context, policyID string, content []byte) error { + if !validStringID(&policyID) { + return errors.New("Invalid value for policy ID") + } + + u := fmt.Sprintf("policies/%s/upload", url.QueryEscape(policyID)) + req, err := s.client.newRequest("PUT", u, content) + if err != nil { + return err + } + + return s.client.do(ctx, req, nil) +} + +// Download the policy content of the policy. +func (s *policies) Download(ctx context.Context, policyID string) ([]byte, error) { + if !validStringID(&policyID) { + return nil, errors.New("Invalid value for policy ID") + } + + u := fmt.Sprintf("policies/%s/download", url.QueryEscape(policyID)) + 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 +} diff --git a/vendor/github.com/hashicorp/go-tfe/policy_check.go b/vendor/github.com/hashicorp/go-tfe/policy_check.go index ef01a1872..e138d2692 100644 --- a/vendor/github.com/hashicorp/go-tfe/policy_check.go +++ b/vendor/github.com/hashicorp/go-tfe/policy_check.go @@ -18,7 +18,7 @@ var _ PolicyChecks = (*policyChecks)(nil) // https://www.terraform.io/docs/enterprise/api/policy-checks.html type PolicyChecks interface { // List all policy checks of the given run. - List(ctx context.Context, runID string, options PolicyCheckListOptions) ([]*PolicyCheck, error) + List(ctx context.Context, runID string, options PolicyCheckListOptions) (*PolicyCheckList, error) // Override a soft-mandatory or warning policy. Override(ctx context.Context, policyCheckID string) (*PolicyCheck, error) @@ -52,6 +52,12 @@ const ( PolicySoftFailed PolicyStatus = "soft_failed" ) +// PolicyCheckList represents a list of policy checks. +type PolicyCheckList struct { + *Pagination + Items []*PolicyCheck +} + // PolicyCheck represents a Terraform Enterprise policy check.. type PolicyCheck struct { ID string `jsonapi:"primary,policy-checks"` @@ -101,7 +107,7 @@ type PolicyCheckListOptions struct { } // List all policy checks of the given run. -func (s *policyChecks) List(ctx context.Context, runID string, options PolicyCheckListOptions) ([]*PolicyCheck, error) { +func (s *policyChecks) List(ctx context.Context, runID string, options PolicyCheckListOptions) (*PolicyCheckList, error) { if !validStringID(&runID) { return nil, errors.New("Invalid value for run ID") } @@ -112,13 +118,13 @@ func (s *policyChecks) List(ctx context.Context, runID string, options PolicyChe return nil, err } - var pcs []*PolicyCheck - err = s.client.do(ctx, req, &pcs) + pcl := &PolicyCheckList{} + err = s.client.do(ctx, req, pcl) if err != nil { return nil, err } - return pcs, nil + return pcl, nil } // Override a soft-mandatory or warning policy. diff --git a/vendor/github.com/hashicorp/go-tfe/run.go b/vendor/github.com/hashicorp/go-tfe/run.go index c5a4ab9f8..9011a8378 100644 --- a/vendor/github.com/hashicorp/go-tfe/run.go +++ b/vendor/github.com/hashicorp/go-tfe/run.go @@ -17,7 +17,7 @@ var _ Runs = (*runs)(nil) // 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) ([]*Run, error) + 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) @@ -69,6 +69,12 @@ const ( 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"` @@ -117,7 +123,7 @@ type RunListOptions struct { } // List all the runs of the given workspace. -func (s *runs) List(ctx context.Context, workspaceID string, options RunListOptions) ([]*Run, error) { +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") } @@ -128,13 +134,13 @@ func (s *runs) List(ctx context.Context, workspaceID string, options RunListOpti return nil, err } - var rs []*Run - err = s.client.do(ctx, req, &rs) + rl := &RunList{} + err = s.client.do(ctx, req, rl) if err != nil { return nil, err } - return rs, nil + return rl, nil } // RunCreateOptions represents the options for creating a new run. diff --git a/vendor/github.com/hashicorp/go-tfe/ssh_key.go b/vendor/github.com/hashicorp/go-tfe/ssh_key.go index 7f8c93032..b76a170db 100644 --- a/vendor/github.com/hashicorp/go-tfe/ssh_key.go +++ b/vendor/github.com/hashicorp/go-tfe/ssh_key.go @@ -17,7 +17,7 @@ var _ SSHKeys = (*sshKeys)(nil) // https://www.terraform.io/docs/enterprise/api/ssh-keys.html type SSHKeys interface { // List all the SSH keys for a given organization - List(ctx context.Context, organization string, options SSHKeyListOptions) ([]*SSHKey, error) + List(ctx context.Context, organization string, options SSHKeyListOptions) (*SSHKeyList, error) // Create an SSH key and associate it with an organization. Create(ctx context.Context, organization string, options SSHKeyCreateOptions) (*SSHKey, error) @@ -37,6 +37,12 @@ type sshKeys struct { client *Client } +// SSHKeyList represents a list of SSH keys. +type SSHKeyList struct { + *Pagination + Items []*SSHKey +} + // SSHKey represents a SSH key. type SSHKey struct { ID string `jsonapi:"primary,ssh-keys"` @@ -49,7 +55,7 @@ type SSHKeyListOptions struct { } // List all the SSH keys for a given organization -func (s *sshKeys) List(ctx context.Context, organization string, options SSHKeyListOptions) ([]*SSHKey, error) { +func (s *sshKeys) List(ctx context.Context, organization string, options SSHKeyListOptions) (*SSHKeyList, error) { if !validStringID(&organization) { return nil, errors.New("Invalid value for organization") } @@ -60,13 +66,13 @@ func (s *sshKeys) List(ctx context.Context, organization string, options SSHKeyL return nil, err } - var ks []*SSHKey - err = s.client.do(ctx, req, &ks) + kl := &SSHKeyList{} + err = s.client.do(ctx, req, kl) if err != nil { return nil, err } - return ks, nil + return kl, nil } // SSHKeyCreateOptions represents the options for creating an SSH key. diff --git a/vendor/github.com/hashicorp/go-tfe/state_version.go b/vendor/github.com/hashicorp/go-tfe/state_version.go index de6e4c537..89bcfda1c 100644 --- a/vendor/github.com/hashicorp/go-tfe/state_version.go +++ b/vendor/github.com/hashicorp/go-tfe/state_version.go @@ -19,7 +19,7 @@ var _ StateVersions = (*stateVersions)(nil) // https://www.terraform.io/docs/enterprise/api/state-versions.html type StateVersions interface { // List all the state versions for a given workspace. - List(ctx context.Context, options StateVersionListOptions) ([]*StateVersion, error) + List(ctx context.Context, options StateVersionListOptions) (*StateVersionList, error) // Create a new state version for the given workspace. Create(ctx context.Context, workspaceID string, options StateVersionCreateOptions) (*StateVersion, error) @@ -39,6 +39,12 @@ type stateVersions struct { client *Client } +// StateVersionList represents a list of state versions. +type StateVersionList struct { + *Pagination + Items []*StateVersion +} + // StateVersion represents a Terraform Enterprise state version. type StateVersion struct { ID string `jsonapi:"primary,state-versions"` @@ -70,7 +76,7 @@ func (o StateVersionListOptions) valid() error { } // List all the state versions for a given workspace. -func (s *stateVersions) List(ctx context.Context, options StateVersionListOptions) ([]*StateVersion, error) { +func (s *stateVersions) List(ctx context.Context, options StateVersionListOptions) (*StateVersionList, error) { if err := options.valid(); err != nil { return nil, err } @@ -80,13 +86,13 @@ func (s *stateVersions) List(ctx context.Context, options StateVersionListOption return nil, err } - var svs []*StateVersion - err = s.client.do(ctx, req, &svs) + svl := &StateVersionList{} + err = s.client.do(ctx, req, svl) if err != nil { return nil, err } - return svs, nil + return svl, nil } // StateVersionCreateOptions represents the options for creating a state version. @@ -105,6 +111,9 @@ type StateVersionCreateOptions struct { // The base64 encoded state. State *string `jsonapi:"attr,state"` + + // Specifies the run to associate the state with. + Run *Run `jsonapi:"relation,run,omitempty"` } func (o StateVersionCreateOptions) valid() error { diff --git a/vendor/github.com/hashicorp/go-tfe/team.go b/vendor/github.com/hashicorp/go-tfe/team.go index 8f82e7cb0..e6a69c3d2 100644 --- a/vendor/github.com/hashicorp/go-tfe/team.go +++ b/vendor/github.com/hashicorp/go-tfe/team.go @@ -16,7 +16,7 @@ var _ Teams = (*teams)(nil) // TFE API docs: https://www.terraform.io/docs/enterprise/api/teams.html type Teams interface { // List all the teams of the given organization. - List(ctx context.Context, organization string, options TeamListOptions) ([]*Team, error) + List(ctx context.Context, organization string, options TeamListOptions) (*TeamList, error) // Create a new team with the given options. Create(ctx context.Context, organization string, options TeamCreateOptions) (*Team, error) @@ -33,6 +33,12 @@ type teams struct { client *Client } +// TeamList represents a list of teams. +type TeamList struct { + *Pagination + Items []*Team +} + // Team represents a Terraform Enterprise team. type Team struct { ID string `jsonapi:"primary,teams"` @@ -41,7 +47,7 @@ type Team struct { UserCount int `jsonapi:"attr,users-count"` // Relations - //User []*User `jsonapi:"relation,users"` + Users []*User `jsonapi:"relation,users"` } // TeamPermissions represents the team permissions. @@ -56,7 +62,7 @@ type TeamListOptions struct { } // List all the teams of the given organization. -func (s *teams) List(ctx context.Context, organization string, options TeamListOptions) ([]*Team, error) { +func (s *teams) List(ctx context.Context, organization string, options TeamListOptions) (*TeamList, error) { if !validStringID(&organization) { return nil, errors.New("Invalid value for organization") } @@ -67,13 +73,13 @@ func (s *teams) List(ctx context.Context, organization string, options TeamListO return nil, err } - var ts []*Team - err = s.client.do(ctx, req, &ts) + tl := &TeamList{} + err = s.client.do(ctx, req, tl) if err != nil { return nil, err } - return ts, nil + return tl, nil } // TeamCreateOptions represents the options for creating a team. diff --git a/vendor/github.com/hashicorp/go-tfe/team_access.go b/vendor/github.com/hashicorp/go-tfe/team_access.go index 9c3b4b835..33abc3225 100644 --- a/vendor/github.com/hashicorp/go-tfe/team_access.go +++ b/vendor/github.com/hashicorp/go-tfe/team_access.go @@ -17,7 +17,7 @@ var _ TeamAccesses = (*teamAccesses)(nil) // https://www.terraform.io/docs/enterprise/api/team-access.html type TeamAccesses interface { // List all the team accesses for a given workspace. - List(ctx context.Context, options TeamAccessListOptions) ([]*TeamAccess, error) + List(ctx context.Context, options TeamAccessListOptions) (*TeamAccessList, error) // Add team access for a workspace. Add(ctx context.Context, options TeamAccessAddOptions) (*TeamAccess, error) @@ -34,20 +34,26 @@ type teamAccesses struct { client *Client } -// TeamAccessType represents a team access type. -type TeamAccessType string +// AccessType represents a team access type. +type AccessType string // List all available team access types. const ( - TeamAccessAdmin TeamAccessType = "admin" - TeamAccessRead TeamAccessType = "read" - TeamAccessWrite TeamAccessType = "write" + AccessAdmin AccessType = "admin" + AccessRead AccessType = "read" + AccessWrite AccessType = "write" ) +// TeamAccessList represents a list of team accesses. +type TeamAccessList struct { + *Pagination + Items []*TeamAccess +} + // TeamAccess represents the workspace access for a team. type TeamAccess struct { - ID string `jsonapi:"primary,team-workspaces"` - Access TeamAccessType `jsonapi:"attr,access"` + ID string `jsonapi:"primary,team-workspaces"` + Access AccessType `jsonapi:"attr,access"` // Relations Team *Team `jsonapi:"relation,team"` @@ -71,7 +77,7 @@ func (o TeamAccessListOptions) valid() error { } // List all the team accesses for a given workspace. -func (s *teamAccesses) List(ctx context.Context, options TeamAccessListOptions) ([]*TeamAccess, error) { +func (s *teamAccesses) List(ctx context.Context, options TeamAccessListOptions) (*TeamAccessList, error) { if err := options.valid(); err != nil { return nil, err } @@ -81,13 +87,13 @@ func (s *teamAccesses) List(ctx context.Context, options TeamAccessListOptions) return nil, err } - var tas []*TeamAccess - err = s.client.do(ctx, req, &tas) + tal := &TeamAccessList{} + err = s.client.do(ctx, req, tal) if err != nil { return nil, err } - return tas, nil + return tal, nil } // TeamAccessAddOptions represents the options for adding team access. @@ -96,7 +102,7 @@ type TeamAccessAddOptions struct { ID string `jsonapi:"primary,team-workspaces"` // The type of access to grant. - Access *TeamAccessType `jsonapi:"attr,access"` + Access *AccessType `jsonapi:"attr,access"` // The team to add to the workspace Team *Team `jsonapi:"relation,team"` diff --git a/vendor/github.com/hashicorp/go-tfe/team_member.go b/vendor/github.com/hashicorp/go-tfe/team_member.go index 5182e5b8f..297d58a6b 100644 --- a/vendor/github.com/hashicorp/go-tfe/team_member.go +++ b/vendor/github.com/hashicorp/go-tfe/team_member.go @@ -16,6 +16,9 @@ var _ TeamMembers = (*teamMembers)(nil) // TFE API docs: // https://www.terraform.io/docs/enterprise/api/team-members.html type TeamMembers interface { + // List all members of a team. + List(ctx context.Context, teamID string) ([]*User, error) + // Add multiple users to a team. Add(ctx context.Context, teamID string, options TeamMemberAddOptions) error @@ -32,6 +35,33 @@ type teamMember struct { Username string `jsonapi:"primary,users"` } +// List all members of a team. +func (s *teamMembers) List(ctx context.Context, teamID string) ([]*User, error) { + if !validStringID(&teamID) { + return nil, errors.New("Invalid value for team ID") + } + + options := struct { + Include string `url:"include"` + }{ + Include: "users", + } + + u := fmt.Sprintf("teams/%s", url.QueryEscape(teamID)) + req, err := s.client.newRequest("GET", u, options) + if err != nil { + return nil, err + } + + t := &Team{} + err = s.client.do(ctx, req, t) + if err != nil { + return nil, err + } + + return t.Users, nil +} + // TeamMemberAddOptions represents the options for adding team members. type TeamMemberAddOptions struct { Usernames []string diff --git a/vendor/github.com/hashicorp/go-tfe/team_token.go b/vendor/github.com/hashicorp/go-tfe/team_token.go index 105dd7295..baaf75789 100644 --- a/vendor/github.com/hashicorp/go-tfe/team_token.go +++ b/vendor/github.com/hashicorp/go-tfe/team_token.go @@ -20,6 +20,9 @@ type TeamTokens interface { // Generate a new team token, replacing any existing token. Generate(ctx context.Context, teamID string) (*TeamToken, error) + // Read a team token by its ID. + Read(ctx context.Context, teamID string) (*TeamToken, error) + // Delete a team token by its ID. Delete(ctx context.Context, teamID string) error } @@ -59,6 +62,27 @@ func (s *teamTokens) Generate(ctx context.Context, teamID string) (*TeamToken, e return tt, err } +// Read a team token by its ID. +func (s *teamTokens) Read(ctx context.Context, teamID string) (*TeamToken, error) { + if !validStringID(&teamID) { + return nil, errors.New("Invalid value for team ID") + } + + u := fmt.Sprintf("teams/%s/authentication-token", url.QueryEscape(teamID)) + req, err := s.client.newRequest("GET", u, nil) + if err != nil { + return nil, err + } + + tt := &TeamToken{} + err = s.client.do(ctx, req, tt) + if err != nil { + return nil, err + } + + return tt, err +} + // Delete a team token by its ID. func (s *teamTokens) Delete(ctx context.Context, teamID string) error { if !validStringID(&teamID) { diff --git a/vendor/github.com/hashicorp/go-tfe/tfe.go b/vendor/github.com/hashicorp/go-tfe/tfe.go index b783aefd5..87eeb57cb 100644 --- a/vendor/github.com/hashicorp/go-tfe/tfe.go +++ b/vendor/github.com/hashicorp/go-tfe/tfe.go @@ -174,6 +174,15 @@ type ListOptions struct { PageSize int `url:"page[size],omitempty"` } +// Pagination is used to return the pagination details of an API request. +type Pagination struct { + CurrentPage int `json:"current-page"` + PreviousPage int `json:"prev-page"` + NextPage int `json:"next-page"` + TotalPages int `json:"total-pages"` + TotalCount int `json:"total-count"` +} + // newRequest creates an API request. A relative URL path can be provided in // path, in which case it is resolved relative to the apiVersionPath of the // Client. Relative URL paths should always be specified without a preceding @@ -208,7 +217,7 @@ func (c *Client) newRequest(method, path string, v interface{}) (*http.Request, } u.RawQuery = q.Encode() } - case "PATCH", "POST": + case "DELETE", "PATCH", "POST": req.Header.Set("Accept", "application/vnd.api+json") req.Header.Set("Content-Type", "application/vnd.api+json") @@ -245,11 +254,13 @@ func (c *Client) newRequest(method, path string, v interface{}) (*http.Request, return req, nil } -// do sends an API request and returns the API response. The API response is -// JSONAPI decoded and stored in the value pointed to by v, or returned as an -// error if an API error has occurred. +// do sends an API request and returns the API response. The API response +// is JSONAPI decoded and the document's primary data is stored in the value +// pointed to by v, or returned as an error if an API error has occurred. + // If v implements the io.Writer interface, the raw response body will be // written to v, without attempting to first decode it. +// // The provided ctx must be non-nil. If it is canceled or times out, ctx.Err() // will be returned. func (c *Client) do(ctx context.Context, req *http.Request, v interface{}) error { @@ -286,22 +297,41 @@ func (c *Client) do(ctx context.Context, req *http.Request, v interface{}) error return err } - // Get the value of v so we can test if it's a slice. + // Get the value of v so we can test if it's a struct. dst := reflect.Indirect(reflect.ValueOf(v)) - // Unmarshal a single value if v isn't a slice. - if dst.Type().Kind() != reflect.Slice { + // Return an error if v is not a struct or an io.Writer. + if dst.Kind() != reflect.Struct { + return fmt.Errorf("v must be a struct or an io.Writer") + } + + // Try to get the Items and Pagination struct fields. + items := dst.FieldByName("Items") + pagination := dst.FieldByName("Pagination") + + // Unmarshal a single value if v does not contain the + // Items and Pagination struct fields. + if !items.IsValid() || !pagination.IsValid() { return jsonapi.UnmarshalPayload(resp.Body, v) } - // Unmarshal as a list of values if v is a slice. - raw, err := jsonapi.UnmarshalManyPayload(resp.Body, dst.Type().Elem()) + // Return an error if v.Items is not a slice. + if items.Type().Kind() != reflect.Slice { + return fmt.Errorf("v.Items must be a slice") + } + + // Create a temporary buffer and copy all the read data into it. + body := bytes.NewBuffer(nil) + reader := io.TeeReader(resp.Body, body) + + // Unmarshal as a list of values as v.Items is a slice. + raw, err := jsonapi.UnmarshalManyPayload(reader, items.Type().Elem()) if err != nil { return err } // Make a new slice to hold the results. - sliceType := reflect.SliceOf(dst.Type().Elem()) + sliceType := reflect.SliceOf(items.Type().Elem()) result := reflect.MakeSlice(sliceType, 0, len(raw)) // Add all of the results to the new slice. @@ -310,11 +340,36 @@ func (c *Client) do(ctx context.Context, req *http.Request, v interface{}) error } // Pointer-swap the result. - dst.Set(result) + items.Set(result) + + // As we are getting a list of values, we need to decode + // the pagination details out of the response body. + p, err := parsePagination(body) + if err != nil { + return err + } + + // Pointer-swap the decoded pagination details. + pagination.Set(reflect.ValueOf(p)) return nil } +func parsePagination(body io.Reader) (*Pagination, error) { + var raw struct { + Meta struct { + Pagination Pagination `json:"pagination"` + } `json:"meta"` + } + + // JSON decode the raw response. + if err := json.NewDecoder(body).Decode(&raw); err != nil { + return &Pagination{}, err + } + + return &raw.Meta.Pagination, nil +} + // checkResponseCode can be used to check the status code of an HTTP request. func checkResponseCode(r *http.Response) error { if r.StatusCode >= 200 && r.StatusCode <= 299 { diff --git a/vendor/github.com/hashicorp/go-tfe/type_helpers.go b/vendor/github.com/hashicorp/go-tfe/type_helpers.go index 3b2a95d42..30df01e49 100644 --- a/vendor/github.com/hashicorp/go-tfe/type_helpers.go +++ b/vendor/github.com/hashicorp/go-tfe/type_helpers.go @@ -1,7 +1,7 @@ package tfe // Access returns a pointer to the given team access type. -func Access(v TeamAccessType) *TeamAccessType { +func Access(v AccessType) *AccessType { return &v } @@ -25,6 +25,11 @@ func EnforcementMode(v EnforcementLevel) *EnforcementLevel { return &v } +// Int returns a pointer to the given int. +func Int(v int) *int { + return &v +} + // Int64 returns a pointer to the given int64. func Int64(v int64) *int64 { return &v diff --git a/vendor/github.com/hashicorp/go-tfe/variable.go b/vendor/github.com/hashicorp/go-tfe/variable.go index ff7101f1a..0374cc789 100644 --- a/vendor/github.com/hashicorp/go-tfe/variable.go +++ b/vendor/github.com/hashicorp/go-tfe/variable.go @@ -16,7 +16,7 @@ var _ Variables = (*variables)(nil) // TFE API docs: https://www.terraform.io/docs/enterprise/api/variables.html type Variables interface { // List all the variables associated with the given workspace. - List(ctx context.Context, options VariableListOptions) ([]*Variable, error) + List(ctx context.Context, options VariableListOptions) (*VariableList, error) // Create is used to create a new variable. Create(ctx context.Context, options VariableCreateOptions) (*Variable, error) @@ -42,6 +42,12 @@ const ( CategoryTerraform CategoryType = "terraform" ) +// VariableList represents a list of variables. +type VariableList struct { + *Pagination + Items []*Variable +} + // Variable represents a Terraform Enterprise variable. type Variable struct { ID string `jsonapi:"primary,vars"` @@ -73,7 +79,7 @@ func (o VariableListOptions) valid() error { } // List all the variables associated with the given workspace. -func (s *variables) List(ctx context.Context, options VariableListOptions) ([]*Variable, error) { +func (s *variables) List(ctx context.Context, options VariableListOptions) (*VariableList, error) { if err := options.valid(); err != nil { return nil, err } @@ -83,13 +89,13 @@ func (s *variables) List(ctx context.Context, options VariableListOptions) ([]*V return nil, err } - var vs []*Variable - err = s.client.do(ctx, req, &vs) + vl := &VariableList{} + err = s.client.do(ctx, req, vl) if err != nil { return nil, err } - return vs, nil + return vl, nil } // VariableCreateOptions represents the options for creating a new variable. @@ -166,9 +172,6 @@ type VariableUpdateOptions struct { // The value of the variable. Value *string `jsonapi:"attr,value,omitempty"` - // Whether this is a Terraform or environment variable. - Category *CategoryType `jsonapi:"attr,category,omitempty"` - // Whether to evaluate the value of the variable as a string of HCL code. HCL *bool `jsonapi:"attr,hcl,omitempty"` diff --git a/vendor/github.com/hashicorp/go-tfe/workspace.go b/vendor/github.com/hashicorp/go-tfe/workspace.go index 923e81d66..d781f45a0 100644 --- a/vendor/github.com/hashicorp/go-tfe/workspace.go +++ b/vendor/github.com/hashicorp/go-tfe/workspace.go @@ -17,7 +17,7 @@ var _ Workspaces = (*workspaces)(nil) // TFE API docs: https://www.terraform.io/docs/enterprise/api/workspaces.html type Workspaces interface { // List all the workspaces within an organization. - List(ctx context.Context, organization string, options WorkspaceListOptions) ([]*Workspace, error) + List(ctx context.Context, organization string, options WorkspaceListOptions) (*WorkspaceList, error) // Create is used to create a new workspace. Create(ctx context.Context, organization string, options WorkspaceCreateOptions) (*Workspace, error) @@ -49,6 +49,12 @@ type workspaces struct { client *Client } +// WorkspaceList represents a list of workspaces. +type WorkspaceList struct { + *Pagination + Items []*Workspace +} + // Workspace represents a Terraform Enterprise workspace. type Workspace struct { ID string `jsonapi:"primary,workspaces"` @@ -74,7 +80,7 @@ type Workspace struct { type VCSRepo struct { Branch string `json:"branch"` Identifier string `json:"identifier"` - IncludeSubmodules bool `json:"ingress-submodules"` + IngressSubmodules bool `json:"ingress-submodules"` OAuthTokenID string `json:"oauth-token-id"` } @@ -97,10 +103,13 @@ type WorkspacePermissions struct { // WorkspaceListOptions represents the options for listing workspaces. type WorkspaceListOptions struct { ListOptions + + // A search string (partial workspace name) used to filter the results. + Search *string `url:"search[name],omitempty"` } // List all the workspaces within an organization. -func (s *workspaces) List(ctx context.Context, organization string, options WorkspaceListOptions) ([]*Workspace, error) { +func (s *workspaces) List(ctx context.Context, organization string, options WorkspaceListOptions) (*WorkspaceList, error) { if !validStringID(&organization) { return nil, errors.New("Invalid value for organization") } @@ -111,13 +120,13 @@ func (s *workspaces) List(ctx context.Context, organization string, options Work return nil, err } - var ws []*Workspace - err = s.client.do(ctx, req, &ws) + wl := &WorkspaceList{} + err = s.client.do(ctx, req, wl) if err != nil { return nil, err } - return ws, nil + return wl, nil } // WorkspaceCreateOptions represents the options for creating a new workspace. @@ -157,7 +166,7 @@ type WorkspaceCreateOptions struct { type VCSRepoOptions struct { Branch *string `json:"branch,omitempty"` Identifier *string `json:"identifier,omitempty"` - IncludeSubmodules *bool `json:"ingress-submodules,omitempty"` + IngressSubmodules *bool `json:"ingress-submodules,omitempty"` OAuthTokenID *string `json:"oauth-token-id,omitempty"` } diff --git a/vendor/vendor.json b/vendor/vendor.json index 40d3646b7..db4980f68 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -1804,10 +1804,10 @@ "revisionTime": "2018-07-12T07:51:27Z" }, { - "checksumSHA1": "926/ijhO8KTdgb02B/++x3w+Ykc=", + "checksumSHA1": "Xo/jovk4kg+1xHsdyfTtBhcLkXo=", "path": "github.com/hashicorp/go-tfe", - "revision": "0e7cd8ef626181232db2d6886263a3db937708cd", - "revisionTime": "2018-08-01T08:24:33Z" + "revision": "6781009f2a64d61df9aff58f17427f0ef43abad0", + "revisionTime": "2018-09-08T08:19:18Z" }, { "checksumSHA1": "85XUnluYJL7F55ptcwdmN8eSOsk=",