Merge pull request #1917 from lightpanda-io/semantic-versioning

build: automate version resolution in build.zig
This commit is contained in:
Pierre Tachoire
2026-03-25 08:46:04 +01:00
committed by GitHub
11 changed files with 79 additions and 51 deletions

View File

@@ -27,7 +27,7 @@ jobs:
- uses: ./.github/actions/install
- name: zig build release
run: zig build -Dprebuilt_v8_path=v8/libc_v8.a -Doptimize=ReleaseFast -Dcpu=x86_64 -Dgit_commit=$(git rev-parse --short ${{ github.sha }})
run: zig build -Dprebuilt_v8_path=v8/libc_v8.a -Doptimize=ReleaseFast -Dcpu=x86_64
- name: upload artifact
uses: actions/upload-artifact@v7

View File

@@ -52,7 +52,7 @@ jobs:
- uses: ./.github/actions/install
- name: zig build release
run: zig build -Dprebuilt_v8_path=v8/libc_v8.a -Doptimize=ReleaseFast -Dcpu=x86_64 -Dgit_commit=$(git rev-parse --short ${{ github.sha }})
run: zig build -Dprebuilt_v8_path=v8/libc_v8.a -Doptimize=ReleaseFast -Dcpu=x86_64
- name: upload artifact
uses: actions/upload-artifact@v7

View File

@@ -7,7 +7,7 @@ env:
AWS_REGION: ${{ vars.NIGHTLY_BUILD_AWS_REGION }}
RELEASE: ${{ github.ref_type == 'tag' && github.ref_name || 'nightly' }}
GIT_VERSION_FLAG: ${{ github.ref_type == 'tag' && format('-Dgit_version={0}', github.ref_name) || '' }}
VERSION: ${{ github.ref_type == 'tag' && github.ref_name || '1.0.0-nightly' }}
on:
push:
@@ -45,7 +45,7 @@ jobs:
run: zig build -Dprebuilt_v8_path=v8/libc_v8.a -Doptimize=ReleaseFast snapshot_creator -- src/snapshot.bin
- name: zig build
run: zig build -Dsnapshot_path=../../snapshot.bin -Dprebuilt_v8_path=v8/libc_v8.a -Doptimize=ReleaseFast -Dcpu=x86_64 -Dgit_commit=$(git rev-parse --short ${{ github.sha }}) ${{ env.GIT_VERSION_FLAG }}
run: zig build -Dsnapshot_path=../../snapshot.bin -Dprebuilt_v8_path=v8/libc_v8.a -Doptimize=ReleaseFast -Dcpu=x86_64 -Dversion_string=${{ env.VERSION }}
- name: Rename binary
run: mv zig-out/bin/lightpanda lightpanda-${{ env.ARCH }}-${{ env.OS }}
@@ -85,7 +85,7 @@ jobs:
run: zig build -Dprebuilt_v8_path=v8/libc_v8.a -Doptimize=ReleaseFast snapshot_creator -- src/snapshot.bin
- name: zig build
run: zig build -Dsnapshot_path=../../snapshot.bin -Dprebuilt_v8_path=v8/libc_v8.a -Doptimize=ReleaseFast -Dcpu=generic -Dgit_commit=$(git rev-parse --short ${{ github.sha }}) ${{ env.GIT_VERSION_FLAG }}
run: zig build -Dsnapshot_path=../../snapshot.bin -Dprebuilt_v8_path=v8/libc_v8.a -Doptimize=ReleaseFast -Dcpu=generic -Dversion_string=${{ env.VERSION }}
- name: Rename binary
run: mv zig-out/bin/lightpanda lightpanda-${{ env.ARCH }}-${{ env.OS }}
@@ -127,7 +127,7 @@ jobs:
run: zig build -Dprebuilt_v8_path=v8/libc_v8.a -Doptimize=ReleaseFast snapshot_creator -- src/snapshot.bin
- name: zig build
run: zig build -Dsnapshot_path=../../snapshot.bin -Dprebuilt_v8_path=v8/libc_v8.a -Doptimize=ReleaseFast -Dgit_commit=$(git rev-parse --short ${{ github.sha }}) ${{ env.GIT_VERSION_FLAG }}
run: zig build -Dsnapshot_path=../../snapshot.bin -Dprebuilt_v8_path=v8/libc_v8.a -Doptimize=ReleaseFast -Dversion_string=${{ env.VERSION }}
- name: Rename binary
run: mv zig-out/bin/lightpanda lightpanda-${{ env.ARCH }}-${{ env.OS }}
@@ -167,7 +167,7 @@ jobs:
run: zig build -Dprebuilt_v8_path=v8/libc_v8.a -Doptimize=ReleaseFast snapshot_creator -- src/snapshot.bin
- name: zig build
run: zig build -Dsnapshot_path=../../snapshot.bin -Dprebuilt_v8_path=v8/libc_v8.a -Doptimize=ReleaseFast -Dgit_commit=$(git rev-parse --short ${{ github.sha }}) ${{ env.GIT_VERSION_FLAG }}
run: zig build -Dsnapshot_path=../../snapshot.bin -Dprebuilt_v8_path=v8/libc_v8.a -Doptimize=ReleaseFast -Dversion_string=${{ env.VERSION }}
- name: Rename binary
run: mv zig-out/bin/lightpanda lightpanda-${{ env.ARCH }}-${{ env.OS }}

