ReviewOS

also looking at this

zig-utils/zig-test-framework

build: single-source the package and CLI version

#20
Merged glennmichael123 wants to merge codex/issue-13-version into main
7 files +40 -11
CONTRIBUTING.mdmodified+2-1
Changes to CONTRIBUTING.md
@@ -328,7 +328,8 @@ We follow [Semantic Versioning](https://semver.org/):
328328
329329### Release Steps
330330
3311. Update version in `build.zig.zon`
3311. Update version in `build.zig.zon`. This is the authoritative package
332 version; the build injects it into `zig-test --version` automatically.
3323332. Update CHANGELOG.md
3333343. Create git tag: `git tag -a v1.2.3 -m "Release 1.2.3"`
3343354. Push tag: `git push origin v1.2.3`
FEATURES_SUMMARY.mdmodified+2-2
Changes to FEATURES_SUMMARY.md
@@ -1,6 +1,6 @@
11# Zig Test Framework - Features Summary
22
3**Framework Version:** 2.3.0
3**Framework Version:** See `build.zig.zon` (the authoritative version source)
44**Last Updated:** 2025-10-26
55**Status:** Production Ready
66
@@ -537,5 +537,5 @@ The framework is ready for production use and provides a comprehensive testing s
537537---
538538
539539**Last Updated:** 2025-10-26
540**Framework Version:** 2.3.0
540**Framework Version:** See `build.zig.zon` (the authoritative version source)
541541**Status:** Production Ready ✅
README.mdmodified+3-3
Changes to README.md
@@ -35,11 +35,11 @@ Add to your `build.zig.zon`:
3535```zig
3636.{
3737 .name = "my-project",
38 .version = "0.1.0",
38 .version = "0.1.0", // Your project's version
3939 .dependencies = .{
4040 .@"zig-test-framework" = .{
41 .url = "https://github.com/zig-utils/zig-test-framework/archive/refs/tags/v0.1.0.tar.gz",
42 // Replace with actual hash after publishing
41 .url = "https://github.com/zig-utils/zig-test-framework/archive/refs/tags/vX.Y.Z.tar.gz",
42 // Replace X.Y.Z and the hash with the release you use
4343 },
4444 },
4545}
build.zigmodified+23-0
Changes to build.zig
@@ -1,19 +1,37 @@
11const std = ;
2const manifest_source = @embedFile("build.zig.zon");
3const package_version = manifestVersion(manifest_source);
4
5fn manifestVersion(source: []const u8) []const u8 {
6 const marker = ".version = \"";
7 const marker_start = std.mem.indexOf(u8, source, marker) orelse
8 @compileError("build.zig.zon must declare .version");
9 const start = marker_start + marker.len;
10 const end_offset = std.mem.indexOfScalar(u8, source[start..], '"') orelse
11 @compileError("build.zig.zon contains an unterminated .version");
12 return source[start .. start + end_offset];
13}
214
315pub fn build(b: *std.Build) void {
416 const target = b.standardTargetOptions(.{});
517 const optimize = b.standardOptimizeOption(.{});
618
19 const build_options = b.addOptions();
20 build_options.addOption([]const u8, "version", package_version);
21
722 // Create the main library module
823 const lib_module = b.addModule("zig_test_framework", .{
924 .root_source_file = b.path("src/lib.zig"),
1025 .target = target,
1126 .link_libc = true,
1227 });
28 lib_module.addOptions("build_options", build_options);
1329
1430 // Create the test runner executable
1531 const exe = b.addExecutable(.{
1632 .name = "zig-test",
33 .version = std.SemanticVersion.parse(package_version) catch
34 @panic("build.zig.zon contains an invalid semantic version"),
1735 .root_module = b.createModule(.{
1836 .root_source_file = b.path("src/main.zig"),
1937 .target = target,
@@ -258,6 +276,11 @@ pub fn build(b: *std.Build) void {
258276 run_invalid_config.expectExitCode(2);
259277 test_step.dependOn(&run_invalid_config.step);
260278
279 const run_version = b.addRunArtifact(exe);
280 run_version.addArg("--version");
281 run_version.expectStdErrEqual(b.fmt("Zig Test Framework v{s}\n", .{package_version}));
282 test_step.dependOn(&run_version.step);
283
261284 // Examples
262285 const basic_example = b.addExecutable(.{
263286 .name = "basic_example",
package.jsonmodified+0-1
Changes to package.json
@@ -1,6 +1,5 @@
11{
22 "name": "zig-test-framework",
3 "version": "0.2.0",
43 "scripts": {
54 "release": "pantry release patch --yes",
65 "release:minor": "pantry release minor --yes",
src/cli.zigmodified+8-2
Changes to src/cli.zig
@@ -1,4 +1,5 @@
11const std = ;
2const build_options = ;
23const config_mod = ;
34const test_runner = ;
45
@@ -44,6 +45,8 @@ pub const CLIOptions = struct {
4445 timeout: ?u64 = null, // Global timeout in milliseconds
4546};
4647
48pub const version = build_options.version;
49
4750pub const CLIError = error{
4851 InvalidArgument,
4952 MissingValue,
@@ -383,8 +386,7 @@ pub const CLI = struct {
383386 /// Print version information
384387 pub fn printVersion(self: Self) void {
385388 _ = self;
386 std.debug.print("Zig Test Framework v2.5.0\n", .{});
387 std.debug.print("Features: Parallel, Coverage, UI, Snapshots, Watch, Memory Profiling, TAP/JUnit, Progress Indicators, Timeout\n", .{});
389 std.debug.print("Zig Test Framework v{s}\n", .{version});
388390 }
389391
390392 /// Convert CLI options to RunnerOptions
@@ -423,6 +425,10 @@ test "CLI parse version" {
423425 try std.testing.expect(cli.options.version);
424426}
425427
428test "CLI build version is valid semantic version metadata" {
429 _ = try std.SemanticVersion.parse(version);
430}
431
426432test "CLI parse bail" {
427433 var cli = CLI.init(std.testing.allocator);
428434 const args = [_][]const u8{ "zig-test", "--bail" };
src/main.zigmodified+2-2
Changes to src/main.zig
@@ -1,6 +1,6 @@
11const std = ;
2const lib = ;
3const compat = ;
2const lib = ;
3const compat = lib.compat;
44
55// Global signal handler state
66var shutdown_requested = std.atomic.Value(bool).init(false);