From 5e294d84b7f4466ce7f2ec5b900369379a4c065d Mon Sep 17 00:00:00 2001 From: George Date: Tue, 3 Sep 2024 13:55:32 +0100 Subject: [PATCH] feat(util/notification): add duration and timestamp constants from stdlib time package (#10706) * feat(util/notification): add duration and timestamp constants from stdlib time package Signed-off-by: George MacRorie * chore(docs): add details on new time constants Signed-off-by: George MacRorie * chore: run go mod tidy Signed-off-by: George MacRorie * chore(util/notification): use require.NoError instead of require.Nil Signed-off-by: George MacRorie * chore: go mod tidy Signed-off-by: George MacRorie --------- Signed-off-by: George MacRorie --- .../notifications/functions.md | 38 ++++++++++++++++ go.mod | 2 +- util/notification/expression/time/time.go | 31 +++++++++++-- .../notification/expression/time/time_test.go | 45 ++++++++++++++++++- 4 files changed, 109 insertions(+), 7 deletions(-) diff --git a/docs/operator-manual/notifications/functions.md b/docs/operator-manual/notifications/functions.md index c50d122024b76..ebde62a62afb0 100644 --- a/docs/operator-manual/notifications/functions.md +++ b/docs/operator-manual/notifications/functions.md @@ -12,6 +12,44 @@ Golang [Time](https://golang.org/pkg/time/#Time). Parses specified string using RFC3339 layout. Returns an instance of Golang [Time](https://golang.org/pkg/time/#Time). +
+Time related constants. + +**Durations** + +``` + time.Nanosecond = 1 + time.Microsecond = 1000 * Nanosecond + time.Millisecond = 1000 * Microsecond + time.Second = 1000 * Millisecond + time.Minute = 60 * Second + time.Hour = 60 * Minute +``` + +**Timestamps** + +Used when formatting time instances as strings (e.g. `time.Now().Format(time.RFC3339)`). + +``` + time.Layout = "01/02 03:04:05PM '06 -0700" // The reference time, in numerical order. + time.ANSIC = "Mon Jan _2 15:04:05 2006" + time.UnixDate = "Mon Jan _2 15:04:05 MST 2006" + time.RubyDate = "Mon Jan 02 15:04:05 -0700 2006" + time.RFC822 = "02 Jan 06 15:04 MST" + time.RFC822Z = "02 Jan 06 15:04 -0700" // RFC822 with numeric zone + time.RFC850 = "Monday, 02-Jan-06 15:04:05 MST" + time.RFC1123 = "Mon, 02 Jan 2006 15:04:05 MST" + time.RFC1123Z = "Mon, 02 Jan 2006 15:04:05 -0700" // RFC1123 with numeric zone + time.RFC3339 = "2006-01-02T15:04:05Z07:00" + time.RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00" + time.Kitchen = "3:04PM" + // Handy time stamps. + time.Stamp = "Jan _2 15:04:05" + time.StampMilli = "Jan _2 15:04:05.000" + time.StampMicro = "Jan _2 15:04:05.000000" + time.StampNano = "Jan _2 15:04:05.000000000" +``` + ### **strings** String related functions. diff --git a/go.mod b/go.mod index 2440ee7c32ec6..2be32c1ffa798 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( github.com/Masterminds/sprig/v3 v3.3.0 github.com/TomOnTime/utfutil v0.0.0-20180511104225-09c41003ee1d github.com/alicebob/miniredis/v2 v2.33.0 + github.com/antonmedv/expr v1.15.1 github.com/argoproj/gitops-engine v0.7.1-0.20240823213048-95e00254f82a github.com/argoproj/notifications-engine v0.4.1-0.20240606074338-0802cd427621 github.com/argoproj/pkg v0.13.7-0.20230626144333-d56162821bd1 @@ -117,7 +118,6 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 // indirect github.com/AzureAD/microsoft-authentication-library-for-go v0.5.2 // indirect - github.com/antonmedv/expr v1.15.1 // indirect github.com/aws/aws-sdk-go-v2 v1.24.1 // indirect github.com/aws/aws-sdk-go-v2/config v1.25.12 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.16.16 // indirect diff --git a/util/notification/expression/time/time.go b/util/notification/expression/time/time.go index 6457b75d8c093..63aa31c3d3d13 100644 --- a/util/notification/expression/time/time.go +++ b/util/notification/expression/time/time.go @@ -4,10 +4,37 @@ import ( "time" ) +var now = time.Now + func NewExprs() map[string]interface{} { return map[string]interface{}{ + // Functions "Parse": parse, "Now": now, + // Durations + "Nanosecond": time.Nanosecond, + "Microsecond": time.Microsecond, + "Millisecond": time.Millisecond, + "Second": time.Second, + "Minute": time.Minute, + "Hour": time.Hour, + // Timestamps + "Layout": time.Layout, + "ANSIC": time.ANSIC, + "UnixDate": time.UnixDate, + "RubyDate": time.RubyDate, + "RFC822": time.RFC822, + "RFC822Z": time.RFC822Z, + "RFC850": time.RFC850, + "RFC1123": time.RFC1123, + "RFC1123Z": time.RFC1123Z, + "RFC3339": time.RFC3339, + "RFC3339Nano": time.RFC3339Nano, + "Kitchen": time.Kitchen, + "Stamp": time.Stamp, + "StampMilli": time.StampMilli, + "StampMicro": time.StampMicro, + "StampNano": time.StampNano, } } @@ -18,7 +45,3 @@ func parse(timestamp string) time.Time { } return res } - -func now() time.Time { - return time.Now() -} diff --git a/util/notification/expression/time/time_test.go b/util/notification/expression/time/time_test.go index 3003521344eb4..a450260bea399 100644 --- a/util/notification/expression/time/time_test.go +++ b/util/notification/expression/time/time_test.go @@ -2,19 +2,60 @@ package time import ( "testing" + "time" + "github.com/antonmedv/expr" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestNewTimeExprs(t *testing.T) { funcs := []string{ "Parse", "Now", + "Nanosecond", + "Microsecond", + "Millisecond", + "Second", + "Minute", + "Hour", + "Layout", + "ANSIC", + "UnixDate", + "RubyDate", + "RFC822", + "RFC822Z", + "RFC850", + "RFC1123", + "RFC1123Z", + "RFC3339", + "RFC3339Nano", + "Kitchen", + "Stamp", + "StampMilli", + "StampMicro", + "StampNano", } for _, fn := range funcs { timeExprs := NewExprs() - _, hasFunc := timeExprs[fn] - assert.True(t, hasFunc) + _, exists := timeExprs[fn] + assert.True(t, exists) } } + +func Test_NewExprs_Now(t *testing.T) { + defer func() { now = time.Now }() + fixedTime := time.Date(2022, 9, 26, 11, 30, 25, 0, time.UTC) + now = func() time.Time { + return fixedTime + } + + vm, err := expr.Compile("time.Now().Truncate(time.Hour).Format(time.RFC3339)") + require.NoError(t, err) + + val, err := expr.Run(vm, map[string]interface{}{"time": NewExprs()}) + require.NoError(t, err) + + assert.Equal(t, "2022-09-26T11:00:00Z", val) +}