Skip to content

Commit cac499a

Browse files
committed
r/group_raw: add planmodifier on config to
remove blank lines in the value
1 parent 5550523 commit cac499a

File tree

3 files changed

+171
-0
lines changed

3 files changed

+171
-0
lines changed

internal/provider/resource_group_raw.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77

88
"github.com/jeremmfr/terraform-provider-junos/internal/junos"
99
"github.com/jeremmfr/terraform-provider-junos/internal/tfdiag"
10+
"github.com/jeremmfr/terraform-provider-junos/internal/tfplanmodifier"
1011
"github.com/jeremmfr/terraform-provider-junos/internal/tfvalidator"
1112

1213
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
@@ -97,6 +98,9 @@ func (rsc *groupRaw) Schema(
9798
"config": schema.StringAttribute{
9899
Required: true,
99100
Description: "The raw configuration to load.",
101+
PlanModifiers: []planmodifier.String{
102+
tfplanmodifier.StringRemoveBlankLines(),
103+
},
100104
Validators: []validator.String{
101105
stringvalidator.LengthAtLeast(1),
102106
},

internal/tfplanmodifier/string.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ package tfplanmodifier
22

33
import (
44
"context"
5+
"strings"
56

67
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
8+
"github.com/hashicorp/terraform-plugin-framework/types"
79
)
810

911
// StringUseStateNullForUnknown returns a plan modifier that copies a null prior state
@@ -45,3 +47,50 @@ func (m stringUseStateNullForUnknownModifier) PlanModifyString(
4547

4648
resp.PlanValue = req.StateValue
4749
}
50+
51+
// StringRemoveBlankLines returns a plan modifier that removes all blank lines
52+
// (empty lines and lines containing only whitespace) from multiline string values.
53+
func StringRemoveBlankLines() planmodifier.String {
54+
return stringRemoveBlankLines{}
55+
}
56+
57+
type stringRemoveBlankLines struct{}
58+
59+
func (m stringRemoveBlankLines) Description(_ context.Context) string {
60+
return "Removes blank lines (empty lines and lines containing only whitespace) from multiline strings."
61+
}
62+
63+
func (m stringRemoveBlankLines) MarkdownDescription(_ context.Context) string {
64+
return "Removes blank lines (empty lines and lines containing only whitespace) from multiline strings."
65+
}
66+
67+
// PlanModifyString implements the plan modification logic.
68+
func (m stringRemoveBlankLines) PlanModifyString(
69+
_ context.Context, req planmodifier.StringRequest, resp *planmodifier.StringResponse,
70+
) {
71+
// Do nothing if there is a null planned value.
72+
if req.PlanValue.IsNull() {
73+
return
74+
}
75+
76+
// Do nothing if there is an unknown planned value.
77+
if req.PlanValue.IsUnknown() {
78+
return
79+
}
80+
81+
// Do nothing if value doesn't have multiple lines.
82+
if !strings.Contains(req.PlanValue.ValueString(), "\n") {
83+
return
84+
}
85+
86+
newValue := strings.Builder{}
87+
for item := range strings.SplitSeq(req.PlanValue.ValueString(), "\n") {
88+
if strings.TrimSpace(item) == "" {
89+
continue
90+
}
91+
92+
_, _ = newValue.WriteString(item + "\n")
93+
}
94+
95+
resp.PlanValue = types.StringValue(newValue.String())
96+
}
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
package tfplanmodifier_test
2+
3+
import (
4+
"context"
5+
"reflect"
6+
"testing"
7+
8+
"github.com/jeremmfr/terraform-provider-junos/internal/tfplanmodifier"
9+
10+
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
11+
"github.com/hashicorp/terraform-plugin-framework/types"
12+
)
13+
14+
func TestStringRemoveBlankLines(t *testing.T) {
15+
t.Parallel()
16+
17+
testCases := map[string]struct {
18+
request planmodifier.StringRequest
19+
expected *planmodifier.StringResponse
20+
}{
21+
"null value": {
22+
request: planmodifier.StringRequest{
23+
PlanValue: types.StringNull(),
24+
},
25+
expected: &planmodifier.StringResponse{
26+
PlanValue: types.StringNull(),
27+
},
28+
},
29+
"unknown value": {
30+
request: planmodifier.StringRequest{
31+
PlanValue: types.StringUnknown(),
32+
},
33+
expected: &planmodifier.StringResponse{
34+
PlanValue: types.StringUnknown(),
35+
},
36+
},
37+
"single line without newline": {
38+
request: planmodifier.StringRequest{
39+
PlanValue: types.StringValue("single line"),
40+
},
41+
expected: &planmodifier.StringResponse{
42+
PlanValue: types.StringValue("single line"),
43+
},
44+
},
45+
"multiline with blank lines": {
46+
request: planmodifier.StringRequest{
47+
PlanValue: types.StringValue("line1\n\nline2\n\nline3\n"),
48+
},
49+
expected: &planmodifier.StringResponse{
50+
PlanValue: types.StringValue("line1\nline2\nline3\n"),
51+
},
52+
},
53+
"multiline with only spaces": {
54+
request: planmodifier.StringRequest{
55+
PlanValue: types.StringValue("line1\n \nline2\n \nline3\n"),
56+
},
57+
expected: &planmodifier.StringResponse{
58+
PlanValue: types.StringValue("line1\nline2\nline3\n"),
59+
},
60+
},
61+
"multiline with tabs and spaces": {
62+
request: planmodifier.StringRequest{
63+
PlanValue: types.StringValue("line1\n\t \t\nline2\n \t \nline3\n"),
64+
},
65+
expected: &planmodifier.StringResponse{
66+
PlanValue: types.StringValue("line1\nline2\nline3\n"),
67+
},
68+
},
69+
"all blank lines": {
70+
request: planmodifier.StringRequest{
71+
PlanValue: types.StringValue("\n\n \n\t\n"),
72+
},
73+
expected: &planmodifier.StringResponse{
74+
PlanValue: types.StringValue(""),
75+
},
76+
},
77+
"no blank lines": {
78+
request: planmodifier.StringRequest{
79+
PlanValue: types.StringValue("line1\nline2\nline3\n"),
80+
},
81+
expected: &planmodifier.StringResponse{
82+
PlanValue: types.StringValue("line1\nline2\nline3\n"),
83+
},
84+
},
85+
"preserve indentation": {
86+
request: planmodifier.StringRequest{
87+
PlanValue: types.StringValue(" line1\n\n line2\n"),
88+
},
89+
expected: &planmodifier.StringResponse{
90+
PlanValue: types.StringValue(" line1\n line2\n"),
91+
},
92+
},
93+
"empty string": {
94+
request: planmodifier.StringRequest{
95+
PlanValue: types.StringValue(""),
96+
},
97+
expected: &planmodifier.StringResponse{
98+
PlanValue: types.StringValue(""),
99+
},
100+
},
101+
}
102+
103+
for name, testCase := range testCases {
104+
t.Run(name, func(t *testing.T) {
105+
t.Parallel()
106+
107+
resp := &planmodifier.StringResponse{
108+
PlanValue: testCase.request.PlanValue,
109+
}
110+
111+
tfplanmodifier.StringRemoveBlankLines().PlanModifyString(context.Background(), testCase.request, resp)
112+
113+
if !reflect.DeepEqual(testCase.expected, resp) {
114+
t.Errorf("unexpected StringResponse: want %#v, got %#v", testCase.expected, resp)
115+
}
116+
})
117+
}
118+
}

0 commit comments

Comments
 (0)