Forge
csharp3407750f
1using AgentForge.Abstractions;
2using AgentForge.Plugin.Grouping.Core;
3
4namespace AgentForge.Plugin.Grouping.Releases.Axes;
5
6internal abstract class ForgeFixedSectionReleaseGroupingAxis(
7 string id,
8 string label,
9 int order,
10 IReadOnlyList<ForgeGroupingSection> sections)
11 : ForgeFixedSectionGroupingAxis<ForgeReleaseListItem>(id, label, order, sections),
12 IForgeReleaseGroupingAxis;
13
14internal sealed class ReleaseChannelGroupingAxis()
15 : ForgeFixedSectionReleaseGroupingAxis(
16 "channel",
17 "Channel",
18 order: 10,
19 sections:
20 [
21 new("stable", "Stable"),
22 new("prerelease", "Pre-release"),
23 new("draft", "Draft"),
24 ])
25{
26 public override string GetKey(ForgeReleaseListItem item, DateTimeOffset utcNow) =>
27 item.IsPrerelease ? "prerelease" : "stable";
28}
29
30internal sealed class ReleaseMajorVersionGroupingAxis() : IForgeReleaseGroupingAxis
31{
32 public string Id => "major";
33
34 public string Label => "Major version";
35
36 public int Order => 20;
37
38 public string GetKey(ForgeReleaseListItem item, DateTimeOffset utcNow) =>
39 ParseMajor(item.Tag);
40
41 public IReadOnlyList<ForgeGroupingSection> SectionsFor(
42 IReadOnlyList<ForgeReleaseListItem> items,
43 DateTimeOffset utcNow)
44 {
45 var keys = items
46 .Select(item => ParseMajor(item.Tag))
47 .Distinct(StringComparer.OrdinalIgnoreCase)
48 .OrderByDescending(key => int.TryParse(key, out var n) ? n : int.MinValue)
49 .ThenBy(key => key, StringComparer.OrdinalIgnoreCase)
50 .Select(key => new ForgeGroupingSection(key, key == "unknown" ? "Unknown" : $"v{key}"))
51 .ToList();
52
53 return keys.Count == 0 ? [new("unknown", "Unknown")] : keys;
54 }
55
56 private static string ParseMajor(string tag)
57 {
58 var trimmed = tag.Trim();
59 if (trimmed.StartsWith('v') || trimmed.StartsWith('V'))
60 trimmed = trimmed[1..];
61
62 var dot = trimmed.IndexOf('.');
63 var majorPart = dot >= 0 ? trimmed[..dot] : trimmed;
64 return int.TryParse(majorPart, out _) ? majorPart : "unknown";
65 }
66}
67
68internal sealed class ReleasePublishedGroupingAxis()
69 : ForgeFixedSectionReleaseGroupingAxis(
70 "published",
71 "Published",
72 order: 30,
73 ForgeGroupingDateBuckets.Sections())
74{
75 public override string GetKey(ForgeReleaseListItem item, DateTimeOffset utcNow) =>
76 ForgeGroupingDateBuckets.Bucket(item.PublishedAt, utcNow);
77}
78
79internal sealed class ReleaseTargetPlatformGroupingAxis()
80 : ForgeFixedSectionReleaseGroupingAxis(
81 "target_platform",
82 "Target platform",
83 order: 40,
84 sections:
85 [
86 new("windows", "Windows"),
87 new("linux", "Linux"),
88 new("macos", "macOS"),
89 new("multi", "Multi-platform"),
90 new("unknown", "Unknown"),
91 ])
92{
93 public override string GetKey(ForgeReleaseListItem item, DateTimeOffset utcNow) =>
94 ReleaseGroupingAxisHelpers.NormalizePlatform(item.TargetPlatform);
95}
96
97internal sealed class ReleasePackageFormatGroupingAxis()
98 : ForgeFixedSectionReleaseGroupingAxis(
99 "package_format",
100 "Package format",
101 order: 50,
102 sections:
103 [
104 new("exe", "EXE"),
105 new("msi", "MSI"),
106 new("zip", "ZIP"),
107 new("nupkg", "NuGet"),
108 new("na", "N/A"),
109 new("unknown", "Unknown"),
110 ])
111{
112 public override string GetKey(ForgeReleaseListItem item, DateTimeOffset utcNow)
113 {
114 if (!string.Equals(ReleaseGroupingAxisHelpers.NormalizePlatform(item.TargetPlatform), "windows", StringComparison.OrdinalIgnoreCase))
115 return "na";
116
117 return ReleaseGroupingAxisHelpers.NormalizeFormat(item.PackageFormat);
118 }
119}
120
121internal static class ReleaseGroupingAxisHelpers
122{
123 internal static string NormalizePlatform(string? platform)
124 {
125 if (string.IsNullOrWhiteSpace(platform))
126 return "unknown";
127
128 return platform.Trim().ToLowerInvariant() switch
129 {
130 "win" or "windows" or "win-x64" or "win-x86" => "windows",
131 "linux" => "linux",
132 "osx" or "macos" or "darwin" => "macos",
133 "multi" or "multi-platform" or "all" => "multi",
134 _ => platform.Trim().ToLowerInvariant(),
135 };
136 }
137
138 internal static string NormalizeFormat(string? format)
139 {
140 if (string.IsNullOrWhiteSpace(format))
141 return "unknown";
142
143 return format.Trim().ToLowerInvariant() switch
144 {
145 "exe" or "winexe" => "exe",
146 "msi" or "wix" => "msi",
147 "zip" or "archive" => "zip",
148 "nupkg" or "nuget" => "nupkg",
149 _ => format.Trim().ToLowerInvariant(),
150 };
151 }
152}
153
View only · write via MCP/CIDE