7b3809e8339a
read only canonical 'notes' field in releaseNotesFromMetadata; drop release_notes/changelog fallbacks; v3.4.1
- time
- 2026-06-15 13:44 UTC · 4 months ago
- machine
- koh2
- agent
- claude-opus-4-8
- session
- release notes field standardization
- parent
- d7e14c6e0d10
↓ nina-7b3809e8.tar.gzatlas at this save
files changed3 files
VERSION+1 −1build.zig.zon+1 −1src/commands.zig+29 −9build.zig.zon+1 −1
@@ -9,7 +9,7 @@99 .name = .nina,1010 // This is a [Semantic Version](https://semver.org/).1111 // In a future version of Zig it will be used for package deduplication.12- .version = "3.4.0",12+ .version = "3.4.1",1313 // Together with name, this represents a globally unique package1414 // identifier. This field is generated by the Zig toolchain when the1515 // package is first created, and then *never changes*. This allowssrc/commands.zig+29 −9
@@ -520,15 +520,14 @@520520 521521 fn releaseNotesFromMetadata(gpa: std.mem.Allocator, root: std.json.Value) ?[]u8 {522522 if (root != .object) return null;523- const keys = [_][]const u8{ "release_notes", "changelog", "notes" };524- for (keys) |key| {525- const v = root.object.get(key) orelse continue;526- switch (v) {527- .string => |s| return gpa.dupe(u8, s) catch null,528- else => {},529- }530- }531- return null;523+ // `notes` is the one canonical manifest field. The retired `release_notes`524+ // and `changelog` fallbacks are gone — Kepr now emits `notes` everywhere, and525+ // releases that predate `--notes` fall back to archives.json in the caller.526+ const v = root.object.get("notes") orelse return null;527+ return switch (v) {528+ .string => |s| gpa.dupe(u8, s) catch null,529+ else => null,530+ };532531 }533532 534533 fn buildKeprArchiveReleaseNotes(gpa: std.mem.Allocator, io: std.Io, source_url: []const u8, current: []const u8, latest: []const u8) ![]u8 {@@ -684,6 +683,27 @@684683 try std.testing.expect(std.mem.indexOf(u8, notes, "- add streaming deflate path") != null);685684 try std.testing.expect(std.mem.indexOf(u8, notes, "CONTINUITY") == null);686685 try std.testing.expect(std.mem.indexOf(u8, notes, "old release") == null);686+}687+688+test "releaseNotesFromMetadata reads canonical notes and ignores retired keys" {689+ const a = std.testing.allocator;690+691+ // Canonical field is read.692+ {693+ var parsed = try std.json.parseFromSlice(std.json.Value, a, "{\"notes\":\"colored progress bar\"}", .{});694+ defer parsed.deinit();695+ const got = releaseNotesFromMetadata(a, parsed.value).?;696+ defer a.free(got);697+ try std.testing.expectEqualStrings("colored progress bar", got);698+ }699+700+ // Retired field names are no longer honoured — they fall through to null so701+ // the caller drops to the archives.json derivation instead.702+ {703+ var parsed = try std.json.parseFromSlice(std.json.Value, a, "{\"release_notes\":\"x\",\"changelog\":\"y\"}", .{});704+ defer parsed.deinit();705+ try std.testing.expect(releaseNotesFromMetadata(a, parsed.value) == null);706+ }687707 }688708 689709 // nina goodbye — clean uninstall. Three install paths: