Skip to content

Upgrade to Zig 0.15.2 - #38

Merged
christianhelle merged 7 commits into
mainfrom
zig-0.15.2
Feb 15, 2026
Merged

Upgrade to Zig 0.15.2#38
christianhelle merged 7 commits into
mainfrom
zig-0.15.2

Conversation

@christianhelle

@christianhelle christianhelle commented Feb 14, 2026

Copy link
Copy Markdown
Owner
  • Target Zig 0.15.2
  • Fix memory leak: free duped server descriptions in OpenAPI converter
  • Remove unnecessary seekBy(0) and deduplicate file writing logic
  • Use proper error format specifier {} instead of {any}
  • Fix compile errors in legacy generators: add missing allocator args and fix self references in free functions
  • Fix generated code: ArrayList.deinit() requires allocator argument in Zig 0.15
  • Use proper error format specifier {} instead of {any} in test files

Summary by CodeRabbit

  • Chores

    • Updated minimum Zig version requirement from 0.15.1 to 0.15.2 across development environment, CI/CD workflows, and documentation.
  • Bug Fixes

    • Improved allocator handling in code generation pipelines.
    • Enhanced error message formatting for better debugging.

Copilot AI review requested due to automatic review settings February 14, 2026 14:52
@coderabbitai

coderabbitai Bot commented Feb 14, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

This PR performs a Zig toolchain version bump from 0.15.1 to 0.15.2 across configuration and documentation files, refactors code generators to propagate allocators through function parameters instead of using instance state, adds explicit allocation-tracking flags to the Server struct, simplifies output path handling in the main generator, and standardizes error formatting across test files.

Changes

