Skip to content

Commit a4c6dab

Browse files
Fix --offline --since date filtering bug (#29)
Fix --offline --since date filtering bug
1 parent 8a05f6a commit a4c6dab

File tree

2 files changed

+216
-0
lines changed

2 files changed

+216
-0
lines changed

main.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,22 @@ func run(stdout, stderr io.Writer, args []string, deps *Dependencies) int {
276276

277277
result := diff.Compare(previousSnapshot, currentSnapshot)
278278

279+
// Filter results by since date if specified
280+
// This is needed because snapshots contain historical data (e.g., 30 days),
281+
// so we need to filter out activities that occurred before the since date
282+
if cfg.Since != "" {
283+
var filterDate time.Time
284+
filterDate, err = parseSinceDate(cfg.Since, deps.Now())
285+
if err != nil {
286+
_, _ = fmt.Fprintf(stderr, "Error parsing --since date for filtering: %v\n", err)
287+
return 1
288+
}
289+
result = filterResultBySinceDate(result, filterDate)
290+
if cfg.Verbose {
291+
_, _ = fmt.Fprintf(stdout, "Filtered results to only show activity from %s onwards\n", filterDate.Format("2006-01-02"))
292+
}
293+
}
294+
279295
if cfg.Verbose {
280296
_, _ = fmt.Fprintf(stdout, "Diff result: NewStars=%d, NewRepos=%d, NewEvents=%d, NewUsers=%d, GoneUsers=%d\n",
281297
len(result.NewStars), len(result.NewRepos), len(result.NewEvents), len(result.NewUsers), len(result.GoneUsers))
@@ -723,6 +739,41 @@ func eventTypeToActivityType(eventType string) report.ActivityType {
723739
}
724740
}
725741

742+
// filterResultBySinceDate filters a diff result to only include activities created on or after the given date.
743+
// This is necessary when using --since because snapshots contain historical data (e.g., 30 days),
744+
// and we only want to show activities that occurred after the specified since date.
745+
func filterResultBySinceDate(result *diff.Result, sinceDate time.Time) *diff.Result {
746+
filtered := &diff.Result{
747+
OldCapturedAt: result.OldCapturedAt,
748+
NewCapturedAt: result.NewCapturedAt,
749+
NewUsers: result.NewUsers,
750+
GoneUsers: result.GoneUsers,
751+
}
752+
753+
// Filter new stars - only include repos created on or after since date
754+
for _, star := range result.NewStars {
755+
if !star.Repo.CreatedAt.Before(sinceDate) {
756+
filtered.NewStars = append(filtered.NewStars, star)
757+
}
758+
}
759+
760+
// Filter new repos - only include repos created on or after since date
761+
for _, repo := range result.NewRepos {
762+
if !repo.Repo.CreatedAt.Before(sinceDate) {
763+
filtered.NewRepos = append(filtered.NewRepos, repo)
764+
}
765+
}
766+
767+
// Filter new events - only include events created on or after since date
768+
for _, event := range result.NewEvents {
769+
if !event.Event.CreatedAt.Before(sinceDate) {
770+
filtered.NewEvents = append(filtered.NewEvents, event)
771+
}
772+
}
773+
774+
return filtered
775+
}
776+
726777
func formatNotificationMessage(result *diff.Result) string {
727778
parts := []string{}
728779

main_test.go

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1522,3 +1522,168 @@ func TestRun_OfflineMode_NoTokenRequired(t *testing.T) {
15221522
t.Errorf("should not require GITHUB_TOKEN in offline mode, got: %s", stderr.String())
15231523
}
15241524
}
1525+
1526+
func TestFilterResultBySinceDate(t *testing.T) {
1527+
now := time.Date(2026, 1, 22, 12, 0, 0, 0, time.UTC)
1528+
sinceDate := time.Date(2026, 1, 21, 0, 0, 0, 0, time.UTC)
1529+
oldDate := time.Date(2026, 1, 5, 0, 0, 0, 0, time.UTC) // 3 weeks ago
1530+
1531+
result := &diff.Result{
1532+
OldCapturedAt: time.Date(2026, 1, 1, 0, 0, 0, 0, time.UTC),
1533+
NewCapturedAt: now,
1534+
NewStars: []diff.RepoChange{
1535+
{
1536+
Username: "simonw",
1537+
Repo: diff.Repo{
1538+
Owner: "simonw",
1539+
Name: "old-repo",
1540+
CreatedAt: oldDate, // Should be filtered out
1541+
},
1542+
},
1543+
{
1544+
Username: "octocat",
1545+
Repo: diff.Repo{
1546+
Owner: "octocat",
1547+
Name: "new-repo",
1548+
CreatedAt: sinceDate.Add(time.Hour), // Should be included
1549+
},
1550+
},
1551+
},
1552+
NewRepos: []diff.RepoChange{
1553+
{
1554+
Username: "user1",
1555+
Repo: diff.Repo{
1556+
Owner: "user1",
1557+
Name: "ancient-repo",
1558+
CreatedAt: oldDate, // Should be filtered out
1559+
},
1560+
},
1561+
{
1562+
Username: "user2",
1563+
Repo: diff.Repo{
1564+
Owner: "user2",
1565+
Name: "recent-repo",
1566+
CreatedAt: now, // Should be included
1567+
},
1568+
},
1569+
},
1570+
NewEvents: []diff.EventChange{
1571+
{
1572+
Username: "simonw",
1573+
Event: diff.Event{
1574+
Type: "PushEvent",
1575+
Actor: "simonw",
1576+
Repo: "simonw/old-project",
1577+
CreatedAt: oldDate, // Should be filtered out
1578+
},
1579+
},
1580+
{
1581+
Username: "octocat",
1582+
Event: diff.Event{
1583+
Type: "PushEvent",
1584+
Actor: "octocat",
1585+
Repo: "octocat/fresh-project",
1586+
CreatedAt: sinceDate, // Exactly on since date - should be included
1587+
},
1588+
},
1589+
},
1590+
NewUsers: []string{"newuser1", "newuser2"},
1591+
GoneUsers: []string{"goneuser1"},
1592+
}
1593+
1594+
filtered := filterResultBySinceDate(result, sinceDate)
1595+
1596+
// Check that timestamps are preserved
1597+
if !filtered.OldCapturedAt.Equal(result.OldCapturedAt) {
1598+
t.Errorf("OldCapturedAt mismatch: got %v, want %v", filtered.OldCapturedAt, result.OldCapturedAt)
1599+
}
1600+
if !filtered.NewCapturedAt.Equal(result.NewCapturedAt) {
1601+
t.Errorf("NewCapturedAt mismatch: got %v, want %v", filtered.NewCapturedAt, result.NewCapturedAt)
1602+
}
1603+
1604+
// Check that user lists are preserved
1605+
if len(filtered.NewUsers) != 2 || filtered.NewUsers[0] != "newuser1" {
1606+
t.Errorf("NewUsers not preserved: got %v, want %v", filtered.NewUsers, result.NewUsers)
1607+
}
1608+
if len(filtered.GoneUsers) != 1 || filtered.GoneUsers[0] != "goneuser1" {
1609+
t.Errorf("GoneUsers not preserved: got %v, want %v", filtered.GoneUsers, result.GoneUsers)
1610+
}
1611+
1612+
// Check that old stars are filtered out
1613+
if len(filtered.NewStars) != 1 {
1614+
t.Fatalf("expected 1 new star, got %d", len(filtered.NewStars))
1615+
}
1616+
if filtered.NewStars[0].Username != "octocat" {
1617+
t.Errorf("wrong star kept: got %s, want octocat", filtered.NewStars[0].Username)
1618+
}
1619+
1620+
// Check that old repos are filtered out
1621+
if len(filtered.NewRepos) != 1 {
1622+
t.Fatalf("expected 1 new repo, got %d", len(filtered.NewRepos))
1623+
}
1624+
if filtered.NewRepos[0].Username != "user2" {
1625+
t.Errorf("wrong repo kept: got %s, want user2", filtered.NewRepos[0].Username)
1626+
}
1627+
1628+
// Check that old events are filtered out
1629+
if len(filtered.NewEvents) != 1 {
1630+
t.Fatalf("expected 1 new event, got %d", len(filtered.NewEvents))
1631+
}
1632+
if filtered.NewEvents[0].Username != "octocat" {
1633+
t.Errorf("wrong event kept: got %s, want octocat", filtered.NewEvents[0].Username)
1634+
}
1635+
}
1636+
1637+
func TestFilterResultBySinceDate_BoundaryConditions(t *testing.T) {
1638+
sinceDate := time.Date(2026, 1, 15, 0, 0, 0, 0, time.UTC)
1639+
1640+
tests := []struct {
1641+
createdAt time.Time
1642+
name string
1643+
shouldInclude bool
1644+
}{
1645+
{
1646+
name: "before since date",
1647+
createdAt: sinceDate.Add(-24 * time.Hour),
1648+
shouldInclude: false,
1649+
},
1650+
{
1651+
name: "exactly on since date",
1652+
createdAt: sinceDate,
1653+
shouldInclude: true,
1654+
},
1655+
{
1656+
name: "after since date",
1657+
createdAt: sinceDate.Add(24 * time.Hour),
1658+
shouldInclude: true,
1659+
},
1660+
}
1661+
1662+
for _, tt := range tests {
1663+
t.Run(tt.name, func(t *testing.T) {
1664+
result := &diff.Result{
1665+
NewStars: []diff.RepoChange{
1666+
{
1667+
Username: "user",
1668+
Repo: diff.Repo{
1669+
Owner: "user",
1670+
Name: "repo",
1671+
CreatedAt: tt.createdAt,
1672+
},
1673+
},
1674+
},
1675+
}
1676+
1677+
filtered := filterResultBySinceDate(result, sinceDate)
1678+
1679+
expectedCount := 0
1680+
if tt.shouldInclude {
1681+
expectedCount = 1
1682+
}
1683+
1684+
if len(filtered.NewStars) != expectedCount {
1685+
t.Errorf("expected %d stars, got %d", expectedCount, len(filtered.NewStars))
1686+
}
1687+
})
1688+
}
1689+
}

0 commit comments

Comments
 (0)