Introduce --upgrade CLI argument - #63
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
✅ Files skipped from review due to trivial changes (1)
📝 WalkthroughWalkthroughAdds a ChangesSelf-upgrade feature
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant User
participant Cli
participant Main
participant Upgrade
participant GitHubReleases
User->>Cli: run with --upgrade
Cli->>Main: parsed_args.upgrade = true
Main->>Upgrade: run(allocator, io, environ_map)
Upgrade->>GitHubReleases: fetch latest release tag
GitHubReleases-->>Upgrade: tag_name
Upgrade->>Upgrade: download and extract archive
Upgrade->>Upgrade: replaceBinary
Upgrade-->>Main: success or error.UpgradeFailed
Main-->>User: print status / return
Possibly related PRs
Suggested labels: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (4)
src/main.zig (1)
13-19: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDuplicate error output on upgrade failure.
upgrade.runalready prints a specific failure reason internally before returning the error (e.g." Failed to check for updates: {}\n"per src/upgrade.zig), and this branch prints a second, generic"Upgrade failed: {}\n"for the same error. Users will see two lines describing the same failure. Consider either dropping the wrapper print here (lettingupgrade.runown user-facing messaging) or removing the internal prints inupgrade.runand centralizing the message here.♻️ Example: let upgrade.run own the messaging
if (parsed_args.upgrade) { - upgrade.run(allocator, io, init.environ_map) catch |err| { - std.debug.print("Upgrade failed: {}\n", .{err}); - return err; - }; + try upgrade.run(allocator, io, init.environ_map); return; }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/main.zig` around lines 13 - 19, The upgrade failure path in main should not emit duplicate user-facing errors because upgrade.run already prints the specific reason internally. Update the parsed_args.upgrade branch in main.zig to either stop printing the generic "Upgrade failed" message and just return the error, or move all user-facing failure logging out of upgrade.run and centralize it here. Keep the behavior consistent by choosing one owner for the message across main and upgrade.run.src/upgrade.zig (3)
282-285: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueThis test duplicates the trim logic instead of exercising production code.
The assertions re-implement the
v-prefix stripping inline, so they pass regardless of the actual code inrun. Extract the prefix-stripping into a small helper (e.g.stripVPrefix) and test that, so the test protects the real behavior.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/upgrade.zig` around lines 282 - 285, The test in upgrade.zig is duplicating the inline v-prefix trimming logic instead of verifying the actual behavior used by run. Extract the prefix removal into a small helper such as stripVPrefix and update the version comparison test to call that helper directly, so the assertions exercise the production path rather than reimplementing it inside the test.
88-104: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winError paths discard useful diagnostics.
Every failure here collapses to a bare
error.UpgradeFailed, so users get no indication whethercurl/powershellis missing, the network call failed, or the JSON was malformed. On non-zero exit you already haveresult.stderravailable but discard it. Consider loggingresult.stderr/ the offending condition before returning.As per coding guidelines: "Use Zig error sets and
catch |err|pattern for error handling with meaningful context messages".🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/upgrade.zig` around lines 88 - 104, The upgrade flow in upgrade logic returns bare UpgradeFailed for every failure, which hides whether the command failed, stderr was emitted, or the JSON response was invalid. Update the error handling around the command result and JSON parsing to log meaningful context before returning, especially in the result.term check and the non-Windows parsing path; use the existing result.stderr and the offending condition, and prefer Zig’s catch |err| pattern with descriptive messages in the upgrade function.Source: Coding guidelines
184-201: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
std.process.runresult buffers are leaked here (and inconsistent allocator).
copyFileand the cleanup call discard theRunResultwith_ =, leaking thestdout/stderrallocations (contrast withfetchLatestVersion, which frees them). Line 184 also usesstd.heap.page_allocatorinstead of the passedallocator, which is inconsistent. Impact is small in a short-lived upgrade process, but worth tidying for consistency.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/upgrade.zig` around lines 184 - 201, The cleanup call and copyFile both discard the std.process.run result, which leaks the captured stdout/stderr buffers, and the cleanup path also uses std.heap.page_allocator instead of the allocator passed into the upgrade flow. Update the upgrade logic around std.process.run and the copyFile helper so the RunResult is always captured and its buffers are freed like in fetchLatestVersion, and make the cleanup invocation use the same allocator consistently.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/upgrade.zig`:
- Around line 218-226: The upgrade check in the version comparison is
equality-only, so any non-matching build is treated as needing an upgrade even
when the current build is newer. Update the logic around the current/latest
comparison in upgrade.zig to use a proper semver ordering instead of
std.mem.eql, and only continue with the download/replace flow when
latest_version is strictly newer than version_info.VERSION. Keep the existing
latest_version trimming behavior, but route the decision through the version
comparison in the upgrade path.
- Around line 242-249: The upgrade flow is extracting the release archive to the
wrong directory, so `replaceBinary` later looks in a different path than where
`extractArchive` placed `openapi2zig`. Update the `upgrade` logic around
`extractArchive` and `new_binary` so the archive is extracted into `tmp_sub` or,
alternatively, compute `new_binary` from the actual extraction root
(`tmp_dir_path`) to match the flat release layout and keep the binary lookup
consistent.
- Around line 137-146: The download flow in the release-asset handling path
trusts the archive after reader.allocRemaining and dest_dir.writeFile, so add
artifact authentication before returning the archive name. Verify the downloaded
body against a published SHA-256 checksum or signature in the same upgrade path
that writes the asset, and only proceed when the integrity check passes. Use the
existing download/extract flow in src/upgrade.zig to locate the verification
step so the binary is replaced only after validation.
- Around line 128-131: Increase the response-head buffer used in receiveHead
within the upgrade flow so it can hold larger redirect headers, including
GitHub’s signed Location value; replace the current 1 KiB redirect_buf in the
upgrade-related logic with a larger size such as 8 KiB to avoid truncation and
failed downloads.
---
Nitpick comments:
In `@src/main.zig`:
- Around line 13-19: The upgrade failure path in main should not emit duplicate
user-facing errors because upgrade.run already prints the specific reason
internally. Update the parsed_args.upgrade branch in main.zig to either stop
printing the generic "Upgrade failed" message and just return the error, or move
all user-facing failure logging out of upgrade.run and centralize it here. Keep
the behavior consistent by choosing one owner for the message across main and
upgrade.run.
In `@src/upgrade.zig`:
- Around line 282-285: The test in upgrade.zig is duplicating the inline
v-prefix trimming logic instead of verifying the actual behavior used by run.
Extract the prefix removal into a small helper such as stripVPrefix and update
the version comparison test to call that helper directly, so the assertions
exercise the production path rather than reimplementing it inside the test.
- Around line 88-104: The upgrade flow in upgrade logic returns bare
UpgradeFailed for every failure, which hides whether the command failed, stderr
was emitted, or the JSON response was invalid. Update the error handling around
the command result and JSON parsing to log meaningful context before returning,
especially in the result.term check and the non-Windows parsing path; use the
existing result.stderr and the offending condition, and prefer Zig’s catch |err|
pattern with descriptive messages in the upgrade function.
- Around line 184-201: The cleanup call and copyFile both discard the
std.process.run result, which leaks the captured stdout/stderr buffers, and the
cleanup path also uses std.heap.page_allocator instead of the allocator passed
into the upgrade flow. Update the upgrade logic around std.process.run and the
copyFile helper so the RunResult is always captured and its buffers are freed
like in fetchLatestVersion, and make the cleanup invocation use the same
allocator consistently.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: e4a8adde-2b34-48e4-adaf-48aeea264a54
📒 Files selected for processing (3)
src/cli.zigsrc/main.zigsrc/upgrade.zig
| var redirect_buf: [1024]u8 = undefined; | ||
| var response = try req.receiveHead(&redirect_buf); | ||
|
|
||
| if (response.head.status != .ok) return error.UpgradeFailed; |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🌐 Web query:
Zig std.http.Client request receiveHead redirect buffer size Location header
💡 Result:
In Zig's std.http.Client, the buffering of HTTP headers is essential for handling responses and automatically following redirects, as headers must be parsed to identify fields like Location [1]. Regarding buffer management and size: 1. Header Buffering: When performing a request, std.http.Client requires a buffer to store the incoming HTTP headers. If the entire HTTP header does not fit within the allocated buffer, the request will fail [2][3]. 2. Redirect Buffers: When using the high-level Client.fetch API, you may need to provide a redirect_buffer to handle header data across automatic redirects [4]. 3. Size Limits: - For manual request management (Client.request), the header strategy defaults to dynamic allocation with a maximum limit of 16 KB [1]. - Alternatively, you can provide a static buffer using the.header_strategy =.{.static = &header_buf } option [5]. - If providing a custom buffer, it must be large enough to hold the complete header block (the end of which is marked by the \r\n\r\n pattern) [1]. A commonly used size for these buffers is 8 KB (e.g., u8) [5][4]. Key Considerations: - Location Header: The client parses the Location header from the buffered response to determine the destination for redirects [1]. - Redirect Logic: Automatic redirect handling is enabled by default (usually up to 3 redirects) [1][5]. If a redirect fails or reaches the maximum count, the client may return an error such as TooManyHttpRedirects [6]. - Implementation Note: HTTP headers are parsed in two stages to accommodate the necessity of accessing header information after the initial receipt, which is critical for correctly processing redirects [1].
Citations:
- 1: std.http.Client: support HTTP redirects ziglang/zig#14202
- 2: https://github.com/ziglang/zig/blob/master/lib/std/http/Client.zig
- 3: https://ziglang.org/documentation/0.11.0/std/src/std/http/Client.zig.html
- 4: https://www.definitepotato.dev/posts/20260208-zig-http/
- 5: std.http: curated error sets and custom Headers ziglang/zig#15299
- 6: https://github.com/ziglang/zig/blob/a6d444c2714f24b7232895cf15282e2287fe445e/lib/std/http/Client.zig
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== repo files of interest =="
git ls-files | rg '(^|/)(build\.zig|zig\.mod|src/upgrade\.zig|.*\.zig)$' | sed -n '1,120p'
echo
echo "== src/upgrade.zig around the cited lines =="
nl -ba src/upgrade.zig | sed -n '100,170p'
echo
echo "== Zig version references =="
rg -n 'zig [0-9]|0\.[0-9]+\.[0-9]+|std\.http\.Client|receiveHead|redirect_buf|header_strategy' -S . --glob '!**/node_modules/**' --glob '!**/dist/**' --glob '!**/build/**'Repository: christianhelle/openapi2zig
Length of output: 3778
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== src/upgrade.zig full relevant region =="
nl -ba src/upgrade.zig | sed -n '1,240p'
echo
echo "== search for upgrade/download flow =="
rg -n 'UpgradeFailed|receiveHead|redirect_buf|Location|releases/download|github' src/upgrade.zigRepository: christianhelle/openapi2zig
Length of output: 247
🌐 Web query:
Zig std.http.Client.Request.receiveHead redirect buffer status .ok 302 follow redirects
💡 Result:
In Zig's std.http.Client, the receiveHead function handles the initial response headers, and the library supports automatic HTTP redirects [1][2]. When using std.http.Client.Request.receiveHead, you must provide a redirect_buffer (a []u8 slice) [3][4]. This buffer is used to store and process header information during the redirection process [1]. Key details regarding redirects and buffer usage: - Automatic Handling: The std.http.Client implementation includes support for automatically following HTTP redirects [1][2]. - Redirect Buffer: The redirect_buffer is necessary for the client to store header data during these redirects [1]. If you do not provide one, or if it is too small, the operation may fail. It is recommended to provide an appropriately sized buffer (e.g., 8 KB or 16 KB) [1][2]. - Status Codes: The client handles standard HTTP status codes, including redirect codes like 301, 302, 303, 307, and 308 [5]. - fetch API: For simpler use cases, you can use std.http.Client.fetch, which abstracts away much of the manual request and redirect handling, and accepts a redirect_buffer parameter directly [6][2]. - Potential Issues: If you are manually managing requests (i.e., not using fetch), ensure that the connection state is properly maintained. If a request hangs after receiving headers or performing operations, it may be due to un-flushed data or improper connection state management [4]. If you are encountering specific issues with 302 redirects, ensure your redirect_buffer is allocated and large enough to hold the headers for the redirected request [1][2].
Citations:
- 1: std.http.Client: support HTTP redirects ziglang/zig#14202
- 2: https://www.definitepotato.dev/posts/20260208-zig-http/
- 3: https://github.com/ziglang/zig/blob/master/lib/std/http/Client.zig
- 4: https://ziggit.dev/t/http-request-hangs-when-receiving-head-without-flushing-conn/15536
- 5: https://github.com/ziglang/zig/blob/master/lib/std/http.zig
- 6: std.http: handle Expect: 100-continue, improve redirect logic, add Client.fetch for simple requests ziglang/zig#16929
🏁 Script executed:
#!/bin/bash
set -euo pipefail
python3 - <<'PY'
from pathlib import Path
path = Path("src/upgrade.zig")
lines = path.read_text().splitlines()
for start, end in [(1, 240)]:
for i in range(start, min(end, len(lines)) + 1):
print(f"{i:4d} {lines[i-1]}")
PY
echo
echo "== build/version references =="
python3 - <<'PY'
from pathlib import Path
for name in ["build.zig", "zig.mod", "build.zig.zon"]:
p = Path(name)
if p.exists():
print(f"\n## {name}")
text = p.read_text().splitlines()
for i, line in enumerate(text, 1):
if "zig" in line.lower() or "version" in line.lower() or "http" in line.lower():
print(f"{i:4d} {line}")
PY
echo
echo "== std.http.Client usage in repo =="
rg -n 'receiveHead|redirect_buffer|header_strategy|std\.http\.Client|fetch\(' src build.zigRepository: christianhelle/openapi2zig
Length of output: 15560
🏁 Script executed:
#!/bin/bash
set -euo pipefail
python3 - <<'PY'
from pathlib import Path
path = Path("src/upgrade.zig")
lines = path.read_text().splitlines()
for i, line in enumerate(lines, 1):
if 90 <= i <= 170 or 1 <= i <= 80:
print(f"{i:4d} {line}")
PY
echo
echo "== build/version references =="
python3 - <<'PY'
from pathlib import Path
for name in ["build.zig", "zig.mod", "build.zig.zon"]:
p = Path(name)
if p.exists():
print(f"\n## {name}")
text = p.read_text().splitlines()
for i, line in enumerate(text, 1):
if "zig" in line.lower() or "version" in line.lower() or "http" in line.lower():
print(f"{i:4d} {line}")
PY
echo
echo "== std.http.Client usage in repo =="
rg -n 'receiveHead|redirect_buffer|header_strategy|std\.http\.Client|fetch\(' src build.zigRepository: christianhelle/openapi2zig
Length of output: 12071
Increase the redirect/header buffer here
receiveHead needs enough room for the full response head, including GitHub’s signed 302 Location; 1 KiB can overflow and abort release downloads. 8 KiB is a safer floor.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/upgrade.zig` around lines 128 - 131, Increase the response-head buffer
used in receiveHead within the upgrade flow so it can hold larger redirect
headers, including GitHub’s signed Location value; replace the current 1 KiB
redirect_buf in the upgrade-related logic with a larger size such as 8 KiB to
avoid truncation and failed downloads.
| const body = try reader.allocRemaining(allocator, .limited(100 * 1024 * 1024)); | ||
| defer allocator.free(body); | ||
|
|
||
| try dest_dir.writeFile(io, .{ .sub_path = archive, .data = body }); | ||
|
|
||
| if (content_length) |_| { | ||
| std.debug.print(" Downloaded... ({s})\n", .{archive}); | ||
| } | ||
|
|
||
| return allocator.dupe(u8, archive); |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== file list =="
git ls-files src/upgrade.zig
echo
echo "== outline =="
ast-grep outline src/upgrade.zig --view expanded || true
echo
echo "== relevant lines =="
sed -n '1,260p' src/upgrade.zig | cat -n
echo
echo "== searches for verification / checksum / signature / TLS / install logic =="
rg -n "checksum|sha256|signature|verify|verified|tls|certificate|http|download|extract|writeFile|self-update|upgrade|archive" src/upgrade.zigRepository: christianhelle/openapi2zig
Length of output: 13591
🌐 Web query:
Zig std.http Client TLS certificate validation default behavior official documentation
💡 Result:
In Zig, the std.http.Client performs TLS certificate validation by default when making HTTPS requests [1][2]. Key aspects of its default behavior include: Root Certificate Scanning: Zig performs lazy scanning of system root certificates upon the first HTTPS request [1][3]. The client uses a ca_bundle (of type std.crypto.Certificate.Bundle) to manage these certificates [4][5]. If the server provides a certificate that cannot be verified against the system's root CA chain, the client will return an error, such as error.TlsCertificateNotVerified [1]. TLS Enforcement: TLS is enabled by default in std.http.Client [4][2]. It can be globally disabled by setting std.options.http_disable_tls = true in your project's root file [4][6]. When disabled, any attempt to make an HTTPS request will result in an error.TlsInitializationFailed [6]. Customization: As of the current development state of Zig, direct, first-class support for customizing certificate validation (such as disabling validation or providing custom trust anchors beyond the standard bundle) is limited or requires interacting with lower-level crypto APIs [7]. The implementation relies on std.crypto.tls.Client, which initiates the handshake and enforces verification [1][8]. Because these mechanisms are part of the standard library's internal implementation, behavior may evolve in future versions. Developers are encouraged to check the generated documentation for the specific version of the Zig compiler being used [5][9].
Citations:
- 1: error: TlsInitializationFailed for std.http.Client.fetch with http-URL - redirecting from HTTP to HTTPS on a client which has not made any HTTPS requests yet ziglang/zig#21636
- 2: https://zenn.dev/masakielastic/articles/2977549dea4a98?locale=en
- 3: https://git.jakstys.lt/motiejus/zig/commit/d56a65a8c4609a740eee43fd7073c2485c87c2c6
- 4: https://github.com/ziglang/zig/blob/master/lib/std/http/Client.zig
- 5:
std.httpnamespace documentation ziglang/zig#17964 - 6: std.http: more proxy support, buffer writes, tls toggle ziglang/zig#17407
- 7: Add support for custom certificate validation to std.crypto.tls.Client ziglang/zig#15681
- 8: https://github.com/ziglang/zig/blob/9135115573051eff58ffcf1ba0a3cce51ed0b413/lib/std/crypto/tls/Client.zig
- 9: https://ziglang.org/documentation/0.11.0/std/src/std/http/Client.zig.html
Add checksum or signature verification for the release asset. src/upgrade.zig:137-146 trusts the downloaded archive before extracting and replacing the binary. TLS is already handled by std.http.Client; the missing step is authenticating the artifact itself with a published SHA-256 or signature.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/upgrade.zig` around lines 137 - 146, The download flow in the
release-asset handling path trusts the archive after reader.allocRemaining and
dest_dir.writeFile, so add artifact authentication before returning the archive
name. Verify the downloaded body against a published SHA-256 checksum or
signature in the same upgrade path that writes the asset, and only proceed when
the integrity check passes. Use the existing download/extract flow in
src/upgrade.zig to locate the verification step so the binary is replaced only
after validation.
| const current = version_info.VERSION; | ||
| const latest_trimmed = if (std.mem.startsWith(u8, latest_version, "v")) latest_version[1..] else latest_version; | ||
|
|
||
| std.debug.print(" Latest version: {s}\n", .{latest_version}); | ||
|
|
||
| if (std.mem.eql(u8, current, latest_trimmed)) { | ||
| std.debug.print(" Already up to date.\n", .{}); | ||
| return; | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Version check is equality-only, not "is newer".
std.mem.eql(current, latest_trimmed) treats any difference as "upgrade available". If the running build is newer than the latest release (e.g. a local/dev build) or the tag formatting differs, this will proceed to download and replace with an older binary. Consider a semver comparison so only strictly-newer releases trigger the replace.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/upgrade.zig` around lines 218 - 226, The upgrade check in the version
comparison is equality-only, so any non-matching build is treated as needing an
upgrade even when the current build is newer. Update the logic around the
current/latest comparison in upgrade.zig to use a proper semver ordering instead
of std.mem.eql, and only continue with the download/replace flow when
latest_version is strictly newer than version_info.VERSION. Keep the existing
latest_version trimming behavior, but route the decision through the version
comparison in the upgrade path.
| const archive_path = try std.fs.path.join(allocator, &.{ tmp_dir_path, sub_dir_name, archive_name }); | ||
| defer allocator.free(archive_path); | ||
|
|
||
| std.debug.print(" Extracting...\n", .{}); | ||
| try extractArchive(allocator, io, archive_path, tmp_dir_path, platform); | ||
|
|
||
| const binary_name = if (isWindows(platform)) "openapi2zig.exe" else "openapi2zig"; | ||
| const new_binary = try std.fs.path.join(allocator, &.{ tmp_dir_path, sub_dir_name, binary_name }); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
gh release view --repo christianhelle/openapi2zig --json assets --jq '.assets[].name'Repository: christianhelle/openapi2zig
Length of output: 292
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== src/upgrade.zig relevant sections =="
nl -ba src/upgrade.zig | sed -n '1,340p' | sed -n '180,320p'Repository: christianhelle/openapi2zig
Length of output: 244
🏁 Script executed:
#!/bin/bash
set -euo pipefail
tmpdir="$(mktemp -d)"
asset="openapi2zig-linux-x86_64.tar.gz"
echo "Downloading $asset to $tmpdir"
gh release download --repo christianhelle/openapi2zig "$asset" -D "$tmpdir"
echo "Archive contents:"
python3 - <<'PY' "$tmpdir/$asset"
import sys, tarfile, os
path = sys.argv[1]
with tarfile.open(path, "r:gz") as tf:
names = tf.getnames()
for n in names:
print(n)
PYRepository: christianhelle/openapi2zig
Length of output: 249
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== locate extractArchive =="
rg -n "fn extractArchive|extractArchive\\(" src/upgrade.zig
echo
echo "== relevant section of src/upgrade.zig =="
sed -n '200,320p' src/upgrade.zig
echo
echo "== archive naming / tmp dir uses =="
rg -n "tmp_dir_path|sub_dir_name|tmp_sub|archive_name|new_binary|replaceBinary" src/upgrade.zigRepository: christianhelle/openapi2zig
Length of output: 5417
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== release workflow files =="
fd -a -t f '.github/workflows|build|release|package' .
echo
echo "== search for archive/root directory names =="
rg -n "openapi2zig-upgrade|tar.gz|zip|archive|release asset|pkg|package" .github src . -g '!**/zig-cache/**' -g '!**/zig-out/**'
echo
echo "== inspect any workflow mentioning releases =="
for f in $(fd -a -t f '.github/workflows' .); do
echo "--- $f ---"
sed -n '1,260p' "$f"
doneRepository: christianhelle/openapi2zig
Length of output: 50383
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== install.sh relevant lines =="
sed -n '80,260p' install.sh
echo
echo "== .github/workflows/release.yml relevant lines =="
sed -n '55,95p' .github/workflows/release.yml
echo
echo "== src/upgrade.zig extract + replace flow =="
sed -n '145,260p' src/upgrade.zigRepository: christianhelle/openapi2zig
Length of output: 10665
Extract and look up the binary in the same directory. The release archives are flat (release/* is packaged at the archive root), so extracting to tmp_dir_path places openapi2zig there, but replaceBinary looks under tmp/openapi2zig-upgrade/. Extract into tmp_sub or resolve new_binary from tmp_dir_path.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/upgrade.zig` around lines 242 - 249, The upgrade flow is extracting the
release archive to the wrong directory, so `replaceBinary` later looks in a
different path than where `extractArchive` placed `openapi2zig`. Update the
`upgrade` logic around `extractArchive` and `new_binary` so the archive is
extracted into `tmp_sub` or, alternatively, compute `new_binary` from the actual
extraction root (`tmp_dir_path`) to match the flat release layout and keep the
binary lookup consistent.
This pull request adds a self-upgrade feature to the
openapi2zigCLI tool, allowing users to update to the latest version with a simple--upgradeflag. The implementation includes argument parsing, user-facing documentation, integration in the main entrypoint, and a newupgrade.zigmodule that handles all platform-specific upgrade logic.Upgrade Feature Implementation
--upgradeflag in CLI argument parsing, making it possible to trigger an upgrade from the command line.--upgradeoption and provide example usage. [1] [2]--upgradeflag is parsed correctly.Integration and Upgrade Logic
src/main.zig, so that when the--upgradeflag is present, the upgrade process is run instead of normal code generation. [1] [2]upgrade.zigmodule that:Summary by CodeRabbit
New Features
--upgradeoption to update the app directly from the CLI, including refreshed usage/help text.Bug Fixes
Tests