Skip to content

Commit 3bc01ca

Browse files
committed
display name checking
1 parent 8b5ffeb commit 3bc01ca

File tree

1 file changed

+69
-52
lines changed

1 file changed

+69
-52
lines changed

internal/provider/function_resource.go

Lines changed: 69 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ package provider
33
import (
44
"context"
55
"fmt"
6+
67
"net/http"
78
"regexp"
8-
"strings"
99

1010
"github.com/segmentio/terraform-provider-segment/internal/provider/docs"
1111
"github.com/segmentio/terraform-provider-segment/internal/provider/models"
@@ -17,25 +17,10 @@ import (
1717
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
1818
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
1919
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
20-
"github.com/hashicorp/terraform-plugin-framework/types"
21-
20+
tftypes "github.com/hashicorp/terraform-plugin-framework/types"
2221
"github.com/segmentio/public-api-sdk-go/api"
2322
)
2423

25-
/*──────────────────────────── helper ────────────────────────────*/
26-
27-
// Matches "<name> (workspace-slug)" and returns "<name>"
28-
var wsSuffix = regexp.MustCompile(`^(.*) [^)]+$`)
29-
30-
func stripWorkspaceSuffix(name string) string {
31-
if m := wsSuffix.FindStringSubmatch(name); m != nil {
32-
return strings.TrimSpace(m[1])
33-
}
34-
return name
35-
}
36-
37-
/*──────────────────────────── resource boilerplate ──────────────*/
38-
3924
var (
4025
_ resource.Resource = &functionResource{}
4126
_ resource.ResourceWithConfigure = &functionResource{}
@@ -51,12 +36,14 @@ type functionResource struct {
5136
authContext context.Context
5237
}
5338

39+
func hasValue(v tftypes.String) bool {
40+
return !(v.IsNull() || v.IsUnknown())
41+
}
42+
5443
func (r *functionResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
5544
resp.TypeName = req.ProviderTypeName + "_function"
5645
}
5746

58-
/*──────────────────────────── schema ────────────────────────────*/
59-
6047
func (r *functionResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
6148
resp.Schema = schema.Schema{
6249
Description: "Configures a Function. For more information, visit the [Segment docs](https://segment.com/docs/connections/functions/).\n\n" +
@@ -75,7 +62,7 @@ func (r *functionResource) Schema(_ context.Context, _ resource.SchemaRequest, r
7562
},
7663
"display_name": schema.StringAttribute{
7764
Optional: true,
78-
Description: "A display name for this Function (alphanumeric + spaces).",
65+
Description: "A display name for this Function. Destination Functions append the Workspace to the display name, but this is omitted from the Terraform output for consistency purposes.",
7966
},
8067
"logo_url": schema.StringAttribute{
8168
Optional: true,
@@ -102,7 +89,7 @@ func (r *functionResource) Schema(_ context.Context, _ resource.SchemaRequest, r
10289
},
10390
"settings": schema.SetNestedAttribute{
10491
Optional: true,
105-
Description: "Settings associated with this Function.",
92+
Description: "The settings associated with this Function. Common settings are connection-related configuration used to connect to it, for example host, username, and port.",
10693
NestedObject: schema.NestedAttributeObject{
10794
Attributes: map[string]schema.Attribute{
10895
"name": schema.StringAttribute{
@@ -111,26 +98,26 @@ func (r *functionResource) Schema(_ context.Context, _ resource.SchemaRequest, r
11198
},
11299
"label": schema.StringAttribute{
113100
Required: true,
114-
Description: "The label for this Function setting.",
101+
Description: "The label for this Function Setting.",
115102
},
116103
"description": schema.StringAttribute{
117104
Required: true,
118-
Description: "A description of this Function setting.",
105+
Description: "A description of this Function Setting.",
119106
},
120107
"type": schema.StringAttribute{
121108
Required: true,
122-
Description: "The type of this Function setting.",
109+
Description: "The type of this Function Setting.",
123110
Validators: []validator.String{
124111
stringvalidator.RegexMatches(regexp.MustCompile("^[A-Z_]+$"), "'type' must be in all uppercase"),
125112
},
126113
},
127114
"required": schema.BoolAttribute{
128115
Required: true,
129-
Description: "Whether this Function setting is required.",
116+
Description: "Whether this Function Setting is required.",
130117
},
131118
"sensitive": schema.BoolAttribute{
132119
Required: true,
133-
Description: "Whether this Function setting contains sensitive information.",
120+
Description: "Whether this Function Setting contains sensitive information.",
134121
},
135122
},
136123
},
@@ -139,8 +126,6 @@ func (r *functionResource) Schema(_ context.Context, _ resource.SchemaRequest, r
139126
}
140127
}
141128

142-
/*──────────────────────────── CREATE ────────────────────────────*/
143-
144129
func (r *functionResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
145130
var plan models.FunctionPlan
146131
diags := req.Plan.Get(ctx, &plan)
@@ -167,7 +152,11 @@ func (r *functionResource) Create(ctx context.Context, req resource.CreateReques
167152
defer body.Body.Close()
168153
}
169154
if err != nil {
170-
resp.Diagnostics.AddError("Unable to create Function", getError(err, body))
155+
resp.Diagnostics.AddError(
156+
"Unable to create Function",
157+
getError(err, body),
158+
)
159+
171160
return
172161
}
173162

@@ -178,18 +167,24 @@ func (r *functionResource) Create(ctx context.Context, req resource.CreateReques
178167
var state models.FunctionState
179168
state.Fill(function)
180169

181-
// Always normalise the name for workspace-scoped types
182-
state.DisplayName = types.StringValue(stripWorkspaceSuffix(state.DisplayName.ValueString()))
170+
// Destination functions append workspace name to display name causing inconsistency
171+
if state.ResourceType.ValueString() == "DESTINATION" || state.ResourceType.ValueString() == "INSERT_DESTINATION" || state.ResourceType.ValueString() == "INSERT_SOURCE" {
172+
state.DisplayName = plan.DisplayName
173+
}
183174

184-
diags = resp.State.Set(ctx, &state)
175+
// Set state to fully populated data
176+
diags = resp.State.Set(ctx, state)
185177
resp.Diagnostics.Append(diags...)
178+
if resp.Diagnostics.HasError() {
179+
return
180+
}
186181
}
187182

188-
/*──────────────────────────── READ ───────────────────────────────*/
189-
190183
func (r *functionResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
191184
var previousState models.FunctionState
185+
192186
diags := req.State.Get(ctx, &previousState)
187+
193188
resp.Diagnostics.Append(diags...)
194189
if resp.Diagnostics.HasError() {
195190
return
@@ -202,26 +197,35 @@ func (r *functionResource) Read(ctx context.Context, req resource.ReadRequest, r
202197
if err != nil {
203198
if body.StatusCode == http.StatusNotFound {
204199
resp.State.RemoveResource(ctx)
200+
205201
return
206202
}
207-
resp.Diagnostics.AddError(fmt.Sprintf("Unable to read Function (ID: %s)", previousState.ID.ValueString()), getError(err, body))
203+
204+
resp.Diagnostics.AddError(
205+
fmt.Sprintf("Unable to read Function (ID: %s)", previousState.ID.ValueString()),
206+
getError(err, body),
207+
)
208+
208209
return
209210
}
210211

211212
var state models.FunctionState
212-
state.Fill(response.Data.GetFunction())
213213

214-
// normalise if necessary
215-
if rt := state.ResourceType.ValueString(); rt == "DESTINATION" || rt == "INSERT_DESTINATION" || rt == "INSERT_SOURCE" {
216-
state.DisplayName = types.StringValue(stripWorkspaceSuffix(state.DisplayName.ValueString()))
214+
function := response.Data.GetFunction()
215+
state.Fill(function)
216+
217+
// Destination functions append workspace name to display name causing inconsistency
218+
if state.ResourceType.ValueString() == "DESTINATION" || state.ResourceType.ValueString() == "INSERT_DESTINATION" || state.ResourceType.ValueString() == "INSERT_SOURCE" && hasValue(previousState.DisplayName) {
219+
state.DisplayName = previousState.DisplayName
217220
}
218221

219222
diags = resp.State.Set(ctx, &state)
220223
resp.Diagnostics.Append(diags...)
224+
if resp.Diagnostics.HasError() {
225+
return
226+
}
221227
}
222228

223-
/*──────────────────────────── UPDATE ────────────────────────────*/
224-
225229
func (r *functionResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
226230
var plan models.FunctionPlan
227231
diags := req.Plan.Get(ctx, &plan)
@@ -254,22 +258,30 @@ func (r *functionResource) Update(ctx context.Context, req resource.UpdateReques
254258
defer body.Body.Close()
255259
}
256260
if err != nil {
257-
resp.Diagnostics.AddError(fmt.Sprintf("Unable to update Function (ID: %s)", plan.ID.ValueString()), getError(err, body))
261+
resp.Diagnostics.AddError(
262+
fmt.Sprintf("Unable to update Function (ID: %s)", plan.ID.ValueString()),
263+
getError(err, body),
264+
)
265+
258266
return
259267
}
260268

261-
state.Fill(out.Data.GetFunction())
269+
function := out.Data.GetFunction()
270+
271+
state.Fill(function)
262272

263-
if rt := state.ResourceType.ValueString(); rt == "DESTINATION" || rt == "INSERT_DESTINATION" || rt == "INSERT_SOURCE" {
264-
state.DisplayName = types.StringValue(stripWorkspaceSuffix(state.DisplayName.ValueString()))
273+
// Destination functions append workspace name to display name causing inconsistency
274+
if state.ResourceType.ValueString() == "DESTINATION" || state.ResourceType.ValueString() == "INSERT_DESTINATION" || state.ResourceType.ValueString() == "INSERT_SOURCE" {
275+
state.DisplayName = plan.DisplayName
265276
}
266277

267278
diags = resp.State.Set(ctx, &state)
268279
resp.Diagnostics.Append(diags...)
280+
if resp.Diagnostics.HasError() {
281+
return
282+
}
269283
}
270284

271-
/*──────────────────────────── DELETE ────────────────────────────*/
272-
273285
func (r *functionResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
274286
var config models.FunctionState
275287
diags := req.State.Get(ctx, &config)
@@ -283,30 +295,35 @@ func (r *functionResource) Delete(ctx context.Context, req resource.DeleteReques
283295
defer body.Body.Close()
284296
}
285297
if err != nil {
286-
resp.Diagnostics.AddError(fmt.Sprintf("Unable to delete Function (ID: %s)", config.ID.ValueString()), getError(err, body))
298+
resp.Diagnostics.AddError(
299+
fmt.Sprintf("Unable to delete Function (ID: %s)", config.ID.ValueString()),
300+
getError(err, body),
301+
)
302+
303+
return
287304
}
288305
}
289306

290-
/*──────────────────────────── IMPORT ────────────────────────────*/
291-
292307
func (r *functionResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
308+
// Retrieve import ID and save to id attribute
293309
resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
294310
}
295311

296-
/*──────────────────────────── CONFIGURE ─────────────────────────*/
297-
298312
func (r *functionResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
299313
if req.ProviderData == nil {
300314
return
301315
}
316+
302317
config, ok := req.ProviderData.(*ClientInfo)
303318
if !ok {
304319
resp.Diagnostics.AddError(
305320
"Unexpected Resource Configure Type",
306321
fmt.Sprintf("Expected ClientInfo, got: %T. Please report this issue to the provider developers.", req.ProviderData),
307322
)
323+
308324
return
309325
}
326+
310327
r.client = config.client
311328
r.authContext = config.authContext
312329
}

0 commit comments

Comments
 (0)