mirror of
https://github.com/opentofu/opentofu.git
synced 2025-02-25 18:45:20 -06:00
MakeStaticTimestampFunc now returns unknown value if the given time.Time is zero (#2413)
Signed-off-by: yottta <andpectech@gmail.com> Co-authored-by: yottta <andpectech@gmail.com>
This commit is contained in:
parent
f5eac16b00
commit
8fe739dc83
@ -22,6 +22,7 @@ BUG FIXES:
|
|||||||
- When assigning an empty map to a variable that is declared as a map of an object type with at least one optional attribute, OpenTofu will no longer create a subtly-broken value. ([#2371](https://github.com/opentofu/opentofu/pull/2371))
|
- When assigning an empty map to a variable that is declared as a map of an object type with at least one optional attribute, OpenTofu will no longer create a subtly-broken value. ([#2371](https://github.com/opentofu/opentofu/pull/2371))
|
||||||
- The `format` and `formatlist` functions can now accept `null` as one of the arguments without causing problems during the apply phase. Previously these functions would incorrectly return an unknown value when given `null` and so could cause a failure during the apply phase where no unknown values are allowed. ([#2371](https://github.com/opentofu/opentofu/pull/2371))
|
- The `format` and `formatlist` functions can now accept `null` as one of the arguments without causing problems during the apply phase. Previously these functions would incorrectly return an unknown value when given `null` and so could cause a failure during the apply phase where no unknown values are allowed. ([#2371](https://github.com/opentofu/opentofu/pull/2371))
|
||||||
- Provider used in import is correctly identified. ([#2336](https://github.com/opentofu/opentofu/pull/2336))
|
- Provider used in import is correctly identified. ([#2336](https://github.com/opentofu/opentofu/pull/2336))
|
||||||
|
- `plantimestamp()` now returns unknown value during validation ([#2397](https://github.com/opentofu/opentofu/issues/2397))
|
||||||
|
|
||||||
## Previous Releases
|
## Previous Releases
|
||||||
|
|
||||||
|
@ -30,6 +30,11 @@ func MakeStaticTimestampFunc(static time.Time) function.Function {
|
|||||||
Params: []function.Parameter{},
|
Params: []function.Parameter{},
|
||||||
Type: function.StaticReturnType(cty.String),
|
Type: function.StaticReturnType(cty.String),
|
||||||
Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
|
Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
|
||||||
|
// During validation phase, the planTimestamp is zero. By returning unknown value, it's forcing the
|
||||||
|
// HCL parser to skip any evaluation of other expressions that could use this.
|
||||||
|
if static.IsZero() {
|
||||||
|
return cty.UnknownVal(cty.String), nil
|
||||||
|
}
|
||||||
return cty.StringVal(static.Format(time.RFC3339)), nil
|
return cty.StringVal(static.Format(time.RFC3339)), nil
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -185,3 +185,49 @@ func TestTimeCmp(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMakeStaticTimestampFunc(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
Name string
|
||||||
|
// Setup made like this to bind the generated time value to the wanted value.
|
||||||
|
Setup func() (time.Time, cty.Value)
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
Name: "zero",
|
||||||
|
Setup: func() (time.Time, cty.Value) {
|
||||||
|
in := time.Time{}
|
||||||
|
out := cty.UnknownVal(cty.String)
|
||||||
|
return in, out
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "now",
|
||||||
|
Setup: func() (time.Time, cty.Value) {
|
||||||
|
in := time.Now()
|
||||||
|
out := cty.StringVal(in.Format(time.RFC3339))
|
||||||
|
return in, out
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "one year later",
|
||||||
|
Setup: func() (time.Time, cty.Value) {
|
||||||
|
in := time.Now().Add(8766 * time.Hour) // 1 year later
|
||||||
|
out := cty.StringVal(in.Format(time.RFC3339))
|
||||||
|
return in, out
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(fmt.Sprintf("MakeStaticTimestampFunc(%s)", test.Name), func(t *testing.T) {
|
||||||
|
in, want := test.Setup()
|
||||||
|
got, err := MakeStaticTimestampFunc(in).Call(nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("MakeStaticTimestampFunc is not meant to return error but got one: %v", err)
|
||||||
|
}
|
||||||
|
if !got.RawEquals(want) {
|
||||||
|
t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -2488,3 +2488,21 @@ locals {
|
|||||||
t.Fatalf("expected deprecated warning, got: %q\n", warn)
|
t.Fatalf("expected deprecated warning, got: %q\n", warn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ensure that the plantimestamp() call is not affecting the validation step.
|
||||||
|
func TestContext2Validate_rangeOverZeroPlanTimestamp(t *testing.T) {
|
||||||
|
p := testProvider("test")
|
||||||
|
|
||||||
|
m := testModule(t, "plan_range_over_plan_timestamp")
|
||||||
|
|
||||||
|
ctx := testContext2(t, &ContextOpts{
|
||||||
|
Providers: map[addrs.Provider]providers.Factory{
|
||||||
|
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
diags := ctx.Validate(context.Background(), m)
|
||||||
|
if diags.HasErrors() {
|
||||||
|
t.Fatal(diags.ErrWithWarnings())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
12
internal/tofu/testdata/plan_range_over_plan_timestamp/main.tf
vendored
Normal file
12
internal/tofu/testdata/plan_range_over_plan_timestamp/main.tf
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
locals {
|
||||||
|
first_year = 2024
|
||||||
|
current_timestamp = plantimestamp()
|
||||||
|
}
|
||||||
|
|
||||||
|
output "table_years" {
|
||||||
|
value = toset(
|
||||||
|
[
|
||||||
|
for year in range(local.first_year, tonumber(formatdate("YYYY", local.current_timestamp)) + 2) : tostring(year)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user