@@ -3,9 +3,9 @@ package provider
3
3
import (
4
4
"context"
5
5
"fmt"
6
+
6
7
"net/http"
7
8
"regexp"
8
- "strings"
9
9
10
10
"github.com/segmentio/terraform-provider-segment/internal/provider/docs"
11
11
"github.com/segmentio/terraform-provider-segment/internal/provider/models"
@@ -17,25 +17,10 @@ import (
17
17
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
18
18
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
19
19
"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"
22
21
"github.com/segmentio/public-api-sdk-go/api"
23
22
)
24
23
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
-
39
24
var (
40
25
_ resource.Resource = & functionResource {}
41
26
_ resource.ResourceWithConfigure = & functionResource {}
@@ -51,12 +36,14 @@ type functionResource struct {
51
36
authContext context.Context
52
37
}
53
38
39
+ func hasValue (v tftypes.String ) bool {
40
+ return ! (v .IsNull () || v .IsUnknown ())
41
+ }
42
+
54
43
func (r * functionResource ) Metadata (_ context.Context , req resource.MetadataRequest , resp * resource.MetadataResponse ) {
55
44
resp .TypeName = req .ProviderTypeName + "_function"
56
45
}
57
46
58
- /*──────────────────────────── schema ────────────────────────────*/
59
-
60
47
func (r * functionResource ) Schema (_ context.Context , _ resource.SchemaRequest , resp * resource.SchemaResponse ) {
61
48
resp .Schema = schema.Schema {
62
49
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
75
62
},
76
63
"display_name" : schema.StringAttribute {
77
64
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 ." ,
79
66
},
80
67
"logo_url" : schema.StringAttribute {
81
68
Optional : true ,
@@ -102,7 +89,7 @@ func (r *functionResource) Schema(_ context.Context, _ resource.SchemaRequest, r
102
89
},
103
90
"settings" : schema.SetNestedAttribute {
104
91
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 ." ,
106
93
NestedObject : schema.NestedAttributeObject {
107
94
Attributes : map [string ]schema.Attribute {
108
95
"name" : schema.StringAttribute {
@@ -111,26 +98,26 @@ func (r *functionResource) Schema(_ context.Context, _ resource.SchemaRequest, r
111
98
},
112
99
"label" : schema.StringAttribute {
113
100
Required : true ,
114
- Description : "The label for this Function setting ." ,
101
+ Description : "The label for this Function Setting ." ,
115
102
},
116
103
"description" : schema.StringAttribute {
117
104
Required : true ,
118
- Description : "A description of this Function setting ." ,
105
+ Description : "A description of this Function Setting ." ,
119
106
},
120
107
"type" : schema.StringAttribute {
121
108
Required : true ,
122
- Description : "The type of this Function setting ." ,
109
+ Description : "The type of this Function Setting ." ,
123
110
Validators : []validator.String {
124
111
stringvalidator .RegexMatches (regexp .MustCompile ("^[A-Z_]+$" ), "'type' must be in all uppercase" ),
125
112
},
126
113
},
127
114
"required" : schema.BoolAttribute {
128
115
Required : true ,
129
- Description : "Whether this Function setting is required." ,
116
+ Description : "Whether this Function Setting is required." ,
130
117
},
131
118
"sensitive" : schema.BoolAttribute {
132
119
Required : true ,
133
- Description : "Whether this Function setting contains sensitive information." ,
120
+ Description : "Whether this Function Setting contains sensitive information." ,
134
121
},
135
122
},
136
123
},
@@ -139,8 +126,6 @@ func (r *functionResource) Schema(_ context.Context, _ resource.SchemaRequest, r
139
126
}
140
127
}
141
128
142
- /*──────────────────────────── CREATE ────────────────────────────*/
143
-
144
129
func (r * functionResource ) Create (ctx context.Context , req resource.CreateRequest , resp * resource.CreateResponse ) {
145
130
var plan models.FunctionPlan
146
131
diags := req .Plan .Get (ctx , & plan )
@@ -167,7 +152,11 @@ func (r *functionResource) Create(ctx context.Context, req resource.CreateReques
167
152
defer body .Body .Close ()
168
153
}
169
154
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
+
171
160
return
172
161
}
173
162
@@ -178,18 +167,24 @@ func (r *functionResource) Create(ctx context.Context, req resource.CreateReques
178
167
var state models.FunctionState
179
168
state .Fill (function )
180
169
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
+ }
183
174
184
- diags = resp .State .Set (ctx , & state )
175
+ // Set state to fully populated data
176
+ diags = resp .State .Set (ctx , state )
185
177
resp .Diagnostics .Append (diags ... )
178
+ if resp .Diagnostics .HasError () {
179
+ return
180
+ }
186
181
}
187
182
188
- /*──────────────────────────── READ ───────────────────────────────*/
189
-
190
183
func (r * functionResource ) Read (ctx context.Context , req resource.ReadRequest , resp * resource.ReadResponse ) {
191
184
var previousState models.FunctionState
185
+
192
186
diags := req .State .Get (ctx , & previousState )
187
+
193
188
resp .Diagnostics .Append (diags ... )
194
189
if resp .Diagnostics .HasError () {
195
190
return
@@ -202,26 +197,35 @@ func (r *functionResource) Read(ctx context.Context, req resource.ReadRequest, r
202
197
if err != nil {
203
198
if body .StatusCode == http .StatusNotFound {
204
199
resp .State .RemoveResource (ctx )
200
+
205
201
return
206
202
}
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
+
208
209
return
209
210
}
210
211
211
212
var state models.FunctionState
212
- state .Fill (response .Data .GetFunction ())
213
213
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
217
220
}
218
221
219
222
diags = resp .State .Set (ctx , & state )
220
223
resp .Diagnostics .Append (diags ... )
224
+ if resp .Diagnostics .HasError () {
225
+ return
226
+ }
221
227
}
222
228
223
- /*──────────────────────────── UPDATE ────────────────────────────*/
224
-
225
229
func (r * functionResource ) Update (ctx context.Context , req resource.UpdateRequest , resp * resource.UpdateResponse ) {
226
230
var plan models.FunctionPlan
227
231
diags := req .Plan .Get (ctx , & plan )
@@ -254,22 +258,30 @@ func (r *functionResource) Update(ctx context.Context, req resource.UpdateReques
254
258
defer body .Body .Close ()
255
259
}
256
260
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
+
258
266
return
259
267
}
260
268
261
- state .Fill (out .Data .GetFunction ())
269
+ function := out .Data .GetFunction ()
270
+
271
+ state .Fill (function )
262
272
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
265
276
}
266
277
267
278
diags = resp .State .Set (ctx , & state )
268
279
resp .Diagnostics .Append (diags ... )
280
+ if resp .Diagnostics .HasError () {
281
+ return
282
+ }
269
283
}
270
284
271
- /*──────────────────────────── DELETE ────────────────────────────*/
272
-
273
285
func (r * functionResource ) Delete (ctx context.Context , req resource.DeleteRequest , resp * resource.DeleteResponse ) {
274
286
var config models.FunctionState
275
287
diags := req .State .Get (ctx , & config )
@@ -283,30 +295,35 @@ func (r *functionResource) Delete(ctx context.Context, req resource.DeleteReques
283
295
defer body .Body .Close ()
284
296
}
285
297
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
287
304
}
288
305
}
289
306
290
- /*──────────────────────────── IMPORT ────────────────────────────*/
291
-
292
307
func (r * functionResource ) ImportState (ctx context.Context , req resource.ImportStateRequest , resp * resource.ImportStateResponse ) {
308
+ // Retrieve import ID and save to id attribute
293
309
resource .ImportStatePassthroughID (ctx , path .Root ("id" ), req , resp )
294
310
}
295
311
296
- /*──────────────────────────── CONFIGURE ─────────────────────────*/
297
-
298
312
func (r * functionResource ) Configure (_ context.Context , req resource.ConfigureRequest , resp * resource.ConfigureResponse ) {
299
313
if req .ProviderData == nil {
300
314
return
301
315
}
316
+
302
317
config , ok := req .ProviderData .(* ClientInfo )
303
318
if ! ok {
304
319
resp .Diagnostics .AddError (
305
320
"Unexpected Resource Configure Type" ,
306
321
fmt .Sprintf ("Expected ClientInfo, got: %T. Please report this issue to the provider developers." , req .ProviderData ),
307
322
)
323
+
308
324
return
309
325
}
326
+
310
327
r .client = config .client
311
328
r .authContext = config .authContext
312
329
}
0 commit comments