mirror of
https://github.com/OneUptime/oneuptime.git
synced 2026-04-06 00:32:12 +02:00
feat: Capture OpenAPI format information and preserve original values for binary fields in resource generation
This commit is contained in:
@@ -570,6 +570,7 @@ export class OpenAPIParser {
|
||||
|
||||
const prop: any = propSchema as any;
|
||||
let propType: string = prop.type || "string";
|
||||
let propFormat: string | undefined = prop.format; // Capture the format field
|
||||
let description: string = prop.description || "";
|
||||
let example: any = prop.example;
|
||||
let defaultValue: any = prop.default;
|
||||
@@ -579,6 +580,7 @@ export class OpenAPIParser {
|
||||
const resolvedProp: any = this.resolveSchemaRef(prop.$ref);
|
||||
if (resolvedProp) {
|
||||
propType = resolvedProp.type || "string";
|
||||
propFormat = resolvedProp.format || propFormat; // Also capture format from resolved refs
|
||||
description = resolvedProp.description || description;
|
||||
example = resolvedProp.example || example;
|
||||
defaultValue = resolvedProp.default || defaultValue;
|
||||
@@ -661,6 +663,7 @@ export class OpenAPIParser {
|
||||
example: example, // Extract example from OpenAPI schema
|
||||
default: defaultValue, // Extract default value from OpenAPI schema
|
||||
isComplexObject: propType === "object", // Flag to indicate this string field is actually a complex object
|
||||
...(propFormat && { format: propFormat }), // Only include format if it exists
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -592,6 +592,8 @@ func (r *${resourceTypeName}Resource) Create(ctx context.Context, req resource.C
|
||||
return
|
||||
}
|
||||
|
||||
${this.generateOriginalValueStorage(resource)}
|
||||
|
||||
// Create API request body
|
||||
${resourceVarName}Request := map[string]interface{}{
|
||||
"data": map[string]interface{}{
|
||||
@@ -614,7 +616,7 @@ ${this.generateRequestBody(resource)}
|
||||
}
|
||||
|
||||
// Update the model with response data
|
||||
${this.generateResponseMapping(resource, resourceVarName + "Response")}
|
||||
${this.generateResponseMapping(resource, resourceVarName + "Response", true)}
|
||||
|
||||
// Write logs using the tflog package
|
||||
tflog.Trace(ctx, "created a resource")
|
||||
@@ -693,7 +695,7 @@ ${this.generateSelectParameter(resource)}
|
||||
}
|
||||
|
||||
// Update the model with response data
|
||||
${this.generateResponseMapping(resource, resourceVarName + "Response")}
|
||||
${this.generateResponseMapping(resource, resourceVarName + "Response", false)}
|
||||
|
||||
// Save updated data into Terraform state
|
||||
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
|
||||
@@ -829,7 +831,7 @@ ${this.generateSelectParameter(resource)}
|
||||
}
|
||||
|
||||
// Update the model with response data from the Read operation
|
||||
${this.generateResponseMapping(resource, "readResponse")}
|
||||
${this.generateResponseMapping(resource, "readResponse", false)}
|
||||
|
||||
// Save updated data into Terraform state
|
||||
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
|
||||
@@ -1122,6 +1124,7 @@ func (r *${resourceTypeName}Resource) Delete(ctx context.Context, req resource.D
|
||||
private generateResponseMapping(
|
||||
resource: TerraformResource,
|
||||
responseVar: string,
|
||||
isCreateMethod: boolean = false,
|
||||
): string {
|
||||
const mappings: string[] = [];
|
||||
|
||||
@@ -1168,6 +1171,9 @@ func (r *${resourceTypeName}Resource) Delete(ctx context.Context, req resource.D
|
||||
`dataMap["${apiFieldName}"]`,
|
||||
attr.default !== undefined && attr.default !== null, // hasDefault
|
||||
attr.isComplexObject || false, // isComplexObject
|
||||
attr.format, // format
|
||||
isCreateMethod, // isCreateMethod
|
||||
sanitizedName, // fieldName for original value preservation
|
||||
);
|
||||
mappings.push(` ${setter}`);
|
||||
}
|
||||
@@ -1189,10 +1195,35 @@ func (r *${resourceTypeName}Resource) Delete(ctx context.Context, req resource.D
|
||||
responseValue: string,
|
||||
hasDefault: boolean = false,
|
||||
isComplexObject: boolean = false,
|
||||
format?: string,
|
||||
isCreateMethod: boolean = false,
|
||||
originalFieldName?: string,
|
||||
): string {
|
||||
|
||||
switch (terraformType) {
|
||||
case "string":
|
||||
if (isComplexObject) {
|
||||
// Handle binary format fields (like base64 file content) specially
|
||||
if (format === "binary") {
|
||||
// For binary fields, treat the response as a simple string without complex object processing
|
||||
if (isCreateMethod && originalFieldName) {
|
||||
// In Create method, preserve original value if API doesn't return the file content
|
||||
return `if val, ok := ${responseValue}.(string); ok {
|
||||
${fieldName} = types.StringValue(val)
|
||||
} else {
|
||||
// Preserve original value from the request since API doesn't return file content
|
||||
${fieldName} = types.StringValue(original${StringUtils.toPascalCase(originalFieldName)}Value)
|
||||
}`;
|
||||
} else {
|
||||
// In Read/Update methods, preserve existing value if not present in API response
|
||||
// This prevents drift detection when API doesn't return binary content
|
||||
return `if val, ok := ${responseValue}.(string); ok {
|
||||
${fieldName} = types.StringValue(val)
|
||||
} else {
|
||||
// Keep existing value to prevent drift - API doesn't return binary content
|
||||
// ${fieldName} value is already set from the existing state
|
||||
}`;
|
||||
}
|
||||
} else if (isComplexObject) {
|
||||
// For complex object strings, convert API object response to JSON string
|
||||
return `if val, ok := ${responseValue}.(map[string]interface{}); ok {
|
||||
if jsonBytes, err := json.Marshal(val); err == nil {
|
||||
@@ -1384,4 +1415,21 @@ ${resourceFunctions}
|
||||
resourceListContent,
|
||||
);
|
||||
}
|
||||
|
||||
private generateOriginalValueStorage(resource: TerraformResource): string {
|
||||
const storage: string[] = [];
|
||||
|
||||
// Find binary format fields and store their original values
|
||||
for (const [name, attr] of Object.entries(resource.schema)) {
|
||||
if (attr.format === "binary") {
|
||||
const sanitizedName: string = this.sanitizeAttributeName(name);
|
||||
const fieldName: string = StringUtils.toPascalCase(sanitizedName);
|
||||
storage.push(` // Store the original ${sanitizedName} value since API won't return it`);
|
||||
storage.push(` original${fieldName}Value := data.${fieldName}.ValueString()`);
|
||||
storage.push(``);
|
||||
}
|
||||
}
|
||||
|
||||
return storage.join("\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,6 +114,7 @@ export interface TerraformAttribute {
|
||||
apiFieldName?: string; // Original OpenAPI field name for API requests
|
||||
example?: any; // Example value from OpenAPI spec
|
||||
isComplexObject?: boolean; // Flag to indicate this string field is actually a complex object
|
||||
format?: string; // OpenAPI format information (e.g., "binary", "date-time", etc.)
|
||||
}
|
||||
|
||||
export interface GoType {
|
||||
|
||||
Reference in New Issue
Block a user