filter to only releases in the last year

This commit is contained in:
Emil Lerch 2025-07-13 14:25:31 -07:00
parent 7b555e2162
commit 6edaa25cc5
Signed by: lobo
GPG key ID: A7B62D657EF764F8

View file

@ -18,6 +18,9 @@ const zeit = @import("zeit");
const Provider = @import("Provider.zig");
// Configuration: Only include releases from the last year in the output
const RELEASE_AGE_LIMIT_SECONDS: i64 = 365 * 24 * 60 * 60; // 1 year in seconds
pub const Release = struct {
repo_name: []const u8,
tag_name: []const u8,
@ -147,27 +150,38 @@ pub fn main() !u8 {
print("Found {} new releases from {s}\n", .{ result.releases.items.len, result.provider_name });
}
// Combine existing and new releases
// Combine all releases (existing and new)
var all_releases = ArrayList(Release).init(allocator);
defer all_releases.deinit();
// Add new releases first (they'll appear at the top of the Atom feed)
// Add new releases
try all_releases.appendSlice(new_releases.items);
// Add existing releases (up to a reasonable limit to prevent Atom feed from growing indefinitely)
const max_total_releases = 1000;
const remaining_slots = if (new_releases.items.len < max_total_releases)
max_total_releases - new_releases.items.len
else
0;
const existing_to_add = @min(existing_releases.items.len, remaining_slots);
try all_releases.appendSlice(existing_releases.items[0..existing_to_add]);
// Add all existing releases
try all_releases.appendSlice(existing_releases.items);
// Sort all releases by published date (most recent first)
std.mem.sort(Release, all_releases.items, {}, compareReleasesByDate);
// Generate Atom feed
// Filter releases by age in-place - zero extra allocations
const now = std.time.timestamp();
const cutoff_time = now - RELEASE_AGE_LIMIT_SECONDS;
var write_index: usize = 0;
const original_count = all_releases.items.len;
for (all_releases.items) |release| {
const release_time = parseReleaseTimestamp(release.published_at) catch 0;
if (release_time >= cutoff_time) {
all_releases.items[write_index] = release;
write_index += 1;
}
}
// Shrink the array to only include filtered items
all_releases.shrinkRetainingCapacity(write_index);
// Generate Atom feed from filtered releases
const atom_content = try atom.generateFeed(allocator, all_releases.items);
defer allocator.free(atom_content);
@ -178,7 +192,7 @@ pub fn main() !u8 {
// Log to stderr for user feedback
std.debug.print("Found {} new releases\n", .{new_releases.items.len});
std.debug.print("Total releases in feed: {}\n", .{all_releases.items.len});
std.debug.print("Total releases in feed: {} (filtered from {} total, showing last {} days)\n", .{ all_releases.items.len, original_count, @divTrunc(RELEASE_AGE_LIMIT_SECONDS, 24 * 60 * 60) });
std.debug.print("Updated feed written to: {s}\n", .{output_file});
return 0;
@ -761,6 +775,92 @@ test {
std.testing.refAllDecls(@import("xml_parser_tests.zig"));
}
test "Age-based release filtering" {
const allocator = std.testing.allocator;
const now = std.time.timestamp();
const one_year_ago = now - RELEASE_AGE_LIMIT_SECONDS;
const two_years_ago = now - (2 * RELEASE_AGE_LIMIT_SECONDS);
// Create releases with different ages
const recent_release = Release{
.repo_name = "test/recent",
.tag_name = "v1.0.0",
.published_at = try std.fmt.allocPrint(allocator, "{}", .{now - 86400}), // 1 day ago
.html_url = "https://github.com/test/recent/releases/tag/v1.0.0",
.description = "Recent release",
.provider = "github",
};
defer allocator.free(recent_release.published_at);
const old_release = Release{
.repo_name = "test/old",
.tag_name = "v0.1.0",
.published_at = try std.fmt.allocPrint(allocator, "{}", .{two_years_ago}),
.html_url = "https://github.com/test/old/releases/tag/v0.1.0",
.description = "Old release",
.provider = "github",
};
defer allocator.free(old_release.published_at);
const borderline_release = Release{
.repo_name = "test/borderline",
.tag_name = "v0.5.0",
.published_at = try std.fmt.allocPrint(allocator, "{}", .{one_year_ago + 3600}), // 1 hour within limit
.html_url = "https://github.com/test/borderline/releases/tag/v0.5.0",
.description = "Borderline release",
.provider = "github",
};
defer allocator.free(borderline_release.published_at);
const releases = [_]Release{ recent_release, old_release, borderline_release };
// Test filtering logic
var filtered = ArrayList(Release).init(allocator);
defer filtered.deinit();
const cutoff_time = now - RELEASE_AGE_LIMIT_SECONDS;
for (releases) |release| {
const release_time = parseReleaseTimestamp(release.published_at) catch 0;
if (release_time >= cutoff_time) {
try filtered.append(release);
}
}
// Should include recent and borderline, but not old
try std.testing.expectEqual(@as(usize, 2), filtered.items.len);
// Verify the correct releases were included
var found_recent = false;
var found_borderline = false;
var found_old = false;
for (filtered.items) |release| {
if (std.mem.eql(u8, release.repo_name, "test/recent")) {
found_recent = true;
} else if (std.mem.eql(u8, release.repo_name, "test/borderline")) {
found_borderline = true;
} else if (std.mem.eql(u8, release.repo_name, "test/old")) {
found_old = true;
}
}
try std.testing.expect(found_recent);
try std.testing.expect(found_borderline);
try std.testing.expect(!found_old);
}
test "RELEASE_AGE_LIMIT_SECONDS constant verification" {
// Verify the constant is set to 1 year in seconds
const expected_year_in_seconds = 365 * 24 * 60 * 60;
try std.testing.expectEqual(expected_year_in_seconds, RELEASE_AGE_LIMIT_SECONDS);
// Verify it's approximately 31.5 million seconds (1 year)
try std.testing.expect(RELEASE_AGE_LIMIT_SECONDS > 31_000_000);
try std.testing.expect(RELEASE_AGE_LIMIT_SECONDS < 32_000_000);
}
// Import timestamp tests
test {
std.testing.refAllDecls(@import("timestamp_tests.zig"));