fix(script): route helper error/warning output to stderr - #2159
Conversation
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
WalkthroughDeployment helper diagnostics now write to stderr. Shared error and warning helpers provide consistent stderr routing for lookup failures, invalid addresses, and missing CREATE3 factory configuration. ChangesDiagnostic stream routing
Estimated code review effort: 2 (Simple) | ~10 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
📝 Generate docstrings
🧪 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 |
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
|
|
@coderabbitai review |
✅ Action performedReview finished.
|
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
script/helperFunctions.sh (1)
3270-3277: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick winAdd regression coverage for the stdout/stderr contract.
Cover
error(),warning(),checkFailure(), and the lookup helpers with separate stdout and stderr capture. Assert that returned values remain clean on stdout, diagnostics appear on stderr, and failure statuses remain nonzero.This protects the contract described in the PR objective.
🤖 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 `@script/helperFunctions.sh` around lines 3270 - 3277, Add regression tests for error(), warning(), checkFailure(), and the lookup helpers that capture stdout and stderr separately. Verify stdout contains only the expected returned values, stderr contains diagnostics, and failure cases retain nonzero exit statuses.
🤖 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 `@script/helperFunctions.sh`:
- Around line 3460-3461: Replace the raw stderr echo diagnostics in
findContractInMasterLogByAddress and findContractVersionInTargetState with the
shared stderr-aware info helper. Preserve the existing [info] severity and
message content for normal lookup misses, adding or reusing an info helper if
necessary; do not route these messages through warning().
---
Nitpick comments:
In `@script/helperFunctions.sh`:
- Around line 3270-3277: Add regression tests for error(), warning(),
checkFailure(), and the lookup helpers that capture stdout and stderr
separately. Verify stdout contains only the expected returned values, stderr
contains diagnostics, and failure cases retain nonzero exit statuses.
🪄 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: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: a77ad201-28e6-45f9-b2be-45107df4a563
📒 Files selected for processing (1)
script/helperFunctions.sh
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Which Linear task belongs to this PR?
Fixes EXSC-734
Why did I implement it this way?
error()andwarning()inscript/helperFunctions.shprinted to stdout. Many of the helpers that call them also return their value on stdout and are consumed via command substitution, so on the failure path the caller captured the rendered ANSI error text as the value instead of an empty string — silently defeating-z/emptiness guards while the message never reached the console. #2148 fixed one such site (getCurrentContractVersion→CURRENT_VERSION, which ended up 127 characters long instead of empty) by rc-checking and blanking at the call site.I swept the helper and the deploy scripts for the rest of the class and fixed it at the source instead of per call site. The sweep enumerated every function in
script/helperFunctions.sh(plusscript/deploy/**/*.sh,script/multiNetworkExecution.sh,script/universalCast.sh,script/scriptMaster.sh) whose body callserror/warning, then grepped for$(...)captures of each: within that scope, 79 capture sites across 20 distinct helpers. Becauseerror/warningare pure output helpers with no callers depending on their stdout, redirecting them to stderr once fixes every current and future capture site, whereas rc-check-and-blank would need repeating at every site and would still leave the next new capture broken. That also means #2148's call-site guard stays correct — it is now belt-and-braces rather than load-bearing.Five related stragglers in the same class — hand-rolled stdout diagnostics inside value-returning helpers — found by the same sweep:
checkFailureprintedFailed to <msg>to stdout — same swallowing problem when it fires inside a capture.findContractVersionInTargetStateprinted its[info] No matching entry found…miss message to stdout, i.e. into the very variable callers read as the target version. Its call sites all rc-check, so none were broken today, but the message was invisible whenever the capture succeeded in the shell's eyes.findContractInMasterLogByAddressprinted[info] address not found in MongoDBinto the capturedRESULT/JSON_ENTRY(script/helperFunctions.sh:824,:1097). Both rc-check (:1097already uses the fix(deploy): make target-state generation fail loudly instead of silently wiping entries #2148-style|| JSON_ENTRY=""workaround), so again invisible rather than broken.The two
[info]-level ones go through a newinfo()helper rather than a hand-rolledecho … >&2, so all four diagnostic levels now sit together and share one explanation of why they are stderr-bound (per CodeRabbit review). Its contract is deliberately narrow — diagnostics emitted from inside a value-returning helper — because the 43 other[info]echoes in this file are progress output that belongs on stdout and must keep using plainecho..agents/rules/300-bash.mdis updated to list it, since that rule enumerated the logging helpers exhaustively.doesAddressContainBytecodehand-rolledecho "[warning]: …"on the invalid-address path, which landed inNEW_DEPLOYMENTatscript/deploy/deploySingleContract.sh:192. Switched to thewarninghelper so it follows the same routing and matches[CONV:BASH-HELPERS].getCreate3FactoryAddresshand-rolledecho "Error: create3Factory address not found…"intoCREATE3_FACTORY_ADDRESSatscript/deploy/deploySingleContract.sh:154(rc-checked by the followingcheckFailure). Switched to theerrorhelper, same rationale.Six helpers (
getZkSolcVersion,processNetworkLine,getCoreFacetsArray,normalizePrivateKey,install_foundry_zksync,estimatePauseCost) already appended>&2to individualerror/warningcalls — 18 call sites in total. Those are now redundant but harmless — a second>&2on an already-stderr-boundprintfis a no-op — so I left them rather than widen the diff.Deliberately not changed.
success()stays on stdout: no captured helper calls it, so there is no live bug, and changing it would widen the diff for no behavioural gain.findContractInMasterLog(script/helperFunctions.sh:280) is the one straggler I left in place — see the escalation comment below; fixing it correctly means also deleting two now-dead string-match blocks, one of which lives inscript/playgroundHelpers.sh, outside this PR's scope.I checked every consumer that reads these scripts' output as text before making the switch, to be sure nothing depends on the messages arriving on stdout:
.github/workflows/deploy-smoke-test.yml(2>&1 | tee),.github/workflows/runPendingTimelockTXs.yml(2>&1 | tee execution.log, then greps forFailed to execute), and the per-network capture inscript/multiNetworkExecution.sh:1699(2>&1 | tee). All three already merge stderr into the captured stream, so error text still reaches the logs and the greps they run. There is no| teewithout2>&1anywhere in the repo, and no TypeScript consumer parses helper output.Known trade-off, disclosed. Two call sites suppress stderr with
2>/dev/null, and those redirects were written when our diagnostics went to stdout — so they previously suppressed onlyforge/castnoise and now also swallow our own error detail:script/helperFunctions.sh:2744(deploySingleContract … 2>/dev/nullon the diamond-bootstrap path) andscript/deploy/deploySingleContract.sh:525(verifyContract … 2>/dev/null). Neither becomes a silent success — both are rc-checked, and:2744'scheckFailureruns outside the redirect soFailed to deploy contract …still prints — but the reason is now hidden where it used to be visible. Fixing that means removing the redirects, which re-exposes the tool noise they exist to suppress; that is a separate judgment call, so I left them and flagged it in the review comment rather than deciding it here.Verification. The strongest evidence is end-to-end on a real call path, not on the helper in isolation. Running the real
processNetworkLine(script/helperFunctions.sh:1908) against a nonexistent contract with cell valuelatest, before vs after (Google-Sheets download stubbed with the CSV line it would have produced; helper, guard and JSON writer are unmodified repo code):CURRENT_VERSIONcaptured a ~130-char ANSI blob, the-z "$CURRENT_VERSION"guard did not fire, and the ANSI error text was written into the network target-state JSON ("NonexistentFacetXYZ": "�[31m[error] …"), whichmergeNetworkResultswould then fold into_targetState.json."", and both error lines reach stderr.Per-helper, sourcing the modified file and exercising both paths directly:
getCurrentContractVersionon a bad path111 + len(name))[error]on stderrgetCurrentContractVersion "SquidFacet"(happy path)1.0.01.0.0— unchangedfindContractVersionInTargetStatemiss[info]line[info]on stderrfindContractVersionInTargetStatehit (real_targetState.json,DiamondCutFacet)1.0.01.0.0— unchangeddoesAddressContainBytecodewith empty address[warning]on stderrgetCreate3FactoryAddresson an unknown network[error]on stderrgetCreate3FactoryAddress "mainnet"(realnetworks.json)0x93FEC2C0…4AE10x93FEC2C0…4AE1— unchangedAlso ran
bash -n script/helperFunctions.shandbash -c 'set -euo pipefail; source script/helperFunctions.sh'— both clean.No tests are added: these are shell helpers with no existing bash test harness in the repo, and the behaviour is verified by the executed before/after cases above rather than by a committed test.
Checklist before requesting a review
Checklist for reviewer (DO NOT DEPLOY and contracts BEFORE CHECKING THIS!!!)