From 2e71f04f394395d211db43abc8e56d9459838a9e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 26 Jun 2023 16:59:22 +0000 Subject: [PATCH] Bump github.com/hashicorp/go-tfe from 1.27.0 to 1.28.0 Bumps [github.com/hashicorp/go-tfe](https://github.com/hashicorp/go-tfe) from 1.27.0 to 1.28.0. - [Release notes](https://github.com/hashicorp/go-tfe/releases) - [Changelog](https://github.com/hashicorp/go-tfe/blob/main/CHANGELOG.md) - [Commits](https://github.com/hashicorp/go-tfe/compare/v1.27.0...v1.28.0) --- updated-dependencies: - dependency-name: github.com/hashicorp/go-tfe dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 5 +- go.sum | 10 +- .../hashicorp/go-retryablehttp/CHANGELOG.md | 9 ++ .../hashicorp/go-retryablehttp/CODEOWNERS | 1 + .../hashicorp/go-retryablehttp/LICENSE | 2 + .../hashicorp/go-retryablehttp/client.go | 16 ++- .../go-retryablehttp/roundtripper.go | 3 + .../github.com/hashicorp/go-tfe/CHANGELOG.md | 11 ++ .../hashicorp/go-tfe/configuration_version.go | 7 +- vendor/github.com/hashicorp/go-tfe/errors.go | 6 + .../github.com/hashicorp/go-tfe/ip_ranges.go | 2 +- .../hashicorp/go-tfe/organization_tags.go | 3 + .../hashicorp/go-tfe/policy_set_version.go | 7 +- .../hashicorp/go-tfe/registry_module.go | 7 +- vendor/github.com/hashicorp/go-tfe/request.go | 48 +++++-- .../hashicorp/go-tfe/state_version.go | 94 +++++++++++-- vendor/github.com/hashicorp/go-tfe/tfe.go | 43 +++++- .../github.com/hashicorp/go-tfe/workspace.go | 1 + vendor/golang.org/x/sync/LICENSE | 27 ++++ vendor/golang.org/x/sync/PATENTS | 22 +++ vendor/golang.org/x/sync/errgroup/errgroup.go | 132 ++++++++++++++++++ vendor/golang.org/x/sync/errgroup/go120.go | 14 ++ .../golang.org/x/sync/errgroup/pre_go120.go | 15 ++ vendor/modules.txt | 7 +- 24 files changed, 437 insertions(+), 55 deletions(-) create mode 100644 vendor/github.com/hashicorp/go-retryablehttp/CHANGELOG.md create mode 100644 vendor/github.com/hashicorp/go-retryablehttp/CODEOWNERS create mode 100644 vendor/golang.org/x/sync/LICENSE create mode 100644 vendor/golang.org/x/sync/PATENTS create mode 100644 vendor/golang.org/x/sync/errgroup/errgroup.go create mode 100644 vendor/golang.org/x/sync/errgroup/go120.go create mode 100644 vendor/golang.org/x/sync/errgroup/pre_go120.go diff --git a/go.mod b/go.mod index 5c0af91..5dfaa00 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/AGLEnergyPublic/tfectl go 1.18 require ( - github.com/hashicorp/go-tfe v1.27.0 + github.com/hashicorp/go-tfe v1.28.0 github.com/itchyny/gojq v0.12.13 github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.7.0 @@ -14,7 +14,7 @@ require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect - github.com/hashicorp/go-retryablehttp v0.7.2 // indirect + github.com/hashicorp/go-retryablehttp v0.7.4 // indirect github.com/hashicorp/go-slug v0.11.1 // indirect github.com/hashicorp/go-version v1.6.0 // indirect github.com/hashicorp/jsonapi v0.0.0-20210826224640-ee7dae0fb22d // indirect @@ -22,6 +22,7 @@ require ( github.com/itchyny/timefmt-go v0.1.5 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/spf13/pflag v1.0.5 // indirect + golang.org/x/sync v0.3.0 // indirect golang.org/x/sys v0.8.0 // indirect golang.org/x/time v0.3.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 58e1efd..005edbc 100644 --- a/go.sum +++ b/go.sum @@ -10,12 +10,12 @@ github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9n github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= -github.com/hashicorp/go-retryablehttp v0.7.2 h1:AcYqCvkpalPnPF2pn0KamgwamS42TqUDDYFRKq/RAd0= -github.com/hashicorp/go-retryablehttp v0.7.2/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= +github.com/hashicorp/go-retryablehttp v0.7.4 h1:ZQgVdpTdAL7WpMIwLzCfbalOcSUdkDZnpUv3/+BxzFA= +github.com/hashicorp/go-retryablehttp v0.7.4/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= github.com/hashicorp/go-slug v0.11.1 h1:c6lLdQnlhUWbS5I7hw8SvfymoFuy6EmiFDedy6ir994= github.com/hashicorp/go-slug v0.11.1/go.mod h1:Ib+IWBYfEfJGI1ZyXMGNbu2BU+aa3Dzu41RKLH301v4= -github.com/hashicorp/go-tfe v1.27.0 h1:g+85TZfdUZOhIEkdDKRO8/q2JflhWB9Ne0V1xJOr4nE= -github.com/hashicorp/go-tfe v1.27.0/go.mod h1:gu0DD6yf7K9P9IcuM4Wjl1grKYCa/o3oRRX5BQ+xEnY= +github.com/hashicorp/go-tfe v1.28.0 h1:YQNfHz5UPMiOD2idad4GCjzG3R2ExPww741PBPqMOIU= +github.com/hashicorp/go-tfe v1.28.0/go.mod h1:z0182DGE/63AKUaWblUVBIrt+xdSmsuuXg5AoxGqDF4= github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= @@ -41,6 +41,8 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/vendor/github.com/hashicorp/go-retryablehttp/CHANGELOG.md b/vendor/github.com/hashicorp/go-retryablehttp/CHANGELOG.md new file mode 100644 index 0000000..33686e4 --- /dev/null +++ b/vendor/github.com/hashicorp/go-retryablehttp/CHANGELOG.md @@ -0,0 +1,9 @@ +## 0.7.4 (Jun 6, 2023) + +BUG FIXES + +- client: fixing an issue where the Content-Type header wouldn't be sent with an empty payload when using HTTP/2 [GH-194] + +## 0.7.3 (May 15, 2023) + +Initial release diff --git a/vendor/github.com/hashicorp/go-retryablehttp/CODEOWNERS b/vendor/github.com/hashicorp/go-retryablehttp/CODEOWNERS new file mode 100644 index 0000000..f8389c9 --- /dev/null +++ b/vendor/github.com/hashicorp/go-retryablehttp/CODEOWNERS @@ -0,0 +1 @@ +* @hashicorp/release-engineering \ No newline at end of file diff --git a/vendor/github.com/hashicorp/go-retryablehttp/LICENSE b/vendor/github.com/hashicorp/go-retryablehttp/LICENSE index e87a115..f4f97ee 100644 --- a/vendor/github.com/hashicorp/go-retryablehttp/LICENSE +++ b/vendor/github.com/hashicorp/go-retryablehttp/LICENSE @@ -1,3 +1,5 @@ +Copyright (c) 2015 HashiCorp, Inc. + Mozilla Public License, version 2.0 1. Definitions diff --git a/vendor/github.com/hashicorp/go-retryablehttp/client.go b/vendor/github.com/hashicorp/go-retryablehttp/client.go index f40d241..cad96bd 100644 --- a/vendor/github.com/hashicorp/go-retryablehttp/client.go +++ b/vendor/github.com/hashicorp/go-retryablehttp/client.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + // Package retryablehttp provides a familiar HTTP client interface with // automatic retries and exponential backoff. It is a thin wrapper over the // standard net/http client library and exposes nearly the same public API. @@ -257,10 +260,17 @@ func getBodyReaderAndContentLength(rawBody interface{}) (ReaderFunc, int64, erro if err != nil { return nil, 0, err } - bodyReader = func() (io.Reader, error) { - return bytes.NewReader(buf), nil + if len(buf) == 0 { + bodyReader = func() (io.Reader, error) { + return http.NoBody, nil + } + contentLength = 0 + } else { + bodyReader = func() (io.Reader, error) { + return bytes.NewReader(buf), nil + } + contentLength = int64(len(buf)) } - contentLength = int64(len(buf)) // No body provided, nothing to do case nil: diff --git a/vendor/github.com/hashicorp/go-retryablehttp/roundtripper.go b/vendor/github.com/hashicorp/go-retryablehttp/roundtripper.go index 8f3ee35..8c407ad 100644 --- a/vendor/github.com/hashicorp/go-retryablehttp/roundtripper.go +++ b/vendor/github.com/hashicorp/go-retryablehttp/roundtripper.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package retryablehttp import ( diff --git a/vendor/github.com/hashicorp/go-tfe/CHANGELOG.md b/vendor/github.com/hashicorp/go-tfe/CHANGELOG.md index a6ab45c..90434f5 100644 --- a/vendor/github.com/hashicorp/go-tfe/CHANGELOG.md +++ b/vendor/github.com/hashicorp/go-tfe/CHANGELOG.md @@ -1,5 +1,16 @@ # UNRELEASED +# v1.28.0 + +## Enhancements +* Update `Workspaces` to include associated `project` resource by @glennsarti [#714](https://github.com/hashicorp/go-tfe/pull/714) +* Adds BETA method `Upload` method to `StateVersions` and support for pending state versions by @brandonc [#717](https://github.com/hashicorp/go-tfe/pull/717) +* Adds support for the query parameter `q` to search `Organization Tags` by name by @sharathrnair87 [#720](https://github.com/hashicorp/go-tfe/pull/720) +* Added ContextWithResponseHeaderHook support to `IPRanges` by @brandonc [#717](https://github.com/hashicorp/go-tfe/pull/717) + +## Bug Fixes +* `ConfigurationVersions`, `PolicySetVersions`, and `RegistryModules` `Upload` methods were sending API credentials to the specified upload URL, which was unnecessary by @brandonc [#717](https://github.com/hashicorp/go-tfe/pull/717) + # v1.27.0 ## Enhancements diff --git a/vendor/github.com/hashicorp/go-tfe/configuration_version.go b/vendor/github.com/hashicorp/go-tfe/configuration_version.go index 8f19550..5cb67d3 100644 --- a/vendor/github.com/hashicorp/go-tfe/configuration_version.go +++ b/vendor/github.com/hashicorp/go-tfe/configuration_version.go @@ -275,12 +275,7 @@ func (s *configurationVersions) Upload(ctx context.Context, uploadURL, path stri // **Note**: This method does not validate the content being uploaded and is therefore the caller's // responsibility to ensure the raw content is a valid Terraform configuration. func (s *configurationVersions) UploadTarGzip(ctx context.Context, uploadURL string, archive io.Reader) error { - req, err := s.client.NewRequest("PUT", uploadURL, archive) - if err != nil { - return err - } - - return req.Do(ctx, nil) + return s.client.doForeignPUTRequest(ctx, uploadURL, archive) } // Archive a configuration version. This can only be done on configuration versions that diff --git a/vendor/github.com/hashicorp/go-tfe/errors.go b/vendor/github.com/hashicorp/go-tfe/errors.go index 95e8932..cc8c07a 100644 --- a/vendor/github.com/hashicorp/go-tfe/errors.go +++ b/vendor/github.com/hashicorp/go-tfe/errors.go @@ -353,4 +353,10 @@ var ( ErrRequiredRegistryModule = errors.New("registry module is required") ErrTerraformVersionValidForPlanOnly = errors.New("setting terraform-version is only valid when plan-only is set to true") + + ErrStateMustBeOmitted = errors.New("when uploading state, the State and JSONState strings must be omitted from options") + + ErrRequiredRawState = errors.New("RawState is required") + + ErrStateVersionUploadNotSupported = errors.New("upload not supported by this version of Terraform Enterprise") ) diff --git a/vendor/github.com/hashicorp/go-tfe/ip_ranges.go b/vendor/github.com/hashicorp/go-tfe/ip_ranges.go index 0703887..68a0352 100644 --- a/vendor/github.com/hashicorp/go-tfe/ip_ranges.go +++ b/vendor/github.com/hashicorp/go-tfe/ip_ranges.go @@ -50,7 +50,7 @@ func (i *ipRanges) Read(ctx context.Context, modifiedSince string) (*IPRange, er } ir := &IPRange{} - err = req.doIPRanges(ctx, ir) + err = req.DoJSON(ctx, ir) if err != nil { return nil, err } diff --git a/vendor/github.com/hashicorp/go-tfe/organization_tags.go b/vendor/github.com/hashicorp/go-tfe/organization_tags.go index d0882b9..96fd621 100644 --- a/vendor/github.com/hashicorp/go-tfe/organization_tags.go +++ b/vendor/github.com/hashicorp/go-tfe/organization_tags.go @@ -56,6 +56,9 @@ type OrganizationTagsListOptions struct { ListOptions // Optional: Filter string `url:"filter[exclude][taggable][id],omitempty"` + + // Optional: A search query string. Organization tags are searchable by name likeness. + Query string `url:"q,omitempty"` } // OrganizationTagsDeleteOptions represents the request body for deleting a tag in an organization diff --git a/vendor/github.com/hashicorp/go-tfe/policy_set_version.go b/vendor/github.com/hashicorp/go-tfe/policy_set_version.go index 72bbd6e..c4fdf00 100644 --- a/vendor/github.com/hashicorp/go-tfe/policy_set_version.go +++ b/vendor/github.com/hashicorp/go-tfe/policy_set_version.go @@ -154,10 +154,5 @@ func (p *policySetVersions) Upload(ctx context.Context, psv PolicySetVersion, pa return err } - req, err := p.client.NewRequest("PUT", uploadURL, body) - if err != nil { - return err - } - - return req.Do(ctx, nil) + return p.client.doForeignPUTRequest(ctx, uploadURL, body) } diff --git a/vendor/github.com/hashicorp/go-tfe/registry_module.go b/vendor/github.com/hashicorp/go-tfe/registry_module.go index 60c6303..0a308db 100644 --- a/vendor/github.com/hashicorp/go-tfe/registry_module.go +++ b/vendor/github.com/hashicorp/go-tfe/registry_module.go @@ -270,12 +270,7 @@ func (r *registryModules) Upload(ctx context.Context, rmv RegistryModuleVersion, // **Note**: This method does not validate the content being uploaded and is therefore the caller's // responsibility to ensure the raw content is a valid Terraform configuration. func (r *registryModules) UploadTarGzip(ctx context.Context, uploadURL string, archive io.Reader) error { - req, err := r.client.NewRequest("PUT", uploadURL, archive) - if err != nil { - return err - } - - return req.Do(ctx, nil) + return r.client.doForeignPUTRequest(ctx, uploadURL, archive) } // Create a new registry module without a VCS repo diff --git a/vendor/github.com/hashicorp/go-tfe/request.go b/vendor/github.com/hashicorp/go-tfe/request.go index ce5fb83..aaf8e23 100644 --- a/vendor/github.com/hashicorp/go-tfe/request.go +++ b/vendor/github.com/hashicorp/go-tfe/request.go @@ -27,8 +27,10 @@ type ClientRequest struct { func (r ClientRequest) Do(ctx context.Context, model interface{}) error { // Wait will block until the limiter can obtain a new token // or returns an error if the given context is canceled. - if err := r.limiter.Wait(ctx); err != nil { - return err + if r.limiter != nil { + if err := r.limiter.Wait(ctx); err != nil { + return err + } } // If the caller provided a response header hook then we'll call it @@ -76,20 +78,31 @@ func (r ClientRequest) Do(ctx context.Context, model interface{}) error { return unmarshalResponse(resp.Body, model) } -// doIPRanges is similar to Do except that The IP ranges API is not returning jsonapi -// like every other endpoint which means we need to handle it differently. -func (r *ClientRequest) doIPRanges(ctx context.Context, ir *IPRange) error { +// DoJSON is similar to Do except that it should be used when a plain JSON response is expected +// as opposed to json-api. +func (r *ClientRequest) DoJSON(ctx context.Context, model any) error { // Wait will block until the limiter can obtain a new token // or returns an error if the given context is canceled. - if err := r.limiter.Wait(ctx); err != nil { - return err + if r.limiter != nil { + if err := r.limiter.Wait(ctx); err != nil { + return err + } } // Add the context to the request. contextReq := r.retryableRequest.WithContext(ctx) + // If the caller provided a response header hook then we'll call it + // once we have a response. + respHeaderHook := contextResponseHeaderHook(ctx) + // Execute the request and check the response. resp, err := r.http.Do(contextReq) + if resp != nil { + // We call the callback whenever there's any sort of response, + // even if it's returned in conjunction with an error. + respHeaderHook(resp.StatusCode, resp.Header) + } if err != nil { // If we got an error, and the context has been canceled, // the context's error is probably more useful. @@ -102,15 +115,26 @@ func (r *ClientRequest) doIPRanges(ctx context.Context, ir *IPRange) error { } defer resp.Body.Close() - if resp.StatusCode < 200 && resp.StatusCode >= 400 { - return fmt.Errorf("error HTTP response while retrieving IP ranges: %d", resp.StatusCode) + if resp.StatusCode < 200 || resp.StatusCode >= 400 { + return fmt.Errorf("error HTTP response: %d", resp.StatusCode) } else if resp.StatusCode == 304 { + // Got a "Not Modified" response, but we can't return a model because there is no response body. + // This is necessary to support the IPRanges endpoint, which has the peculiar behavior + // of not returning content but allowing a 304 response by optionally sending an + // If-Modified-Since header. return nil } - err = json.NewDecoder(resp.Body).Decode(ir) - if err != nil { + // Return here if decoding the response isn't needed. + if model == nil { + return nil + } + + // If v implements io.Writer, write the raw response body. + if w, ok := model.(io.Writer); ok { + _, err := io.Copy(w, resp.Body) return err } - return nil + + return json.NewDecoder(resp.Body).Decode(model) } diff --git a/vendor/github.com/hashicorp/go-tfe/state_version.go b/vendor/github.com/hashicorp/go-tfe/state_version.go index 357edf7..9b399c9 100644 --- a/vendor/github.com/hashicorp/go-tfe/state_version.go +++ b/vendor/github.com/hashicorp/go-tfe/state_version.go @@ -8,12 +8,25 @@ import ( "context" "fmt" "net/url" + "strings" "time" + + "golang.org/x/sync/errgroup" ) // Compile-time proof of interface implementation. var _ StateVersions = (*stateVersions)(nil) +// StateVersionStatus are available state version status values +type StateVersionStatus string + +// Available state version statuses. +const ( + StateVersionPending StateVersionStatus = "pending" + StateVersionFinalized StateVersionStatus = "finalized" + StateVersionDiscarded StateVersionStatus = "discarded" +) + // StateVersions describes all the state version related methods that // the Terraform Enterprise API supports. // @@ -26,6 +39,12 @@ type StateVersions interface { // Create a new state version for the given workspace. Create(ctx context.Context, workspaceID string, options StateVersionCreateOptions) (*StateVersion, error) + // Upload creates a new state version but uploads the state content directly to the object store. + // This is a more resilient form of Create and is the recommended approach to creating state versions. + // + // **Note: This method is still in BETA and subject to change.** + Upload(ctx context.Context, workspaceID string, options StateVersionUploadOptions) (*StateVersion, error) + // Read a state version by its ID. Read(ctx context.Context, svID string) (*StateVersion, error) @@ -60,12 +79,16 @@ type StateVersionList struct { // StateVersion represents a Terraform Enterprise state version. type StateVersion struct { - ID string `jsonapi:"primary,state-versions"` - CreatedAt time.Time `jsonapi:"attr,created-at,iso8601"` - DownloadURL string `jsonapi:"attr,hosted-state-download-url"` - Serial int64 `jsonapi:"attr,serial"` - VCSCommitSHA string `jsonapi:"attr,vcs-commit-sha"` - VCSCommitURL string `jsonapi:"attr,vcs-commit-url"` + ID string `jsonapi:"primary,state-versions"` + CreatedAt time.Time `jsonapi:"attr,created-at,iso8601"` + DownloadURL string `jsonapi:"attr,hosted-state-download-url"` + UploadURL string `jsonapi:"attr,hosted-state-upload-url"` + Status StateVersionStatus `jsonapi:"attr,status"` + JSONUploadURL string `jsonapi:"attr,hosted-json-state-upload-url"` + JSONDownloadURL string `jsonapi:"attr,hosted-json-state-download-url"` + Serial int64 `jsonapi:"attr,serial"` + VCSCommitSHA string `jsonapi:"attr,vcs-commit-sha"` + VCSCommitURL string `jsonapi:"attr,vcs-commit-url"` // Whether Terraform Cloud has finished populating any StateVersion fields that required async processing. // If `false`, some fields may appear empty even if they should actually contain data; see comments on // individual fields for details. @@ -147,8 +170,8 @@ type StateVersionCreateOptions struct { // Required: The serial of the state. Serial *int64 `jsonapi:"attr,serial"` - // Required: The base64 encoded state. - State *string `jsonapi:"attr,state"` + // Optional: The base64 encoded state. + State *string `jsonapi:"attr,state,omitempty"` // Optional: Force can be set to skip certain validations. Wrong use // of this flag can cause data loss, so USE WITH CAUTION! @@ -173,6 +196,13 @@ type StateVersionCreateOptions struct { JSONStateOutputs *string `jsonapi:"attr,json-state-outputs,omitempty"` } +type StateVersionUploadOptions struct { + StateVersionCreateOptions + + RawState []byte + RawJSONState []byte +} + type StateVersionModules struct { Root StateVersionModuleRoot `jsonapi:"attr,root"` } @@ -243,6 +273,40 @@ func (s *stateVersions) Create(ctx context.Context, workspaceID string, options return sv, nil } +// Upload creates a new state version but uploads the state content directly to the object store. +// This is a more resilient form of Create and is the recommended approach to creating state versions. +// +// **Note: This method is still in BETA and subject to change.** +func (s *stateVersions) Upload(ctx context.Context, workspaceID string, options StateVersionUploadOptions) (*StateVersion, error) { + if err := options.valid(); err != nil { + return nil, err + } + + sv, err := s.Create(ctx, workspaceID, options.StateVersionCreateOptions) + if err != nil { + if strings.Contains(err.Error(), "param is missing or the value is empty: state") { + return nil, ErrStateVersionUploadNotSupported + } + } + + g, _ := errgroup.WithContext(ctx) + g.Go(func() error { + return s.client.doForeignPUTRequest(ctx, sv.UploadURL, bytes.NewReader(options.RawState)) + }) + if options.RawJSONState != nil { + g.Go(func() error { + return s.client.doForeignPUTRequest(ctx, sv.JSONUploadURL, bytes.NewReader(options.RawJSONState)) + }) + } + + if err := g.Wait(); err != nil { + return nil, err + } + + // Re-read the state version to get the updated status, if available + return s.Read(ctx, sv.ID) +} + // Read a state version by its ID. func (s *stateVersions) ReadWithOptions(ctx context.Context, svID string, options *StateVersionReadOptions) (*StateVersion, error) { if !validStringID(&svID) { @@ -362,8 +426,18 @@ func (o StateVersionCreateOptions) valid() error { if o.Serial == nil { return ErrRequiredSerial } - if !validString(o.State) { - return ErrRequiredState + return nil +} + +func (o StateVersionUploadOptions) valid() error { + if err := o.StateVersionCreateOptions.valid(); err != nil { + return err + } + if o.State != nil || o.JSONState != nil { + return ErrStateMustBeOmitted + } + if o.RawState == nil { + return ErrRequiredRawState } return nil } diff --git a/vendor/github.com/hashicorp/go-tfe/tfe.go b/vendor/github.com/hashicorp/go-tfe/tfe.go index 16eb4cd..82d7fa8 100644 --- a/vendor/github.com/hashicorp/go-tfe/tfe.go +++ b/vendor/github.com/hashicorp/go-tfe/tfe.go @@ -198,11 +198,48 @@ type Meta struct { IPRanges IPRanges } -func (c *Client) NewRequest(method, path string, reqAttr interface{}) (*ClientRequest, error) { +// doForeignPUTRequest performs a PUT request using the specific data body. The Content-Type +// header is set to application/octet-stream but no Authentication header is sent. No response +// body is decoded. +func (c *Client) doForeignPUTRequest(ctx context.Context, foreignURL string, data io.Reader) error { + u, err := url.Parse(foreignURL) + if err != nil { + return fmt.Errorf("specified URL was not valid: %w", err) + } + + reqHeaders := make(http.Header) + reqHeaders.Set("Accept", "application/json, */*") + reqHeaders.Set("Content-Type", "application/octet-stream") + + req, err := retryablehttp.NewRequest("PUT", u.String(), data) + if err != nil { + return err + } + + // Set the default headers. + for k, v := range c.headers { + req.Header[k] = v + } + + // Set the request specific headers. + for k, v := range reqHeaders { + req.Header[k] = v + } + + request := &ClientRequest{ + retryableRequest: req, + http: c.http, + Header: req.Header, + } + + return request.DoJSON(ctx, nil) +} + +func (c *Client) NewRequest(method, path string, reqAttr any) (*ClientRequest, error) { return c.NewRequestWithAdditionalQueryParams(method, path, reqAttr, nil) } -func (c *Client) NewRequestWithAdditionalQueryParams(method, path string, reqAttr interface{}, additionalQueryParams map[string][]string) (*ClientRequest, error) { +func (c *Client) NewRequestWithAdditionalQueryParams(method, path string, reqAttr any, additionalQueryParams map[string][]string) (*ClientRequest, error) { var u *url.URL var err error if strings.Contains(path, "/api/registry/") { @@ -221,7 +258,7 @@ func (c *Client) NewRequestWithAdditionalQueryParams(method, path string, reqAtt reqHeaders := make(http.Header) reqHeaders.Set("Authorization", "Bearer "+c.token) - var body interface{} + var body any switch method { case "GET": reqHeaders.Set("Accept", ContentTypeJSONAPI) diff --git a/vendor/github.com/hashicorp/go-tfe/workspace.go b/vendor/github.com/hashicorp/go-tfe/workspace.go index dc54f6a..2b9c968 100644 --- a/vendor/github.com/hashicorp/go-tfe/workspace.go +++ b/vendor/github.com/hashicorp/go-tfe/workspace.go @@ -238,6 +238,7 @@ const ( WSReadme WSIncludeOpt = "readme" WSOutputs WSIncludeOpt = "outputs" WSCurrentStateVer WSIncludeOpt = "current-state-version" + WSProject WSIncludeOpt = "project" ) // WorkspaceReadOptions represents the options for reading a workspace. diff --git a/vendor/golang.org/x/sync/LICENSE b/vendor/golang.org/x/sync/LICENSE new file mode 100644 index 0000000..6a66aea --- /dev/null +++ b/vendor/golang.org/x/sync/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/golang.org/x/sync/PATENTS b/vendor/golang.org/x/sync/PATENTS new file mode 100644 index 0000000..7330990 --- /dev/null +++ b/vendor/golang.org/x/sync/PATENTS @@ -0,0 +1,22 @@ +Additional IP Rights Grant (Patents) + +"This implementation" means the copyrightable works distributed by +Google as part of the Go project. + +Google hereby grants to You a perpetual, worldwide, non-exclusive, +no-charge, royalty-free, irrevocable (except as stated in this section) +patent license to make, have made, use, offer to sell, sell, import, +transfer and otherwise run, modify and propagate the contents of this +implementation of Go, where such license applies only to those patent +claims, both currently owned or controlled by Google and acquired in +the future, licensable by Google that are necessarily infringed by this +implementation of Go. This grant does not include claims that would be +infringed only as a consequence of further modification of this +implementation. If you or your agent or exclusive licensee institute or +order or agree to the institution of patent litigation against any +entity (including a cross-claim or counterclaim in a lawsuit) alleging +that this implementation of Go or any code incorporated within this +implementation of Go constitutes direct or contributory patent +infringement, or inducement of patent infringement, then any patent +rights granted to you under this License for this implementation of Go +shall terminate as of the date such litigation is filed. diff --git a/vendor/golang.org/x/sync/errgroup/errgroup.go b/vendor/golang.org/x/sync/errgroup/errgroup.go new file mode 100644 index 0000000..b18efb7 --- /dev/null +++ b/vendor/golang.org/x/sync/errgroup/errgroup.go @@ -0,0 +1,132 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package errgroup provides synchronization, error propagation, and Context +// cancelation for groups of goroutines working on subtasks of a common task. +package errgroup + +import ( + "context" + "fmt" + "sync" +) + +type token struct{} + +// A Group is a collection of goroutines working on subtasks that are part of +// the same overall task. +// +// A zero Group is valid, has no limit on the number of active goroutines, +// and does not cancel on error. +type Group struct { + cancel func(error) + + wg sync.WaitGroup + + sem chan token + + errOnce sync.Once + err error +} + +func (g *Group) done() { + if g.sem != nil { + <-g.sem + } + g.wg.Done() +} + +// WithContext returns a new Group and an associated Context derived from ctx. +// +// The derived Context is canceled the first time a function passed to Go +// returns a non-nil error or the first time Wait returns, whichever occurs +// first. +func WithContext(ctx context.Context) (*Group, context.Context) { + ctx, cancel := withCancelCause(ctx) + return &Group{cancel: cancel}, ctx +} + +// Wait blocks until all function calls from the Go method have returned, then +// returns the first non-nil error (if any) from them. +func (g *Group) Wait() error { + g.wg.Wait() + if g.cancel != nil { + g.cancel(g.err) + } + return g.err +} + +// Go calls the given function in a new goroutine. +// It blocks until the new goroutine can be added without the number of +// active goroutines in the group exceeding the configured limit. +// +// The first call to return a non-nil error cancels the group's context, if the +// group was created by calling WithContext. The error will be returned by Wait. +func (g *Group) Go(f func() error) { + if g.sem != nil { + g.sem <- token{} + } + + g.wg.Add(1) + go func() { + defer g.done() + + if err := f(); err != nil { + g.errOnce.Do(func() { + g.err = err + if g.cancel != nil { + g.cancel(g.err) + } + }) + } + }() +} + +// TryGo calls the given function in a new goroutine only if the number of +// active goroutines in the group is currently below the configured limit. +// +// The return value reports whether the goroutine was started. +func (g *Group) TryGo(f func() error) bool { + if g.sem != nil { + select { + case g.sem <- token{}: + // Note: this allows barging iff channels in general allow barging. + default: + return false + } + } + + g.wg.Add(1) + go func() { + defer g.done() + + if err := f(); err != nil { + g.errOnce.Do(func() { + g.err = err + if g.cancel != nil { + g.cancel(g.err) + } + }) + } + }() + return true +} + +// SetLimit limits the number of active goroutines in this group to at most n. +// A negative value indicates no limit. +// +// Any subsequent call to the Go method will block until it can add an active +// goroutine without exceeding the configured limit. +// +// The limit must not be modified while any goroutines in the group are active. +func (g *Group) SetLimit(n int) { + if n < 0 { + g.sem = nil + return + } + if len(g.sem) != 0 { + panic(fmt.Errorf("errgroup: modify limit while %v goroutines in the group are still active", len(g.sem))) + } + g.sem = make(chan token, n) +} diff --git a/vendor/golang.org/x/sync/errgroup/go120.go b/vendor/golang.org/x/sync/errgroup/go120.go new file mode 100644 index 0000000..7d419d3 --- /dev/null +++ b/vendor/golang.org/x/sync/errgroup/go120.go @@ -0,0 +1,14 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build go1.20 +// +build go1.20 + +package errgroup + +import "context" + +func withCancelCause(parent context.Context) (context.Context, func(error)) { + return context.WithCancelCause(parent) +} diff --git a/vendor/golang.org/x/sync/errgroup/pre_go120.go b/vendor/golang.org/x/sync/errgroup/pre_go120.go new file mode 100644 index 0000000..1795c18 --- /dev/null +++ b/vendor/golang.org/x/sync/errgroup/pre_go120.go @@ -0,0 +1,15 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !go1.20 +// +build !go1.20 + +package errgroup + +import "context" + +func withCancelCause(parent context.Context) (context.Context, func(error)) { + ctx, cancel := context.WithCancel(parent) + return ctx, func(error) { cancel() } +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 0af730a..eccfa81 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -7,13 +7,13 @@ github.com/google/go-querystring/query # github.com/hashicorp/go-cleanhttp v0.5.2 ## explicit; go 1.13 github.com/hashicorp/go-cleanhttp -# github.com/hashicorp/go-retryablehttp v0.7.2 +# github.com/hashicorp/go-retryablehttp v0.7.4 ## explicit; go 1.13 github.com/hashicorp/go-retryablehttp # github.com/hashicorp/go-slug v0.11.1 ## explicit; go 1.15 github.com/hashicorp/go-slug -# github.com/hashicorp/go-tfe v1.27.0 +# github.com/hashicorp/go-tfe v1.28.0 ## explicit; go 1.19 github.com/hashicorp/go-tfe # github.com/hashicorp/go-version v1.6.0 @@ -47,6 +47,9 @@ github.com/spf13/pflag ## explicit; go 1.20 github.com/stretchr/testify/assert github.com/stretchr/testify/require +# golang.org/x/sync v0.3.0 +## explicit; go 1.17 +golang.org/x/sync/errgroup # golang.org/x/sys v0.8.0 ## explicit; go 1.17 golang.org/x/sys/internal/unsafeheader