Cohort / File(s) Summary
Version Upgrade
.devcontainer/*, .github/copilot-instructions.md, .github/workflows/*, README.md, build.zig.zon, docs/index.html, examples/PACKAGE.md
Bumped Zig version from 0.15.1 to 0.15.2 across all configuration, workflow, and documentation files.
Allocator Refactoring
src/generators/v2.0/apigenerator.zig, src/generators/v2.0/modelgenerator.zig, src/generators/v3.0/apigenerator.zig
Propagated allocator parameter through generator helper functions; replaced self.allocator references with explicit allocator parameter usage for string concatenation and memory operations.
Memory Management & Tracking
src/models/common/document.zig, src/generators/converters/openapi_converter.zig
Added _description_allocated field to Server struct and updated deinit logic to conditionally free description; OpenApiConverter now sets allocation-tracking flags when constructing Server instances.
Generator Logic & Unified Path
src/generator.zig, src/generators/unified/api_generator.zig
Simplified output path resolution using orelse operator; removed unnecessary initial file seek; fixed allocator parameter in unified API generator deinit call.
Error Formatting
src/main.zig, src/tests/comprehensive_converter_tests.zig, src/tests/openapi_v3_tests.zig, src/tests/swagger_v2_tests.zig, src/tests/unified_converter_tests.zig
Standardized error format placeholders from {any} to {} across error logging statements.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

  • Issue #34: Addresses Zig toolchain version upgrade across the repository, directly aligned with the version bump portion of this PR.

Possibly related PRs

  • PR #36: Overlaps significantly with allocator-driven refactoring (ArrayList init/deinit changes and allocator propagation in generators/models) and Zig version bump across the same functions and files.
  • PR #25: Modifies the same test files (comprehensive_converter_tests, openapi_v3_tests, swagger_v2_tests, unified_converter_tests) that receive error formatting updates in this PR.
  • PR #24: Related through unified OpenAPI/Swagger pipeline changes and modifications to src/generator.zig (generateCodeFromUnifiedDocument and converter/generator delegation).

Suggested labels

enhancement, documentation

Poem

🐰 A version hops forward, so bright and so new,
Allocators flow freely, through functions they brew,
Memory tracked cleanly with flags set just right,
Code organized neatly from morning to night!

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Upgrade to Zig 0.15.2' directly corresponds to the main change across the PR: updating the Zig toolchain version from 0.15.1 to 0.15.2 in configuration files, documentation, and code. While the PR also includes secondary refactoring (allocator fixes, format specifier changes), the primary theme is the version upgrade.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into main

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch zig-0.15.2

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In @.github/copilot-instructions.md:
- Around line 365-367: The troubleshooting text is ambiguous about allowed Zig
versions; update the lines containing the strings "zig: command not found",
"Wrong Zig version", and the phrase "not 0.13.x or 0.15.x" to explicitly require
Zig 0.15.2 and to clarify that other 0.15.y releases (e.g., 0.15.0/0.15.1) are
not acceptable; reword to read something like "Install Zig 0.15.2 exactly" and
"Ensure you're using Zig 0.15.2 (do not use 0.13.x or earlier 0.15.x releases
prior to 0.15.2)" so readers understand 0.15.2 is the only supported 0.15
version.

In `@src/generators/unified/api_generator.zig`:
- Around line 238-241: The generated Zig code calls str.writer() without passing
an allocator which fails in Zig 0.15.2; update the generator call site that
writes the stringify line (the appendSlice invocation that emits "try
std.json.stringify(requestBody, .{}, str.writer());") to instead emit "try
std.json.stringify(requestBody, .{}, str.writer(allocator));". Apply the same
change wherever this string is emitted (notably in the apigenerator
implementations that produce that line for unified, v2.0, and v3.0) so the
generated code calls str.writer(allocator) and compiles.
🧹 Nitpick comments (3)
src/tests/swagger_v2_tests.zig (1)

9-9: Unnecessary seekBy(0) call still present.

The PR description states "Remove unnecessary seekBy(0) calls," but loadSwaggerDocument still has try file.seekBy(0); on Line 9. This is a no-op (seeking by 0 bytes from the current position) and should be removed for consistency with the stated objective.

Proposed fix
 fn loadSwaggerDocument(allocator: std.mem.Allocator, file_path: []const u8) !models.SwaggerDocument {
     const file = try std.fs.cwd().openFile(file_path, .{});
     defer file.close();
-    try file.seekBy(0);
     const file_contents = try file.readToEndAlloc(allocator, std.math.maxInt(usize));
     defer allocator.free(file_contents);
     return try models.SwaggerDocument.parseFromJson(allocator, file_contents);
 }
src/tests/unified_converter_tests.zig (1)

10-10: Unnecessary seekBy(0) call remains.

The PR description mentions removing unnecessary seekBy(0) calls. This one on Line 10 (and Line 19) still exists. A file opened for reading is already at position 0.

♻️ Remove no-op seek
     const file = try std.fs.cwd().openFile(file_path, .{});
     defer file.close();
-    try file.seekBy(0);
     const file_contents = try file.readToEndAlloc(allocator, std.math.maxInt(usize));
src/tests/comprehensive_converter_tests.zig (1)

10-10: Same unnecessary seekBy(0) as in other test files.

Same as in unified_converter_tests.zig — Lines 10 and 19 have no-op seekBy(0) calls that could be removed.

Comment on lines +365 to +367
- **"zig: command not found"**: Install Zig 0.15.2 exactly using methods above
- **Wrong Zig version**: Uninstall other versions, install 0.15.2 specifically
- **Build failures**: Ensure you're using Zig 0.15.2, not 0.13.x or 0.15.x

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Ambiguous version reference in troubleshooting.

Line 367 says "not 0.13.x or 0.15.x" but 0.15.2 is 0.15.x. This could confuse readers.

📝 Suggested fix
-- **Build failures**: Ensure you're using Zig 0.15.2, not 0.13.x or 0.15.x
+- **Build failures**: Ensure you're using Zig 0.15.2, not 0.13.x or 0.14.x
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- **"zig: command not found"**: Install Zig 0.15.2 exactly using methods above
- **Wrong Zig version**: Uninstall other versions, install 0.15.2 specifically
- **Build failures**: Ensure you're using Zig 0.15.2, not 0.13.x or 0.15.x
- **"zig: command not found"**: Install Zig 0.15.2 exactly using methods above
- **Wrong Zig version**: Uninstall other versions, install 0.15.2 specifically
- **Build failures**: Ensure you're using Zig 0.15.2, not 0.13.x or 0.14.x
🤖 Prompt for AI Agents
In @.github/copilot-instructions.md around lines 365 - 367, The troubleshooting
text is ambiguous about allowed Zig versions; update the lines containing the
strings "zig: command not found", "Wrong Zig version", and the phrase "not
0.13.x or 0.15.x" to explicitly require Zig 0.15.2 and to clarify that other
0.15.y releases (e.g., 0.15.0/0.15.1) are not acceptable; reword to read
something like "Install Zig 0.15.2 exactly" and "Ensure you're using Zig 0.15.2
(do not use 0.13.x or earlier 0.15.x releases prior to 0.15.2)" so readers
understand 0.15.2 is the only supported 0.15 version.

Comment on lines 238 to 241
try self.buffer.appendSlice(self.allocator, " var str = std.ArrayList(u8){};\n");
try self.buffer.appendSlice(self.allocator, " defer str.deinit();\n\n");
try self.buffer.appendSlice(self.allocator, " defer str.deinit(allocator);\n\n");
try self.buffer.appendSlice(self.allocator, " try std.json.stringify(requestBody, .{}, str.writer());\n");
try self.buffer.appendSlice(self.allocator, " const payload = str.items;\n\n");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

cat -n src/generators/unified/api_generator.zig | sed -n '230,250p'

Repository: christianhelle/openapi2zig

Length of output: 1629


🏁 Script executed:

# Also check what other .writer() calls exist in the codebase to understand the pattern
rg -n '\.writer\(' --type=zig -C 2

Repository: christianhelle/openapi2zig

Length of output: 2217


🏁 Script executed:

# Check build.zig for Zig version requirement
rg -n "zig_version\|\.builder\|minimum_zig" build.zig -A 3

Repository: christianhelle/openapi2zig

Length of output: 52


🏁 Script executed:

# Check if there's a build.zig.zon or version file
ls -la build.zig.zon 2>/dev/null || echo "No build.zig.zon found"
head -20 build.zig.zon 2>/dev/null || echo "File not found"

Repository: christianhelle/openapi2zig

Length of output: 1056


🏁 Script executed:

# Check what Zig version is mentioned anywhere in the repo
rg -i "zig.*0\.15\|0\.15.*zig" --type-list | head -20

Repository: christianhelle/openapi2zig

Length of output: 459


🏁 Script executed:

# Check build.zig for Zig version constraints
cat -n build.zig | head -30

Repository: christianhelle/openapi2zig

Length of output: 1224


🏁 Script executed:

# Check GitHub workflows for Zig version used
find .github -name "*.yml" -o -name "*.yaml" | xargs grep -l "zig" 2>/dev/null | head -3

Repository: christianhelle/openapi2zig

Length of output: 156


🏁 Script executed:

# Search for any mention of Zig version in workflows
find .github -name "*.yml" -o -name "*.yaml" -exec grep -n "zig\|0\.15" {} + 2>/dev/null | head -20

Repository: christianhelle/openapi2zig

Length of output: 52


🏁 Script executed:

# Check the CI workflow for Zig version
cat .github/workflows/ci.yml

Repository: christianhelle/openapi2zig

Length of output: 4339


🏁 Script executed:

# Check if there's generated code examples in the repo or test fixtures
find . -name "*.zig" -path "*/generated/*" 2>/dev/null | head -5

Repository: christianhelle/openapi2zig

Length of output: 90


🏁 Script executed:

# Check test files to see how generated code is tested
rg -l "stringify\|ArrayList" src/tests/ --type=zig | head -5

Repository: christianhelle/openapi2zig

Length of output: 52


🏁 Script executed:

# Let's check if there are any usages of ArrayList.writer() with allocator in the codebase
rg "\.writer\(.*allocator" --type=zig

Repository: christianhelle/openapi2zig

Length of output: 52


🌐 Web query:

Zig 0.15.2 ArrayList writer method allocator parameter signature

💡 Result:

In Zig 0.15.2, std.ArrayList(T) is the unmanaged ArrayList, so the writer method (only available for u8) takes an allocator explicitly:

pub fn writer(self: *std.ArrayList(u8), allocator: std.mem.Allocator) Writer

Call-site example:

var w = arraylist.writer(allocator);

Writer here is the old std.io.Writer-style writer, commonly used via .adaptToNewApi(...) when you need the new std.Io interfaces. [1]

Why it takes an allocator: in 0.15.x, ArrayList no longer stores an allocator internally; you pass it to any operation that may allocate (including writing/appending). [2]

Sources: [1] [3]


🏁 Script executed:

# Let's verify the exact generated code content by checking line 240 again
sed -n '238,241p' src/generators/unified/api_generator.zig | cat -A

Repository: christianhelle/openapi2zig

Length of output: 532


🏁 Script executed:

# Check if this is the complete picture - look at context around the generated code
sed -n '235,245p' src/generators/unified/api_generator.zig

Repository: christianhelle/openapi2zig

Length of output: 973


Fix the generated code to pass allocator to str.writer() on line 240.

In Zig 0.15.2, ArrayList(u8).writer() requires an allocator parameter. The generated code currently emits str.writer() without the allocator, which will cause a compilation error. Change it to str.writer(allocator).

Current code
try self.buffer.appendSlice(self.allocator, "    try std.json.stringify(requestBody, .{}, str.writer());\n");

The same issue exists in src/generators/v2.0/apigenerator.zig (line 227) and src/generators/v3.0/apigenerator.zig (line 210).

🤖 Prompt for AI Agents
In `@src/generators/unified/api_generator.zig` around lines 238 - 241, The
generated Zig code calls str.writer() without passing an allocator which fails
in Zig 0.15.2; update the generator call site that writes the stringify line
(the appendSlice invocation that emits "try std.json.stringify(requestBody, .{},
str.writer());") to instead emit "try std.json.stringify(requestBody, .{},
str.writer(allocator));". Apply the same change wherever this string is emitted
(notably in the apigenerator implementations that produce that line for unified,
v2.0, and v3.0) so the generated code calls str.writer(allocator) and compiles.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR upgrades the repository to target Zig 0.15.2 and adjusts codegen, converters, and tests to accommodate Zig 0.15 API changes (notably ArrayList allocator-aware APIs), while also addressing a server-description memory leak in the OpenAPI v3 converter.

Changes:

  • Bump Zig version references across build metadata, CI/release workflows, devcontainer setup, and docs to 0.15.2.
  • Update generators/tests to use Zig 0.15-compatible formatting and ArrayList deinit/append APIs.
  • Fix OpenAPI converter server handling by tracking/freing duplicated server descriptions.

Reviewed changes

Copilot reviewed 21 out of 21 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/tests/unified_converter_tests.zig Switch debug printing from {any} to {} for errors.
src/tests/swagger_v2_tests.zig Switch debug printing from {any} to {} for errors.
src/tests/openapi_v3_tests.zig Switch debug printing from {any} to {} for errors.
src/tests/comprehensive_converter_tests.zig Switch debug printing from {any} to {} for errors.
src/models/common/document.zig Track and free allocated server descriptions in Server.deinit.
src/main.zig Use {} error formatting when reporting generation failures.
src/generator.zig Remove redundant seek, use {} error formatting, and deduplicate output-file writing logic.
src/generators/converters/openapi_converter.zig Mark duplicated server fields as allocated to prevent leaks.
src/generators/unified/api_generator.zig Update generated code to call ArrayList.deinit(allocator) in Zig 0.15.
src/generators/v3.0/apigenerator.zig Update legacy generator to allocator-aware ArrayList APIs and deinit signatures.
src/generators/v2.0/modelgenerator.zig Thread allocator through schema generation helpers for Zig 0.15 ArrayList API.
src/generators/v2.0/apigenerator.zig Update legacy generator to allocator-aware ArrayList APIs and deinit signatures.
build.zig.zon Raise .minimum_zig_version to 0.15.2.
README.md Update stated Zig prerequisite/version badge to 0.15.2.
examples/PACKAGE.md Update package publishing/docs to Zig 0.15.2.
docs/index.html Update website Zig badge and dev-env prerequisite text to 0.15.2.
.github/workflows/ci.yml Run CI with Zig 0.15.2.
.github/workflows/release.yml Run release workflow with Zig 0.15.2.
.github/copilot-instructions.md Update contributor instructions to Zig 0.15.2.
.devcontainer/devcontainer.json Update devcontainer Zig feature version to 0.15.2.
.devcontainer/README.md Update devcontainer docs to Zig 0.15.2.

Comment on lines 141 to 143
for (params) |paramOrReference| {
const parameter = paramOrReference.parameter;
if (!std.mem.eql(u8, parameter.in_field, "path") and !std.mem.eql(u8, parameter.in_field, "body")) {

Copilot AI Feb 14, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In generateImplementation, paramOrReference is a union(enum) (parameter vs reference), but the code unconditionally reads paramOrReference.parameter. If a $ref parameter appears, this will trigger an invalid union field access at runtime (or a safety trap in Debug/ReleaseSafe). Handle the union with a switch and either resolve references or skip them before accessing Parameter fields.

Copilot uses AI. Check for mistakes.
Comment on lines +208 to +212
try parts.append(allocator, " var str = std.ArrayList([]const u8){};\n");
try parts.append(allocator, " defer str.deinit(allocator);\n\n");
try parts.append(allocator, " try std.json.stringify(requestBody, .{}, str.writer());\n");
try parts.append(allocator, " const body = try std.mem.join(allocator, \"\", str.items);\n");
try parts.append(allocator, " defer allocator.free(body);\n\n");

Copilot AI Feb 14, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The generated request-body code uses std.ArrayList([]const u8) with std.json.stringify(..., str.writer()). stringify writes bytes, so the generated code should use a byte buffer (e.g., std.ArrayList(u8)) rather than an array of slices; otherwise the generated client code will not compile/work correctly.

Suggested change
try parts.append(allocator, " var str = std.ArrayList([]const u8){};\n");
try parts.append(allocator, " defer str.deinit(allocator);\n\n");
try parts.append(allocator, " try std.json.stringify(requestBody, .{}, str.writer());\n");
try parts.append(allocator, " const body = try std.mem.join(allocator, \"\", str.items);\n");
try parts.append(allocator, " defer allocator.free(body);\n\n");
try parts.append(allocator, " var str = std.ArrayList(u8).init(allocator);\n");
try parts.append(allocator, " defer str.deinit();\n\n");
try parts.append(allocator, " try std.json.stringify(requestBody, .{}, str.writer());\n");
try parts.append(allocator, " const body = str.items;\n\n");

Copilot uses AI. Check for mistakes.
Comment on lines +225 to +229
try parts.append(allocator, " var str = std.ArrayList([]const u8){};\n");
try parts.append(allocator, " defer str.deinit(allocator);\n\n");
try parts.append(allocator, " try std.json.stringify(requestBody, .{}, str.writer());\n");
try parts.append(allocator, " const body = try std.mem.join(allocator, \"\", str.items);\n");
try parts.append(allocator, " defer allocator.free(body);\n\n");

Copilot AI Feb 14, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The generated request-body code uses std.ArrayList([]const u8) with std.json.stringify(..., str.writer()). Since stringify writes bytes, the generated code should use a byte buffer (e.g., std.ArrayList(u8)) rather than an array of slices; otherwise the generated client code will not compile/work correctly.

Suggested change
try parts.append(allocator, " var str = std.ArrayList([]const u8){};\n");
try parts.append(allocator, " defer str.deinit(allocator);\n\n");
try parts.append(allocator, " try std.json.stringify(requestBody, .{}, str.writer());\n");
try parts.append(allocator, " const body = try std.mem.join(allocator, \"\", str.items);\n");
try parts.append(allocator, " defer allocator.free(body);\n\n");
try parts.append(allocator, " var str = std.ArrayList(u8){};\n");
try parts.append(allocator, " defer str.deinit(allocator);\n\n");
try parts.append(allocator, " try std.json.stringify(requestBody, .{}, str.writer());\n");
try parts.append(allocator, " const body = str.items;\n\n");

Copilot uses AI. Check for mistakes.
Comment on lines 95 to 106
fn convertServers(self: *OpenApiConverter, servers: []Server3) ![]Server {
var converted_servers = try self.allocator.alloc(Server, servers.len);
for (servers, 0..) |server, i| {
const url = try self.allocator.dupe(u8, server.url);
const description = if (server.description) |desc| try self.allocator.dupe(u8, desc) else null;
converted_servers[i] = Server{ .url = url, .description = description };
converted_servers[i] = Server{
.url = url,
.description = description,
._url_allocated = true,
._description_allocated = description != null,
};
}

Copilot AI Feb 14, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

convertServers now duplicates both url and description, but if an allocation fails partway through the loop, previously-duped strings (and the converted_servers array) will leak because there is no errdefer cleanup for the partially-built slice. Add error-path cleanup that frees any already-allocated Server fields before returning the error.

Copilot uses AI. Check for mistakes.
Comment thread docs/index.html

<div class="manual-setup-note">
<strong>Prerequisites:</strong> Zig v0.15.1 or later
<strong>Prerequisites:</strong> Zig v0.15.2 or later

Copilot AI Feb 14, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

docs/index.html says "Zig v0.15.2 or later", but other updated docs in this PR state 0.15.2 is required exactly. This is inconsistent and may confuse contributors/users; align the website text with the project’s stated compatibility (or update the other docs to match if newer Zig versions are actually supported).

Suggested change
<strong>Prerequisites:</strong> Zig v0.15.2 or later
<strong>Prerequisites:</strong> Zig v0.15.1 (exact version required)

Copilot uses AI. Check for mistakes.
@christianhelle

Copy link
Copy Markdown
Owner Author

@copilot open a new pull request to apply changes based on the comments in this thread

Copilot AI commented Feb 15, 2026

Copy link
Copy Markdown
Contributor

@christianhelle I've opened a new pull request, #39, to work on those changes. Once the pull request is ready, I'll request review from you.

@christianhelle
christianhelle merged commit c44b641 into main Feb 15, 2026
26 checks passed
@christianhelle
christianhelle deleted the zig-0.15.2 branch February 15, 2026 12:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants