Skip to content
This repository was archived by the owner on Dec 27, 2024. It is now read-only.

Commit b3bba56

Browse files
authored
feat: add stringvalidator/PrefixContains (#77)
1 parent 57aa664 commit b3bba56

File tree

7 files changed

+268
-0
lines changed

7 files changed

+268
-0
lines changed

.changelog/76.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:feature
2+
`stringvalidator/PrefixContains` - Check if the string contains the prefix.
3+
```

.vscode/terraform.code-snippets

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
{
2+
"Release Note Breaking change": {
3+
"scope": "plaintext",
4+
"prefix": "release-note-breaking-change",
5+
"body": [
6+
"```release-note:breaking-change",
7+
"`resource/cloudavenue_xx` - Short Description.",
8+
"`datasource/cloudavenue_xx` - Short Description.",
9+
"```"
10+
]
11+
},
12+
"Release Note New stringvalidator": {
13+
"scope": "plaintext",
14+
"prefix": "release-note-new-stringvalidator",
15+
"body": [
16+
"```release-note:feature",
17+
"`stringvalidator/xxx` - Short Description.",
18+
"```"
19+
]
20+
},
21+
"Release Note New boolvalidator": {
22+
"scope": "plaintext",
23+
"prefix": "release-note-new-boolvalidator",
24+
"body": [
25+
"```release-note:feature",
26+
"`boolvalidator/xxx` - Short Description.",
27+
"```"
28+
]
29+
},
30+
"Release Note New int64validator": {
31+
"scope": "plaintext",
32+
"prefix": "release-note-new-intvalidator",
33+
"body": [
34+
"```release-note:feature",
35+
"`intvalidator/xxx` - Short Description.",
36+
"```"
37+
]
38+
},
39+
"Release Note New float64validator": {
40+
"scope": "plaintext",
41+
"prefix": "release-note-new-floatvalidator",
42+
"body": [
43+
"```release-note:feature",
44+
"`floatvalidator/xxx` - Short Description.",
45+
"```"
46+
]
47+
},
48+
"Release Note New listvalidator": {
49+
"scope": "plaintext",
50+
"prefix": "release-note-new-listvalidator",
51+
"body": [
52+
"```release-note:feature",
53+
"`listvalidator/xxx` - Short Description.",
54+
"```"
55+
]
56+
},
57+
"Release Note New mapvalidator": {
58+
"scope": "plaintext",
59+
"prefix": "release-note-new-mapvalidator",
60+
"body": [
61+
"```release-note:feature",
62+
"`mapvalidator/xxx` - Short Description.",
63+
"```"
64+
]
65+
},
66+
"Release Note New setvalidator": {
67+
"scope": "plaintext",
68+
"prefix": "release-note-new-setvalidator",
69+
"body": [
70+
"```release-note:feature",
71+
"`setvalidator/xxx` - Short Description.",
72+
"```"
73+
]
74+
},
75+
// Release note feature
76+
"Release Note New Feature": {
77+
"scope": "plaintext",
78+
"prefix": "release-note-feature",
79+
"body": [
80+
"```release-note:feature",
81+
"`resource/cloudavenue_xx` - Short Description.",
82+
"`datasource/cloudavenue_xx` - Short Description.",
83+
"```"
84+
]
85+
},
86+
// Release note bug
87+
"Release Note Bug": {
88+
"scope": "plaintext",
89+
"prefix": "release-note-bug",
90+
"body": [
91+
"```release-note:bug",
92+
"`resource/cloudavenue_xx` - Short Description.",
93+
"`datasource/cloudavenue_xx` - Short Description.",
94+
"```"
95+
]
96+
},
97+
// Release note Note
98+
"Release Note Note": {
99+
"scope": "plaintext",
100+
"prefix": "release-note-note",
101+
"body": [
102+
"```release-note:note",
103+
"`resource/cloudavenue_xx` - Short Description.",
104+
"`datasource/cloudavenue_xx` - Short Description.",
105+
"```"
106+
]
107+
},
108+
// Release note enchancement
109+
"Release Note Enhancement": {
110+
"scope": "plaintext",
111+
"prefix": "release-note-enhancement",
112+
"body": [
113+
"```release-note:enhancement",
114+
"`resource/cloudavenue_xx` - Short Description.",
115+
"`datasource/cloudavenue_xx` - Short Description.",
116+
"```"
117+
]
118+
},
119+
}

docs/stringvalidator/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727

2828
- [`IsURN`](isurn.md) - This validator is used to check if the string is a valid URN.
2929
- [`IsUUID`](isuuid.md) - This validator is used to check if the string is a valid UUID.
30+
- [`PrefixContains`](prefixcontains.md) - This validator is used to check if the string contains prefix in the given value.
3031

