Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add X-TFE-Version header #563

Merged
merged 3 commits into from Oct 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -3,6 +3,7 @@
## Enhancements

* Add `NotificationTriggerAssessmentCheckFailed` notification trigger type by @rexredinger [#549](https://github.com/hashicorp/go-tfe/pull/549)
* Add `RemoteTFEVersion()` to the `Client` interface, which exposes the `X-TFE-Version` header set by a remote TFE instance by @sebasslash [#563](https://github.com/hashicorp/go-tfe/pull/563)

# v1.11.0

Expand Down
22 changes: 22 additions & 0 deletions tfe.go
Expand Up @@ -34,6 +34,7 @@ const (
_headerRateLimit = "X-RateLimit-Limit"
_headerRateReset = "X-RateLimit-Reset"
_headerAPIVersion = "TFP-API-Version"
_headerTFEVersion = "X-TFE-Version"
_includeQueryParam = "include"

DefaultAddress = "https://app.terraform.io"
Expand Down Expand Up @@ -115,6 +116,7 @@ type Client struct {
retryLogHook RetryLogHook
retryServerErrors bool
remoteAPIVersion string
remoteTFEVersion string

Admin Admin
Agents Agents
Expand Down Expand Up @@ -341,6 +343,9 @@ func NewClient(cfg *Config) (*Client, error) {
// method later.
client.remoteAPIVersion = meta.APIVersion

// Save the TFE version
client.remoteTFEVersion = meta.TFEVersion

// Create Admin
client.Admin = Admin{
Organizations: &adminOrganizations{client: client},
Expand Down Expand Up @@ -436,6 +441,17 @@ func (c *Client) SetFakeRemoteAPIVersion(fakeAPIVersion string) {
c.remoteAPIVersion = fakeAPIVersion
}

// RemoteTFEVersion returns the server's declared TFE version string.
//
// A Terraform Enterprise API server includes its current version in an
// HTTP header field in all responses. This value is saved by the client
// during the initial setup request and RemoteTFEVersion returns that cached
// value. This function returns an empty string for any Terraform Enterprise version
// earlier than v202208-3 and for Terraform Cloud.
func (c *Client) RemoteTFEVersion() string {
return c.remoteTFEVersion
}

// RetryServerErrors configures the retry HTTP check to also retry
// unexpected errors or requests that failed with a server error.

Expand Down Expand Up @@ -515,6 +531,11 @@ type rawAPIMetadata struct {
// field was not included in the response.
APIVersion string

// TFEVersion is the raw TFE version string reported by the server in the
// X-TFE-Version response header, or an empty string if that header
// field was not included in the response.
TFEVersion string

// RateLimit is the raw API version string reported by the server in the
// X-RateLimit-Limit response header, or an empty string if that header
// field was not included in the response.
Expand Down Expand Up @@ -550,6 +571,7 @@ func (c *Client) getRawAPIMetadata() (rawAPIMetadata, error) {

meta.APIVersion = resp.Header.Get(_headerAPIVersion)
meta.RateLimit = resp.Header.Get(_headerRateLimit)
meta.TFEVersion = resp.Header.Get(_headerTFEVersion)

return meta, nil
}
Expand Down
4 changes: 4 additions & 0 deletions tfe_integration_test.go
Expand Up @@ -27,6 +27,7 @@ func TestClient_newClient(t *testing.T) {
w.Header().Set("Content-Type", "application/vnd.api+json")
w.Header().Set("X-RateLimit-Limit", "30")
w.Header().Set("TFP-API-Version", "34.21.9")
w.Header().Set("X-TFE-Version", "202205-1")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about testing for the case where we have TFC?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The issue with this is that I'd have restructure most of the test simply to test that a field is an empty string (the test isn't really operating under a TFC vs TFE context).

One nice guarantee we have is that the function that's used to fetch the header http.Response.Header.Get() returns a string and the docs mention that if a key does not exist the function will return an empty string. So by testing that we can fetch the value of that header we are also inadvertently testing that it can potentially be empty as well since we know that header can be omitted.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK - that makes sense - thank you for that explanation.

w.WriteHeader(204) // We query the configured ping URL which should return a 204.
}))
defer ts.Close()
Expand Down Expand Up @@ -83,6 +84,9 @@ func TestClient_newClient(t *testing.T) {
if want := "34.21.9"; client.RemoteAPIVersion() != want {
t.Errorf("unexpected remote API version %q; want %q", client.RemoteAPIVersion(), want)
}
if want := "202205-1"; client.RemoteTFEVersion() != want {
t.Errorf("unexpected remote TFE version %q; want %q", client.RemoteTFEVersion(), want)
}

client.SetFakeRemoteAPIVersion("1.0")

Expand Down