diff --git a/internal/provider/connection/model.go b/internal/provider/connection/model.go index 2f33acd..5055f56 100644 --- a/internal/provider/connection/model.go +++ b/internal/provider/connection/model.go @@ -46,9 +46,10 @@ type filterRuleProperty struct { } type retryRule struct { - Count types.Int64 `tfsdk:"count"` - Interval types.Int64 `tfsdk:"interval"` - Strategy types.String `tfsdk:"strategy"` + Count types.Int64 `tfsdk:"count"` + Interval types.Int64 `tfsdk:"interval"` + Strategy types.String `tfsdk:"strategy"` + ResponseStatusCodes types.List `tfsdk:"response_status_codes"` } type transformRule struct { diff --git a/internal/provider/connection/schema_v1.go b/internal/provider/connection/schema_v1.go index 1d21ff5..e53a23a 100644 --- a/internal/provider/connection/schema_v1.go +++ b/internal/provider/connection/schema_v1.go @@ -138,6 +138,11 @@ func schemaAttributesV1() map[string]schema.Attribute { MarkdownDescription: `must be one of ["linear", "exponential"]` + "\n" + `Algorithm to use when calculating delay between retries`, }, + "response_status_codes": schema.ListAttribute{ + Optional: true, + ElementType: types.StringType, + Description: `HTTP codes to retry on. Accepts: range expressions (e.g., "400-499", ">400"), specific codes (e.g., 404), and exclusions (e.g., "!401"). Example: ["500-599", ">400", 404, "!401"]`, + }, }, }, "transform_rule": schema.SingleNestedAttribute{ diff --git a/internal/provider/connection/sdk.go b/internal/provider/connection/sdk.go index 242535b..4b147e8 100644 --- a/internal/provider/connection/sdk.go +++ b/internal/provider/connection/sdk.go @@ -409,6 +409,15 @@ func rulesToAPI(ctx context.Context, rules []rule) ([]interface{}, error) { rule["interval"] = ruleItem.RetryRule.Interval.ValueInt64() } + responseStatusCodesFieldsSet := !ruleItem.RetryRule.ResponseStatusCodes.IsNull() && !ruleItem.RetryRule.ResponseStatusCodes.IsUnknown() + if responseStatusCodesFieldsSet { + responseStatusCodes := []string{} + ruleItem.RetryRule.ResponseStatusCodes.ElementsAs(ctx, &responseStatusCodes, false) + if len(responseStatusCodes) > 0 { + rule["response_status_codes"] = responseStatusCodes + } + } + result = append(result, rule) } @@ -554,6 +563,19 @@ func rulesFromAPI(rules []interface{}) []rule { } else { retryRule.Interval = types.Int64Null() } + if responseStatusCodes, ok := ruleMap["response_status_codes"].([]interface{}); ok { + statusCodeExpressions := []types.String{} + for _, expression := range responseStatusCodes { + if expressionStr, ok := expression.(string); ok { + statusCodeExpressions = append(statusCodeExpressions, types.StringValue(expressionStr)) + } + } + if len(statusCodeExpressions) > 0 { + retryRule.ResponseStatusCodes, _ = types.ListValueFrom(context.Background(), types.StringType, statusCodeExpressions) + } else { + retryRule.ResponseStatusCodes = types.ListNull(types.StringType) + } + } result = append(result, rule{RetryRule: retryRule}) diff --git a/internal/provider/connection/testdata/with_retry_rule_with_codes.tf b/internal/provider/connection/testdata/with_retry_rule_with_codes.tf new file mode 100644 index 0000000..4522fa5 --- /dev/null +++ b/internal/provider/connection/testdata/with_retry_rule_with_codes.tf @@ -0,0 +1,27 @@ +resource "hookdeck_source" "test_%[1]s" { + name = "test-source-%[1]s" +} + +resource "hookdeck_destination" "test_%[1]s" { + name = "test-destination-%[1]s" + config = jsonencode({ + url = "https://mock.hookdeck.com" + }) +} + +resource "hookdeck_connection" "test_%[1]s" { + name = "test-connection-retry-%[1]s" + source_id = hookdeck_source.test_%[1]s.id + destination_id = hookdeck_destination.test_%[1]s.id + + rules = [ + { + retry_rule = { + strategy = "exponential" + count = 5 + interval = 1000 + response_status_codes = ["500-599"] + } + } + ] +}