Skip to content

Commit dfe03b6

Browse files
wesmclaude
andauthored
Fix zero Created date in repo show (#159)
## Summary - `roborev repo show` displayed `Created: 0001-01-01 00:00:00` because `time.Parse(time.RFC3339)` silently failed on SQLite's `CURRENT_TIMESTAMP` format (`2006-01-02 15:04:05`) - Replaced all `time.Parse(time.RFC3339, ...)` calls in `repos.go`, `commits.go`, and `jobs.go` with the existing `parseSQLiteTime()` helper that handles both formats - Added a unit test verifying `CreatedAt` is populated when reading repos from the database ## Test plan - [x] `go test ./internal/storage/ -run TestFindRepo` — new `created_at_is_populated` subtest passes - [x] `go build ./...` clean - [x] `roborev repo show <name>` displays correct created date 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
1 parent fe6a0fb commit dfe03b6

File tree

5 files changed

+44
-22
lines changed

5 files changed

+44
-22
lines changed

cmd/roborev/repo.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,11 @@ Examples:
186186
fmt.Printf(" Failed: %d\n", stats.FailedJobs)
187187
}
188188
fmt.Println()
189-
fmt.Printf("Reviews: %d passed, %d failed\n", stats.PassedReviews, stats.FailedReviews)
189+
fmt.Printf("Reviews: %d total\n", stats.PassedReviews+stats.FailedReviews)
190+
fmt.Printf(" Passed: %d\n", stats.PassedReviews)
191+
fmt.Printf(" Failed: %d\n", stats.FailedReviews)
192+
fmt.Printf(" Addressed: %d\n", stats.AddressedReviews)
193+
fmt.Printf(" Unaddressed: %d\n", stats.UnaddressedReviews)
190194

191195
return nil
192196
},

