Skip to content

Commit ec0bb73

Browse files
committed
bake: add rfc3339parse function
Signed-off-by: CrazyMax <[email protected]>
1 parent 5569825 commit ec0bb73

File tree

3 files changed

+88
-1
lines changed

3 files changed

+88
-1
lines changed

bake/hclparser/stdlib.go

Lines changed: 58 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},
@@ -241,7 +242,7 @@ func sanitizeFunc() function.Function {
241242

242243
// timestampFunc constructs a function that returns a string representation of the current date and time.
243244
//
244-
// This function was imported from terraform's datetime utilities.
245+
// This function was imported from Terraform's datetime utilities.
245246
func timestampFunc() function.Function {
246247
return function.New(&function.Spec{
247248
Description: `Returns a string representation of the current date and time.`,
@@ -253,6 +254,62 @@ func timestampFunc() function.Function {
253254
})
254255
}
255256

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

docs/bake-stdlib.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ title: Bake standard library functions
7676
| `replace` | Replaces all instances of the given substring in the given string with the given replacement string. |
7777
| `reverse` | Returns the given string with all of its Unicode characters in reverse order. |
7878
| `reverselist` | Returns the given list with its elements in reverse order. |
79+
| `rfc3339parse` | Given an RFC3339 timestamp string, will parse and return an object representation of that date and time. |
7980
| `rsadecrypt` | |
8081
| `sanitize` | Replaces all non-alphanumeric characters with a underscore, leaving only characters that are valid for a Bake target name. |
8182
| `sethaselement` | Returns true if the given set contains the given element, or false otherwise. |

0 commit comments

Comments
 (0)