3132
### Special
3233

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# `PrefixContains`
2+
3+
!!! quote inline end "Released in v1.7.0"
4+
5+
This validator is used to check if the string contains prefix in the given value.
6+
7+
## How to use it
8+
9+
```go
10+
// Schema defines the schema for the resource.
11+
func (r *xResource) Schema(ctx context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
12+
resp.Schema = schema.Schema{
13+
(...)
14+
"interface_type": schema.StringAttribute{
15+
Optional: true,
16+
MarkdownDescription: "Type of ...",
17+
Validators: []validator.String{
18+
fstringvalidator.PrefixContains("urn:test:demo:")
19+
},
20+
},
21+
```
22+
23+
## Description and Markdown description
24+
25+
* **Description:**
26+
must start with "urn:test:demo:"
27+
* **Markdown description:**
28+
This value must start with `urn:test:demo:`.
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package common
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"strings"
7+
8+
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
9+
)
10+
11+
var _ validator.String = PrefixValidator{}
12+
13+
type PrefixValidator struct {
14+
Prefix string
15+
}
16+
17+
// Description describes the validation in plain text formatting.
18+
func (validator PrefixValidator) Description(_ context.Context) string {
19+
return fmt.Sprintf("must start with \"%s\"", validator.Prefix)
20+
}
21+
22+
// MarkdownDescription describes the validation in Markdown formatting.
23+
func (validator PrefixValidator) MarkdownDescription(_ context.Context) string {
24+
return fmt.Sprintf("This value must start with `%s`.", validator.Prefix)
25+
}
26+
27+
// Validate performs the validation.
28+
func (validator PrefixValidator) ValidateString(_ context.Context, request validator.StringRequest, response *validator.StringResponse) {
29+
if request.ConfigValue.IsNull() || request.ConfigValue.IsUnknown() {
30+
return
31+
}
32+
33+
if !strings.HasPrefix(request.ConfigValue.ValueString(), validator.Prefix) {
34+
response.Diagnostics.AddAttributeError(
35+
request.Path,
36+
"Does not start with prefix",
37+
fmt.Sprintf("The value %s does not start with the prefix \"%s\".", request.ConfigValue.String(), validator.Prefix),
38+
)
39+
}
40+
}

stringvalidator/prefix.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package stringvalidator
2+
3+
import (
4+
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
5+
6+
"github.com/FrangipaneTeam/terraform-plugin-framework-validators/stringvalidator/common"
7+
)
8+
9+
// PrefixContainsValidator is a validator which ensures that the configured attribute
10+
// value contains the specified prefix.
11+
//
12+
// Null (unconfigured) and unknown (known after apply) values are skipped.
13+
func PrefixContains(prefix string) validator.String {
14+
return &common.PrefixValidator{
15+
Prefix: prefix,
16+
}
17+
}

stringvalidator/prefix_test.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package stringvalidator_test
2+
3+
import (
4+
"context"
5+
"testing"
6+
7+
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
8+
"github.com/hashicorp/terraform-plugin-framework/types"
9+
10+
"github.com/FrangipaneTeam/terraform-plugin-framework-validators/stringvalidator"
11+
)
12+
13+
func TestPrefixContainsValidator(t *testing.T) {
14+
t.Parallel()
15+
16+
type testCase struct {
17+
val types.String
18+
expectError bool
19+
}
20+
tests := map[string]testCase{
21+
"unknown": {
22+
val: types.StringUnknown(),
23+
},
24+
"null": {
25+
val: types.StringNull(),
26+
},
27+
"valid": {
28+
val: types.StringValue("urn:test:demo:4aeb40d8-038c-4e77-8181-a7054f583b12"),
29+
},
30+
"invalid": {
31+
val: types.StringValue("4aeb40d8-038c-4e77-8181-a7054f583b12"),
32+
expectError: true,
33+
},
34+
"multiple byte characters": {
35+
// Rightwards Arrow Over Leftwards Arrow (U+21C4; 3 bytes)
36+
val: types.StringValue("⇄"),
37+
expectError: true,
38+
},
39+
}
40+
41+
for name, test := range tests {
42+
name, test := name, test
43+
t.Run(name, func(t *testing.T) {
44+
t.Parallel()
45+
request := validator.StringRequest{
46+
ConfigValue: test.val,
47+
}
48+
response := validator.StringResponse{}
49+
stringvalidator.PrefixContains("urn:test:demo:").ValidateString(context.TODO(), request, &response)
50+
51+
if !response.Diagnostics.HasError() && test.expectError {
52+
t.Fatal("expected error, got no error")
53+
}
54+
55+
if response.Diagnostics.HasError() && !test.expectError {
56+
t.Fatalf("got unexpected error: %s", response.Diagnostics)
57+
}
58+
})
59+
}
60+
}

0 commit comments

Comments
 (0)