internal/storage/commits.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ func (db *DB) GetOrCreateCommit(repoID int64, sha, author, subject string, times
1414
err := db.QueryRow(`SELECT id, repo_id, sha, author, subject, timestamp, created_at FROM commits WHERE repo_id = ? AND sha = ?`, repoID, sha).
1515
Scan(&commit.ID, &commit.RepoID, &commit.SHA, &commit.Author, &commit.Subject, &ts, &createdAt)
1616
if err == nil {
17-
commit.Timestamp, _ = time.Parse(time.RFC3339, ts)
18-
commit.CreatedAt, _ = time.Parse(time.RFC3339, createdAt)
17+
commit.Timestamp = parseSQLiteTime(ts)
18+
commit.CreatedAt = parseSQLiteTime(createdAt)
1919
return &commit, nil
2020
}
2121
if err != sql.ErrNoRows {
@@ -65,8 +65,8 @@ func (db *DB) GetCommitBySHA(sha string) (*Commit, error) {
6565
if err != nil {
6666
return nil, err
6767
}
68-
commit.Timestamp, _ = time.Parse(time.RFC3339, ts)
69-
commit.CreatedAt, _ = time.Parse(time.RFC3339, createdAt)
68+
commit.Timestamp = parseSQLiteTime(ts)
69+
commit.CreatedAt = parseSQLiteTime(createdAt)
7070
return &commit, nil
7171
}
7272

@@ -79,8 +79,8 @@ func (db *DB) GetCommitByRepoAndSHA(repoID int64, sha string) (*Commit, error) {
7979
if err != nil {
8080
return nil, err
8181
}
82-
commit.Timestamp, _ = time.Parse(time.RFC3339, ts)
83-
commit.CreatedAt, _ = time.Parse(time.RFC3339, createdAt)
82+
commit.Timestamp = parseSQLiteTime(ts)
83+
commit.CreatedAt = parseSQLiteTime(createdAt)
8484
return &commit, nil
8585
}
8686

@@ -93,7 +93,7 @@ func (db *DB) GetCommitByID(id int64) (*Commit, error) {
9393
if err != nil {
9494
return nil, err
9595
}
96-
commit.Timestamp, _ = time.Parse(time.RFC3339, ts)
97-
commit.CreatedAt, _ = time.Parse(time.RFC3339, createdAt)
96+
commit.Timestamp = parseSQLiteTime(ts)
97+
commit.CreatedAt = parseSQLiteTime(createdAt)
9898
return &commit, nil
9999
}

internal/storage/jobs.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1174,11 +1174,11 @@ func (db *DB) ListJobs(statusFilter string, repoFilter string, limit, offset int
11741174
j.Agentic = agentic != 0
11751175
j.EnqueuedAt = parseSQLiteTime(enqueuedAt)
11761176
if startedAt.Valid {
1177-
t, _ := time.Parse(time.RFC3339, startedAt.String)
1177+
t := parseSQLiteTime(startedAt.String)
11781178
j.StartedAt = &t
11791179
}
11801180
if finishedAt.Valid {
1181-
t, _ := time.Parse(time.RFC3339, finishedAt.String)
1181+
t := parseSQLiteTime(finishedAt.String)
11821182
j.FinishedAt = &t
11831183
}
11841184
if workerID.Valid {
@@ -1250,11 +1250,11 @@ func (db *DB) GetJobByID(id int64) (*ReviewJob, error) {
12501250
j.Agentic = agentic != 0
12511251
j.EnqueuedAt = parseSQLiteTime(enqueuedAt)
12521252
if startedAt.Valid {
1253-
t, _ := time.Parse(time.RFC3339, startedAt.String)
1253+
t := parseSQLiteTime(startedAt.String)
12541254
j.StartedAt = &t
12551255
}
12561256
if finishedAt.Valid {
1257-
t, _ := time.Parse(time.RFC3339, finishedAt.String)
1257+
t := parseSQLiteTime(finishedAt.String)
12581258
j.FinishedAt = &t
12591259
}
12601260
if workerID.Valid {

internal/storage/repos.go

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ func (db *DB) GetOrCreateRepo(rootPath string, identity ...string) (*Repo, error
3333
Scan(&repo.ID, &repo.RootPath, &repo.Name, &identityNullable, &createdAt)
3434
if err == nil {
3535
repo.Identity = identityNullable.String
36-
repo.CreatedAt, _ = time.Parse(time.RFC3339, createdAt)
36+
repo.CreatedAt = parseSQLiteTime(createdAt)
3737

3838
// Update identity if provided and not already set
3939
if repoIdentity != "" && repo.Identity == "" {
@@ -85,7 +85,7 @@ func (db *DB) GetRepoByPath(rootPath string) (*Repo, error) {
8585
if err != nil {
8686
return nil, err
8787
}
88-
repo.CreatedAt, _ = time.Parse(time.RFC3339, createdAt)
88+
repo.CreatedAt = parseSQLiteTime(createdAt)
8989
return &repo, nil
9090
}
9191

@@ -288,7 +288,7 @@ func (db *DB) ListRepos() ([]Repo, error) {
288288
if err := rows.Scan(&r.ID, &r.RootPath, &r.Name, &createdAt); err != nil {
289289
return nil, err
290290
}
291-
r.CreatedAt, _ = time.Parse(time.RFC3339, createdAt)
291+
r.CreatedAt = parseSQLiteTime(createdAt)
292292
repos = append(repos, r)
293293
}
294294
return repos, rows.Err()
@@ -303,7 +303,7 @@ func (db *DB) GetRepoByID(id int64) (*Repo, error) {
303303
if err != nil {
304304
return nil, err
305305
}
306-
repo.CreatedAt, _ = time.Parse(time.RFC3339, createdAt)
306+
repo.CreatedAt = parseSQLiteTime(createdAt)
307307
return &repo, nil
308308
}
309309

@@ -316,7 +316,7 @@ func (db *DB) GetRepoByName(name string) (*Repo, error) {
316316
if err != nil {
317317
return nil, err
318318
}
319-
repo.CreatedAt, _ = time.Parse(time.RFC3339, createdAt)
319+
repo.CreatedAt = parseSQLiteTime(createdAt)
320320
return &repo, nil
321321
}
322322

@@ -348,8 +348,10 @@ type RepoStats struct {
348348
RunningJobs int
349349
CompletedJobs int
350350
FailedJobs int
351-
PassedReviews int
352-
FailedReviews int
351+
PassedReviews int
352+
FailedReviews int
353+
AddressedReviews int
354+
UnaddressedReviews int
353355
}
354356

355357
// GetRepoStats returns detailed statistics for a repo
@@ -394,12 +396,14 @@ func (db *DB) GetRepoStats(repoID int64) (*RepoStats, error) {
394396
err = db.QueryRow(`
395397
SELECT
396398
COALESCE(SUM(CASE WHEN r.output LIKE '%**Verdict: PASS%' OR r.output LIKE '%Verdict: PASS%' THEN 1 ELSE 0 END), 0),
397-
COALESCE(SUM(CASE WHEN r.output LIKE '%**Verdict: FAIL%' OR r.output LIKE '%Verdict: FAIL%' THEN 1 ELSE 0 END), 0)
399+
COALESCE(SUM(CASE WHEN r.output LIKE '%**Verdict: FAIL%' OR r.output LIKE '%Verdict: FAIL%' THEN 1 ELSE 0 END), 0),
400+
COALESCE(SUM(CASE WHEN r.addressed = 1 THEN 1 ELSE 0 END), 0),
401+
COALESCE(SUM(CASE WHEN r.addressed = 0 THEN 1 ELSE 0 END), 0)
398402
FROM reviews r
399403
JOIN review_jobs rj ON r.job_id = rj.id
400404
WHERE rj.repo_id = ?
401405
AND NOT (rj.commit_id IS NULL AND rj.git_ref = 'prompt')
402-
`, repoID).Scan(&stats.PassedReviews, &stats.FailedReviews)
406+
`, repoID).Scan(&stats.PassedReviews, &stats.FailedReviews, &stats.AddressedReviews, &stats.UnaddressedReviews)
403407
if err != nil {
404408
return nil, err
405409
}

internal/storage/repos_test.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,20 @@ func TestFindRepo(t *testing.T) {
551551
}
552552
})
553553

554+
t.Run("created_at is populated", func(t *testing.T) {
555+
found, err := db.FindRepo("/tmp/findrepo-test")
556+
if err != nil {
557+
t.Fatalf("FindRepo failed: %v", err)
558+
}
559+
if found.CreatedAt.IsZero() {
560+
t.Error("CreatedAt should not be zero (SQLite CURRENT_TIMESTAMP must be parsed)")
561+
}
562+
// Should be recent (within the last minute)
563+
if time.Since(found.CreatedAt) > time.Minute {
564+
t.Errorf("CreatedAt too old: %v", found.CreatedAt)
565+
}
566+
})
567+
554568
t.Run("not found", func(t *testing.T) {
555569
_, err := db.FindRepo("nonexistent")
556570
if err == nil {

0 commit comments

Comments
 (0)