View File

@@ -40,7 +40,7 @@ jobs:
run: zig build -Dprebuilt_v8_path=v8/libc_v8.a -Doptimize=ReleaseFast snapshot_creator -- src/snapshot.bin
- name: zig build release
run: zig build -Dsnapshot_path=../../snapshot.bin -Dprebuilt_v8_path=v8/libc_v8.a -Doptimize=ReleaseFast -Dcpu=generic -Dgit_commit=$(git rev-parse --short ${{ github.sha }})
run: zig build -Dsnapshot_path=../../snapshot.bin -Dprebuilt_v8_path=v8/libc_v8.a -Doptimize=ReleaseFast -Dcpu=generic
- name: upload artifact
uses: actions/upload-artifact@v7

View File

@@ -53,8 +53,7 @@ RUN zig build -Doptimize=ReleaseFast \
# build release
RUN zig build -Doptimize=ReleaseFast \
-Dsnapshot_path=../../snapshot.bin \
-Dprebuilt_v8_path=v8/libc_v8.a \
-Dgit_commit=$(git rev-parse --short HEAD)
-Dprebuilt_v8_path=v8/libc_v8.a
FROM debian:stable-slim

View File

@@ -58,13 +58,13 @@ build-v8-snapshot:
## Build in release-fast mode
build: build-v8-snapshot
@printf "\033[36mBuilding (release fast)...\033[0m\n"
@$(ZIG) build -Doptimize=ReleaseFast -Dsnapshot_path=../../snapshot.bin -Dgit_commit=$$(git rev-parse --short HEAD) || (printf "\033[33mBuild ERROR\033[0m\n"; exit 1;)
@$(ZIG) build -Doptimize=ReleaseFast -Dsnapshot_path=../../snapshot.bin || (printf "\033[33mBuild ERROR\033[0m\n"; exit 1;)
@printf "\033[33mBuild OK\033[0m\n"
## Build in debug mode
build-dev:
@printf "\033[36mBuilding (debug)...\033[0m\n"
@$(ZIG) build -Dgit_commit=$$(git rev-parse --short HEAD) || (printf "\033[33mBuild ERROR\033[0m\n"; exit 1;)
@$(ZIG) build || (printf "\033[33mBuild ERROR\033[0m\n"; exit 1;)
@printf "\033[33mBuild OK\033[0m\n"
## Run the server in release mode

View File

