Skip to content

Commit 27a7855

Browse files
committed
internal/function: add user_agent provider-defined function
This function will format a User-Agent entry given a product name, product version, and optional comment. It can be paired with the `user_agent` argument in the `provider` and `provider_meta` blocks. ```console % TF_ACC=1 go test -v ./internal/function/... -run=TestUserAgentFunction_ 2025/12/10 15:06:44 Creating Terraform AWS Provider (SDKv2-style)... 2025/12/10 15:06:45 Initializing Terraform AWS Provider (SDKv2-style)... --- PASS: TestUserAgentFunction_missingName (1.01s) --- PASS: TestUserAgentFunction_basic (21.86s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/function 28.277s ```
1 parent deb8ac9 commit 27a7855

File tree

5 files changed

+185
-0
lines changed

5 files changed

+185
-0
lines changed

.changelog/45464.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,6 @@ provider: The `provider_meta` block is now supported. The `user_agent` argument
44
```release-note:enhancement
55
provider: Add `user_agent` argument
66
```
7+
```release-note:new-function
8+
user_agent
9+
```

internal/function/user_agent.go

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
package function
5+
6+
import (
7+
"context"
8+
"strings"
9+
10+
"github.com/hashicorp/terraform-plugin-framework/function"
11+
)
12+
13+
var _ function.Function = userAgentFunction{}
14+
15+
func NewUserAgentFunction() function.Function {
16+
return &userAgentFunction{}
17+
}
18+
19+
type userAgentFunction struct{}
20+
21+
func (f userAgentFunction) Metadata(ctx context.Context, req function.MetadataRequest, resp *function.MetadataResponse) {
22+
resp.Name = "user_agent"
23+
}
24+
25+
func (f userAgentFunction) Definition(ctx context.Context, req function.DefinitionRequest, resp *function.DefinitionResponse) {
26+
resp.Definition = function.Definition{
27+
Summary: "user_agent Function",
28+
MarkdownDescription: "Formats a User-Agent product for use with the user_agent argument in the provider or provider_meta block.",
29+
Parameters: []function.Parameter{
30+
function.StringParameter{
31+
Name: "product_name",
32+
MarkdownDescription: "Product name.",
33+
},
34+
function.StringParameter{
35+
Name: "product_version",
36+
MarkdownDescription: "Product version.",
37+
},
38+
function.StringParameter{
39+
Name: "comment",
40+
MarkdownDescription: "Comment describing any additional product details.",
41+
},
42+
},
43+
Return: function.StringReturn{},
44+
}
45+
}
46+
47+
func (f userAgentFunction) Run(ctx context.Context, req function.RunRequest, resp *function.RunResponse) {
48+
var name, version, comment string
49+
50+
resp.Error = function.ConcatFuncErrors(req.Arguments.Get(ctx, &name, &version, &comment))
51+
if resp.Error != nil {
52+
return
53+
}
54+
55+
if name == "" {
56+
resp.Error = function.ConcatFuncErrors(resp.Error, function.NewFuncError("product_name must be set"))
57+
return
58+
}
59+
60+
var sb strings.Builder
61+
62+
sb.WriteString(name)
63+
if version != "" {
64+
sb.WriteString("/" + version)
65+
}
66+
if comment != "" {
67+
sb.WriteString(" (" + comment + ")")
68+
}
69+
70+
resp.Error = function.ConcatFuncErrors(resp.Result.Set(ctx, sb.String()))
71+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
package function_test
5+
6+
import (
7+
"fmt"
8+
"testing"
9+
10+
"github.com/YakDriver/regexache"
11+
"github.com/hashicorp/go-version"
12+
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
13+
"github.com/hashicorp/terraform-plugin-testing/tfversion"
14+
"github.com/hashicorp/terraform-provider-aws/internal/acctest"
15+
)
16+
17+
func TestUserAgentFunction_basic(t *testing.T) {
18+
t.Parallel()
19+
20+
resource.UnitTest(t, resource.TestCase{
21+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
22+
TerraformVersionChecks: []tfversion.TerraformVersionCheck{
23+
tfversion.SkipBelow(version.Must(version.NewVersion("1.8.0"))),
24+
},
25+
Steps: []resource.TestStep{
26+
{
27+
Config: testUserAgentFunctionConfig("test-module", "0.0.1", "test comment"),
28+
Check: resource.ComposeAggregateTestCheckFunc(
29+
resource.TestCheckOutput("test", "test-module/0.0.1 (test comment)"),
30+
),
31+
},
32+
{
33+
Config: testUserAgentFunctionConfig("test-module", "0.0.1", ""),
34+
Check: resource.ComposeAggregateTestCheckFunc(
35+
resource.TestCheckOutput("test", "test-module/0.0.1"),
36+
),
37+
},
38+
{
39+
Config: testUserAgentFunctionConfig("test-module", "", ""),
40+
Check: resource.ComposeAggregateTestCheckFunc(
41+
resource.TestCheckOutput("test", "test-module"),
42+
),
43+
},
44+
{
45+
Config: testUserAgentFunctionConfig("test-module", "", "test comment"),
46+
Check: resource.ComposeAggregateTestCheckFunc(
47+
resource.TestCheckOutput("test", "test-module (test comment)"),
48+
),
49+
},
50+
},
51+
})
52+
}
53+
54+
func TestUserAgentFunction_missingName(t *testing.T) {
55+
t.Parallel()
56+
57+
resource.UnitTest(t, resource.TestCase{
58+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
59+
TerraformVersionChecks: []tfversion.TerraformVersionCheck{
60+
tfversion.SkipBelow(version.Must(version.NewVersion("1.8.0"))),
61+
},
62+
Steps: []resource.TestStep{
63+
{
64+
Config: testUserAgentFunctionConfig("", "", ""),
65+
// The full message is broken across lines, complicating validation.
66+
// Check just the start.
67+
ExpectError: regexache.MustCompile("product_name must be"),
68+
},
69+
},
70+
})
71+
}
72+
73+
func testUserAgentFunctionConfig(name, version, comment string) string {
74+
return fmt.Sprintf(`
75+
output "test" {
76+
value = provider::aws::user_agent(%[1]q, %[2]q, %[3]q)
77+
}
78+
`, name, version, comment)
79+
}

internal/provider/framework/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,7 @@ func (p *frameworkProvider) Functions(_ context.Context) []func() function.Funct
425425
tffunction.NewARNBuildFunction,
426426
tffunction.NewARNParseFunction,
427427
tffunction.NewTrimIAMRolePathFunction,
428+
tffunction.NewUserAgentFunction,
428429
}
429430
}
430431

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
---
2+
subcategory: ""
3+
layout: "aws"
4+
page_title: "AWS: user_agent"
5+
description: |-
6+
Formats a User-Agent product for use with the user_agent argument in the provider or provider_meta block..
7+
---
8+
# Function: user_agent
9+
10+
~> Provider-defined functions are supported in Terraform 1.8 and later.
11+
12+
Formats a User-Agent product for use with the user_agent argument in the provider or provider_meta block..
13+
14+
## Example Usage
15+
16+
```terraform
17+
# result: foo-bar
18+
output "example" {
19+
value = provider::aws::user_agent("foo")
20+
}
21+
```
22+
23+
## Signature
24+
25+
```text
26+
user_agent(arg string) string
27+
```
28+
29+
## Arguments
30+
31+
1. `arg` (String) Example argument description.

0 commit comments

Comments
 (0)