summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-03-03 23:45:25 +0200
committerPaul Buetow <paul@buetow.org>2026-03-03 23:45:25 +0200
commit626bbc46f9debf892ee250cd104fd37371f2e41e (patch)
tree03efcbd6c2baa04e9b07e52a64b7b7374ec91855
parent7e6b2e4c2ba957899b12dac7e0ea9f7c29a9a7b3 (diff)
cli: harden report import error handling
Capture deferred close errors and preserve parse failure context in import date parsing.
-rw-r--r--internal/cli/work.go21
-rw-r--r--internal/cli/work_test.go23
2 files changed, 39 insertions, 5 deletions
diff --git a/internal/cli/work.go b/internal/cli/work.go
index b454612..e70587f 100644
--- a/internal/cli/work.go
+++ b/internal/cli/work.go
@@ -411,14 +411,24 @@ func activeCategories(entries []worktime.Entry) []string {
return active
}
-func importReportFile(ctx workContext, path string) (int, error) {
+func importReportFile(ctx workContext, path string) (imported int, err error) {
file, err := os.Open(path)
if err != nil {
return 0, err
}
- defer file.Close()
+ defer func() {
+ closeErr := file.Close()
+ if closeErr == nil {
+ return
+ }
+ wrappedCloseErr := fmt.Errorf("close import file %q: %w", path, closeErr)
+ if err == nil {
+ err = wrappedCloseErr
+ return
+ }
+ err = errors.Join(err, wrappedCloseErr)
+ }()
- imported := 0
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
@@ -518,7 +528,8 @@ func parseImportDate(token string) (time.Time, error) {
return time.Time{}, errors.New("import date is empty")
}
- if parsed, err := timefmt.Parse(trimmed); err == nil {
+ parsed, parseErr := timefmt.Parse(trimmed)
+ if parseErr == nil {
return parsed, nil
}
@@ -532,7 +543,7 @@ func parseImportDate(token string) (time.Time, error) {
}
}
- return time.Time{}, fmt.Errorf("unsupported import date %q", token)
+ return time.Time{}, fmt.Errorf("unsupported import date %q: %w", token, parseErr)
}
func workDBPath(dbDir, host string) string {
diff --git a/internal/cli/work_test.go b/internal/cli/work_test.go
index 9621bfb..2be0231 100644
--- a/internal/cli/work_test.go
+++ b/internal/cli/work_test.go
@@ -7,6 +7,7 @@ import (
"strconv"
"strings"
"testing"
+ "time"
timrTimer "codeberg.org/snonux/timr/internal/timer"
)
@@ -108,6 +109,28 @@ func TestWorkLoginLogoutWithTimerFlags(t *testing.T) {
}
}
+func TestParseImportDateFallbackLayout(t *testing.T) {
+ parsed, err := parseImportDate("06.01.2026")
+ if err != nil {
+ t.Fatalf("parseImportDate() error = %v", err)
+ }
+
+ expected := time.Date(2026, 1, 6, 0, 0, 0, 0, time.Local)
+ if parsed.Year() != expected.Year() || parsed.Month() != expected.Month() || parsed.Day() != expected.Day() {
+ t.Fatalf("parsed date = %v, want %v", parsed, expected)
+ }
+}
+
+func TestParseImportDateIncludesUnderlyingParseError(t *testing.T) {
+ _, err := parseImportDate("not-a-date")
+ if err == nil {
+ t.Fatal("parseImportDate() error = nil, want error")
+ }
+ if !strings.Contains(err.Error(), "unsupported import date") {
+ t.Fatalf("parseImportDate() error = %v, want unsupported import date context", err)
+ }
+}
+
func writeWorkConfig(t *testing.T, dbDir, host string) string {
return writeWorkConfigWithAuto(t, dbDir, host, false)
}