@@ -17,24 +17,37 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
const std = @import("std");
const builtin = @import("builtin");
const Build = std.Build;
const lightpanda_version = std.SemanticVersion.parse(@import("build.zig.zon").version) catch unreachable;
const min_zig_version = std.SemanticVersion.parse(@import("build.zig.zon").minimum_zig_version) catch unreachable;
const Build = blk: {
if (builtin.zig_version.order(min_zig_version) == .lt) {
const message = std.fmt.comptimePrint(
\\Zig version is too old:
\\ current Zig version: {f}
\\ minimum Zig version: {f}
, .{ builtin.zig_version, min_zig_version });
@compileError(message);
} else {
break :blk std.Build;
}
};
pub fn build(b: *Build) !void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const manifest = Manifest.init(b);
const git_commit = b.option([]const u8, "git_commit", "Current git commit");
const git_version = b.option([]const u8, "git_version", "Current git version (from tag)");
const prebuilt_v8_path = b.option([]const u8, "prebuilt_v8_path", "Path to prebuilt libc_v8.a");
const snapshot_path = b.option([]const u8, "snapshot_path", "Path to v8 snapshot");
const version = resolveVersion(b);
var stdout = std.fs.File.stdout().writer(&.{});
try stdout.interface.print("Lightpanda {f}\n", .{version});
var opts = b.addOptions();
opts.addOption([]const u8, "version", manifest.version);
opts.addOption([]const u8, "git_commit", git_commit orelse "dev");
opts.addOption(?[]const u8, "git_version", git_version orelse null);
opts.addOption([]const u8, "version", b.fmt("{f}", .{version}));
opts.addOption(?[]const u8, "snapshot_path", snapshot_path);
const enable_tsan = b.option(bool, "tsan", "Enable Thread Sanitizer") orelse false;
@@ -96,6 +109,11 @@ pub fn build(b: *Build) !void {
}
const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step);
const version_info_step = b.step("version", "Print the resolved version information");
const version_info_run = b.addRunArtifact(exe);
version_info_run.addArg("version");
version_info_step.dependOn(&version_info_run.step);
}
{
@@ -701,27 +719,41 @@ fn buildCurl(
return lib;
}
const Manifest = struct {
version: []const u8,
minimum_zig_version: []const u8,
fn init(b: *std.Build) Manifest {
const input = @embedFile("build.zig.zon");
var diagnostics: std.zon.parse.Diagnostics = .{};
defer diagnostics.deinit(b.allocator);
return std.zon.parse.fromSlice(Manifest, b.allocator, input, &diagnostics, .{
.free_on_error = true,
.ignore_unknown_fields = true,
}) catch |err| {
switch (err) {
error.OutOfMemory => @panic("OOM"),
error.ParseZon => {
std.debug.print("Parse diagnostics:\n{f}\n", .{diagnostics});
std.process.exit(1);
},
}
/// Returns `MAJOR.MINOR.PATCH-dev` when `git describe` fails.
fn resolveVersion(b: *std.Build) std.SemanticVersion {
const version_string = b.option([]const u8, "version_string", "Override the version of this build");
if (version_string) |semver_string| {
return std.SemanticVersion.parse(semver_string) catch |err| {
std.debug.panic("Expected -Dversion-string={s} to be a semantic version: {}", .{ semver_string, err });
};
}
// If it's a stable release (no pre or build metadata in build.zig.zon), use it as is
if (lightpanda_version.pre == null and lightpanda_version.build == null) return lightpanda_version;
// For dev/nightly versions, calculate the commit count and hash
const git_hash_raw = runGit(b, &.{ "rev-parse", "--short", "HEAD" }) catch return lightpanda_version;
const commit_hash = std.mem.trim(u8, git_hash_raw, " \n\r");
const git_count_raw = runGit(b, &.{ "rev-list", "--count", "HEAD" }) catch return lightpanda_version;
const commit_count = std.mem.trim(u8, git_count_raw, " \n\r");
return .{
.major = lightpanda_version.major,
.minor = lightpanda_version.minor,
.patch = lightpanda_version.patch,
.pre = b.fmt("{s}.{s}", .{ lightpanda_version.pre.?, commit_count }),
.build = commit_hash,
};
}
/// Helper function to run git commands and return stdout
fn runGit(b: *std.Build, args: []const []const u8) ![]const u8 {
var code: u8 = undefined;
const dir = b.pathFromRoot(".");
var command: std.ArrayList([]const u8) = .empty;
defer command.deinit(b.allocator);
try command.appendSlice(b.allocator, &.{ "git", "-C", dir });
try command.appendSlice(b.allocator, args);
return b.runAllowFail(command.items, &code, .Ignore);
}

View File

@@ -1,6 +1,6 @@
.{
.name = .browser,
.version = "0.0.0",
.version = "1.0.0-dev",
.fingerprint = 0xda130f3af836cea0, // Changing this has security and trust implications.
.minimum_zig_version = "0.15.2",
.dependencies = .{

View File

@@ -47,7 +47,7 @@ pub noinline fn crash(
writer.print("\nreason: {s}\n", .{reason}) catch abort();
writer.print("OS: {s}\n", .{@tagName(builtin.os.tag)}) catch abort();
writer.print("mode: {s}\n", .{@tagName(builtin.mode)}) catch abort();
writer.print("version: {s}\n", .{lp.build_config.git_commit}) catch abort();
writer.print("version: {s}\n", .{lp.build_config.version}) catch abort();
inline for (@typeInfo(@TypeOf(args)).@"struct".fields) |f| {
writer.writeAll(f.name ++ ": ") catch break;
@import("log.zig").writeValue(.pretty, @field(args, f.name), writer) catch abort();
@@ -86,7 +86,7 @@ fn report(reason: []const u8, begin_addr: usize, args: anytype) !void {
var url_buffer: [4096]u8 = undefined;
const url = blk: {
var writer: std.Io.Writer = .fixed(&url_buffer);
try writer.print("https://crash.lightpanda.io/c?v={s}&r=", .{lp.build_config.git_commit});
try writer.print("https://crash.lightpanda.io/c?v={s}&r=", .{lp.build_config.version});
for (reason) |b| {
switch (b) {
'A'...'Z', 'a'...'z', '0'...'9', '-', '.', '_' => try writer.writeByte(b),

View File

@@ -59,11 +59,8 @@ fn run(allocator: Allocator, main_arena: Allocator) !void {
return std.process.cleanExit();
},
.version => {
if (lp.build_config.git_version) |version| {
std.debug.print("{s} ({s})\n", .{ version, lp.build_config.git_commit });
} else {
std.debug.print("{s}\n", .{lp.build_config.git_commit});
}
var stdout = std.fs.File.stdout().writer(&.{});
try stdout.interface.print("{s}\n", .{lp.build_config.version});
return std.process.cleanExit();
},
else => {},

View File

@@ -145,7 +145,7 @@ const LightPandaEvent = struct {
try writer.write(builtin.cpu.arch);
try writer.objectField("version");
try writer.write(build_config.git_version orelse build_config.git_commit);
try writer.write(build_config.version);
try writer.objectField("event");
try writer.write(@tagName(std.meta.activeTag(self.event)));