Skip to content

Commit 33d0ecb

Browse files
committed
bake: add rfc3339parse function
Signed-off-by: CrazyMax <[email protected]>
1 parent 9a5cbac commit 33d0ecb

File tree

2 files changed

+86
-1
lines changed

2 files changed

+86
-1
lines changed

bake/hclparser/stdlib.go

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ var stdlibFunctions = []funcDef{
9494
{name: "replace", fn: stdlib.ReplaceFunc},
9595
{name: "reverse", fn: stdlib.ReverseFunc},
9696
{name: "reverselist", fn: stdlib.ReverseListFunc},
97+
{name: "rfc3339parse", factory: rfc3339ParseFunc},
9798
{name: "rsadecrypt", fn: crypto.RsaDecryptFunc},
9899
{name: "sanitize", factory: sanitizeFunc},
99100
{name: "sethaselement", fn: stdlib.SetHasElementFunc},
@@ -237,7 +238,7 @@ func sanitizeFunc() function.Function {
237238

238239
// timestampFunc constructs a function that returns a string representation of the current date and time.
239240
//
240-
// This function was imported from terraform's datetime utilities.
241+
// This function was imported from Terraform's datetime utilities.
241242
func timestampFunc() function.Function {
242243
return function.New(&function.Spec{
243244
Params: []function.Parameter{},
@@ -248,6 +249,61 @@ func timestampFunc() function.Function {
248249
})
249250
}
250251

252+
// rfc3339ParseFunc, given an RFC3339 timestamp string, will parse and return an
253+
// object representation of that date and time.
254+
//
255+
// This function is similar to the `rfc3339_parse` function in Terraform:
256+
// https://registry.terraform.io/providers/hashicorp/time/latest/docs/functions/rfc3339_parse
257+
func rfc3339ParseFunc() function.Function {
258+
return function.New(&function.Spec{
259+
Params: []function.Parameter{
260+
{
261+
Name: "timestamp",
262+
Description: "RFC3339 timestamp string to parse",
263+
Type: cty.String,
264+
},
265+
},
266+
Type: function.StaticReturnType(cty.Object(map[string]cty.Type{
267+
"year": cty.Number,
268+
"year_day": cty.Number,
269+
"day": cty.Number,
270+
"month": cty.Number,
271+
"month_name": cty.String,
272+
"weekday": cty.Number,
273+
"weekday_name": cty.String,
274+
"hour": cty.Number,
275+
"minute": cty.Number,
276+
"second": cty.Number,
277+
"unix": cty.Number,
278+
"iso_year": cty.Number,
279+
"iso_week": cty.Number,
280+
})),
281+
Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
282+
ts := args[0].AsString()
283+
rfc3339, err := time.Parse(time.RFC3339, ts)
284+
if err != nil {
285+
return cty.NilVal, err
286+
}
287+
isoYear, isoWeek := rfc3339.ISOWeek()
288+
return cty.ObjectVal(map[string]cty.Value{
289+
"year": cty.NumberIntVal(int64(rfc3339.Year())),
290+
"year_day": cty.NumberIntVal(int64(rfc3339.YearDay())),
291+
"day": cty.NumberIntVal(int64(rfc3339.Day())),
292+
"month": cty.NumberIntVal(int64(rfc3339.Month())),
293+
"month_name": cty.StringVal(rfc3339.Month().String()),
294+
"weekday": cty.NumberIntVal(int64(rfc3339.Weekday())),
295+
"weekday_name": cty.StringVal(rfc3339.Weekday().String()),
296+
"hour": cty.NumberIntVal(int64(rfc3339.Hour())),
297+
"minute": cty.NumberIntVal(int64(rfc3339.Minute())),
298+
"second": cty.NumberIntVal(int64(rfc3339.Second())),
299+
"unix": cty.NumberIntVal(int64(rfc3339.Unix())),
300+
"iso_year": cty.NumberIntVal(int64(isoYear)),
301+
"iso_week": cty.NumberIntVal(int64(isoWeek)),
302+
}), nil
303+
},
304+
})
305+
}
306+
251307
func Stdlib() map[string]function.Function {
252308
funcs := make(map[string]function.Function, len(stdlibFunctions))
253309
for _, v := range stdlibFunctions {

bake/hclparser/stdlib_test.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,3 +197,32 @@ func TestSanitize(t *testing.T) {
197197
})
198198
}
199199
}
200+
201+
func TestRfc3339ParseFunc(t *testing.T) {
202+
fn := rfc3339ParseFunc()
203+
input := cty.StringVal("2024-06-01T15:04:05Z")
204+
got, err := fn.Call([]cty.Value{input})
205+
require.NoError(t, err)
206+
207+
expected := map[string]cty.Value{
208+
"year": cty.NumberIntVal(2024),
209+
"year_day": cty.NumberIntVal(153),
210+
"day": cty.NumberIntVal(1),
211+
"month": cty.NumberIntVal(6),
212+
"month_name": cty.StringVal("June"),
213+
"weekday": cty.NumberIntVal(6),
214+
"weekday_name": cty.StringVal("Saturday"),
215+
"hour": cty.NumberIntVal(15),
216+
"minute": cty.NumberIntVal(4),
217+
"second": cty.NumberIntVal(5),
218+
"unix": cty.NumberIntVal(1717254245),
219+
"iso_year": cty.NumberIntVal(2024),
220+
"iso_week": cty.NumberIntVal(22),
221+
}
222+
for k, v := range expected {
223+
require.True(t, got.GetAttr(k).RawEquals(v), "field %s: got %v, want %v", k, got.GetAttr(k), v)
224+
}
225+
226+
_, err = fn.Call([]cty.Value{cty.StringVal("not-a-date")})
227+
require.Error(t, err)
228+
}

0 commit comments

Comments
 (0)