diff --git a/pkg/epoch/epoch.go b/pkg/epoch/epoch.go index 14379a68e..1e4e06c20 100644 --- a/pkg/epoch/epoch.go +++ b/pkg/epoch/epoch.go @@ -37,12 +37,11 @@ func SourceDateEpoch() (*time.Time, error) { if !ok || v == "" { return nil, nil // not an error } - i64, err := strconv.ParseInt(v, 10, 64) + t, err := ParseSourceDateEpoch(v) if err != nil { - return nil, fmt.Errorf("invalid %s value %q: %w", SourceDateEpochEnv, v, err) + return nil, fmt.Errorf("invalid %s value: %w", SourceDateEpochEnv, err) } - unix := time.Unix(i64, 0).UTC() - return &unix, nil + return t, nil } // SourceDateEpochOrNow returns the SOURCE_DATE_EPOCH time if available, @@ -58,6 +57,20 @@ func SourceDateEpochOrNow() time.Time { return time.Now().UTC() } +// ParseSourceDateEpoch parses the given source date epoch, as *time.Time. +// It returns an error if sourceDateEpoch is empty or not well-formatted. +func ParseSourceDateEpoch(sourceDateEpoch string) (*time.Time, error) { + if sourceDateEpoch == "" { + return nil, fmt.Errorf("value is empty") + } + i64, err := strconv.ParseInt(sourceDateEpoch, 10, 64) + if err != nil { + return nil, fmt.Errorf("invalid value: %w", err) + } + unix := time.Unix(i64, 0).UTC() + return &unix, nil +} + // SetSourceDateEpoch sets the SOURCE_DATE_EPOCH env var. func SetSourceDateEpoch(tm time.Time) { _ = os.Setenv(SourceDateEpochEnv, strconv.Itoa(int(tm.Unix()))) diff --git a/pkg/epoch/epoch_test.go b/pkg/epoch/epoch_test.go index 27535b78d..5b3cdb8d1 100644 --- a/pkg/epoch/epoch_test.go +++ b/pkg/epoch/epoch_test.go @@ -19,6 +19,7 @@ package epoch import ( "os" "runtime" + "strconv" "testing" "time" @@ -56,19 +57,25 @@ func TestSourceDateEpoch(t *testing.T) { }) t.Run("WithEmptySourceDateEpoch", func(t *testing.T) { - t.Setenv(SourceDateEpochEnv, "") + const emptyValue = "" + t.Setenv(SourceDateEpochEnv, emptyValue) vp, err := SourceDateEpoch() require.NoError(t, err) require.Nil(t, vp) + vp, err = ParseSourceDateEpoch(emptyValue) + require.Error(t, err, "value is empty") + require.Nil(t, vp) + now := time.Now().UTC() v := SourceDateEpochOrNow() require.True(t, rightAfter(now, v), "now: %s, v: %s", now, v) }) t.Run("WithSourceDateEpoch", func(t *testing.T) { - sourceDateEpoch, err := time.Parse(time.RFC3339, "2022-01-23T12:34:56Z") + const rfc3339Str = "2022-01-23T12:34:56Z" + sourceDateEpoch, err := time.Parse(time.RFC3339, rfc3339Str) require.NoError(t, err) SetSourceDateEpoch(sourceDateEpoch) @@ -76,6 +83,10 @@ func TestSourceDateEpoch(t *testing.T) { vp, err := SourceDateEpoch() require.NoError(t, err) + require.True(t, vp.Equal(sourceDateEpoch.UTC())) + + vp, err = ParseSourceDateEpoch(strconv.Itoa(int(sourceDateEpoch.Unix()))) + require.NoError(t, err) require.True(t, vp.Equal(sourceDateEpoch)) v := SourceDateEpochOrNow() @@ -83,12 +94,17 @@ func TestSourceDateEpoch(t *testing.T) { }) t.Run("WithInvalidSourceDateEpoch", func(t *testing.T) { - t.Setenv(SourceDateEpochEnv, "foo") + const invalidValue = "foo" + t.Setenv(SourceDateEpochEnv, invalidValue) vp, err := SourceDateEpoch() require.ErrorContains(t, err, "invalid SOURCE_DATE_EPOCH value") require.Nil(t, vp) + vp, err = ParseSourceDateEpoch(invalidValue) + require.ErrorContains(t, err, "invalid value:") + require.Nil(t, vp) + now := time.Now().UTC() v := SourceDateEpochOrNow() require.True(t, rightAfter(now, v), "now: %s, v: %s", now, v)