Skip to content

refactor(scripts): functional pipelines in Nushell scripts - #1524

Merged
ryoppippi merged 2 commits into
mainfrom
refactor/nushell-functional-pipelines
Jul 28, 2026
Merged

ryoppippi merged 2 commits into
mainfrom
refactor/nushell-functional-pipelines

Conversation

@ryoppippi

@ryoppippi ryoppippi commented Jul 28, 2026 •

Copy link
Copy Markdown
Member

Summary

Applies the expression-oriented style from the Nushell book (Thinking in Nu, Nu map from functional languages) to the repo's .nu scripts. An earlier pass (#1485) removed the mut/for accumulators; what was left was side-effecting statement sequences where a pipeline expression says the same thing, plus a duplicated otool parse.

Two commits, separately revertable.

refactor(scripts): replace side-effecting loops with Nushell pipelines

  • pricing-lock.nu — report called save --append once per line inside each, then discarded the resulting list of nothings with ignore. to text already renders a list as newline-terminated lines, so this is one append with no per-iteration side effect.
  • generate-e2e-fixture.nu — dropped a let lines binding that existed only to be immediately joined, and removed a redundant $"(...)" interpolation wrapping an already-string claude_line result.
  • upsert-pr-comment.nu — the request body was staged in a mktemp file, passed as gh api --input <path>, then removed. gh api --input - reads stdin and $in forwards pipeline input to an external inside a custom command, so the temp file, its save, and its rm are gone.

refactor(scripts): share otool parsing between native package scripts

ensure-native-binary.nu and stage-native-package.nu each defined binary_name and each parsed otool -L output. The two parses had already drifted — the staging copy kept blank rows the checking copy filtered. Both now come from a new apps/ccusage/scripts/native-binary.nu module, following the pricing-lock.nu precedent for a shared non-executable module.

linked-dylibs returns {ok, stderr, dylibs} instead of erroring, because the callers want different failure handling: staging aborts with the captured stderr, the portability check treats an otool failure as not portable.

Drive-by bug fix

Selecting dylib rows by their tab indent instead of skip 1 fixes a latent bug. otool -L repeats an unindented <binary> (architecture <arch>): header once per architecture:

/bin/ls (architecture x86_64):
	/usr/lib/libutil.dylib (compatibility version 1.0.0, ...)
/bin/ls (architecture arm64e):     <-- skip 1 did not drop this
	/usr/lib/libutil.dylib (compatibility version 1.0.0, ...)

skip 1 dropped only the first header and fed the rest through as linked libraries, so any fat binary was reported as depending on itself — and since a binary path starts with neither /usr/lib/ nor /System/Library/, the portability check failed it. Cargo emits single-architecture binaries, so the shipped path never hit this.

Verification

  • nu-check passes on all 9 .nu files; just fmt (treefmt/nufmt) reports no changes.
  • generate-e2e-fixture.nu output is byte-identical to before (291880 bytes, same sha1).
  • pricing-lock.nu report appends the same changed=/paths= lines across repeated calls.
  • upsert-pr-comment.nu driven end to end against a stub gh covering create, update, HTTP 404 recreate, and HTTP 403 skip — body arrives as correct JSON on stdin in every write path, and the marker match still picks the github-actions[bot] comment over another author's.
  • linked-dylibs compared against both previous implementations on real Mach-O binaries: identical for single-architecture input; /bin/ls now reports its 6 real dylibs and passes the portability check instead of failing it.
  • Full darwin staging cycle run over a nix-store binary that links nix-store libiconv, confirming the install_name_tool rewrite to /usr/lib/libiconv.2.dylib, the chmod 755, and the prepack verification all still pass. Test artefacts removed.

No user-facing behaviour changes, so no docs impact.


View with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is enabled.


Summary by cubic

Refactors Nushell scripts to use functional pipelines and centralizes Mach-O dylib parsing to remove side effects and duplicate code. Fixes dylib parsing for fat binaries on macOS. No user-facing changes.

  • Refactors

    • Replaced loop-based writes with pipelines in .github/scripts and now stream JSON bodies to gh api via stdin (no temp files).
    • Extracted binary-name and linked-dylibs into apps/ccusage/scripts/native-binary.nu, used by ensure-native-binary.nu and stage-native-package.nu.
  • Bug Fixes

    • Parse otool -L output by selecting tab-indented rows, correctly handling fat binaries with repeated headers.
    • Darwin portability check now evaluates actual dylibs; behavior unchanged for single-arch binaries.

Written for commit 411fded. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • Bug Fixes

    • Improved native binary packaging checks across supported platforms.
    • Strengthened macOS library validation and error handling.
    • Improved reliability when generating test fixtures and reporting workflow outputs.
    • Streamlined automated pull request comment updates by handling request data more reliably.
  • Refactor

    • Consolidated native binary naming and dependency inspection into shared tooling for more consistent packaging behavior.

The three CI scripts each drove output through a statement sequence where a
pipeline expression says the same thing directly.

pricing-lock.nu ran `save --append` once per line inside `each`, then discarded
the resulting list of nothings with `ignore`. `to text` already renders a list
as newline-terminated lines, so the whole thing collapses to one append with no
per-iteration side effect.

generate-e2e-fixture.nu bound the generated rows to `lines` only to immediately
join them, and wrapped each `claude_line` call in a redundant `$"(...)"`
interpolation of an already-string value. Feeding the range straight through
`each | flatten | to text | save` drops the binding and the string round-trip.
Verified byte-identical output against the previous implementation.

upsert-pr-comment.nu staged the request body in a `mktemp` file, passed the path
to `gh api --input`, and removed it afterwards. `gh api --input -` reads the body
from standard input, and pipeline input reaches an external command inside a
custom command via `$in`, so the temp file, its `save`, and its `rm` all go away.
Callers that send no body pipe nothing, which `run-external` treats as empty
stdin.

Exercised upsert-pr-comment.nu end to end against a stub `gh` covering the
create, update, HTTP 404 recreate, and HTTP 403 skip paths.
ensure-native-binary.nu and stage-native-package.nu both defined `binary_name`
and both turned `otool -L` output into a list of linked dylibs, so the two
copies of the parse had already drifted: the staging copy kept blank rows the
checking copy filtered out. Extract both into a `native-binary.nu` module
alongside them, following the `pricing-lock.nu` precedent for a shared
non-executable module.

`linked-dylibs` returns `{ok, stderr, dylibs}` rather than erroring, because the
two callers want different failure handling — staging aborts with the captured
stderr, the portability check treats an otool failure as not portable.

Selecting dylib rows by their tab indent instead of `skip 1` also fixes a latent
bug. `otool -L` repeats an unindented `<binary> (architecture <arch>):` header
once per architecture, so `skip 1` dropped only the first and fed the remaining
headers through as if they were linked libraries. Any fat binary was therefore
reported as depending on itself, and since a binary path does not start with
/usr/lib/ or /System/Library/ the portability check failed it. Cargo emits
single-architecture binaries, so the shipped path never hit this, and old and
new parsing agree exactly on single-architecture input.

Verified against real Mach-O binaries: identical dylib lists to the previous
implementations for single-architecture input, and /bin/ls now reports its 6
real dylibs and passes the portability check instead of failing it. Also ran a
full darwin staging cycle over a nix-store binary that links nix-store libiconv,
confirming the install_name_tool rewrite and the prepack verification still pass.
Copilot AI review requested due to automatic review settings July 28, 2026 12:51
@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
ccusage-guide 411fded Commit Preview URL

Branch Preview URL
Jul 28 2026, 12:33 PM

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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@coderabbitai

coderabbitai Bot commented Jul 28, 2026 •

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 974a0bf2-35a2-471d-a635-b6e65ab93945

📥 Commits

Reviewing files that changed from the base of the PR and between 64932e7 and 411fded.

📒 Files selected for processing (6)
  • .github/scripts/generate-e2e-fixture.nu
  • .github/scripts/pricing-lock.nu
  • .github/scripts/upsert-pr-comment.nu
  • apps/ccusage/scripts/ensure-native-binary.nu
  • apps/ccusage/scripts/native-binary.nu
  • apps/ccusage/scripts/stage-native-package.nu

📝 Walkthrough

Walkthrough

The changes add shared Nushell helpers for native binary naming and macOS dylib inspection, update native packaging scripts to use them, simplify GitHub output serialization, and pipe pull request comment request bodies directly into gh api.

Changes

Native binary tooling

Layer / File(s) Summary
Shared native binary helpers
apps/ccusage/scripts/native-binary.nu
Adds binary-name for platform-specific filenames and linked-dylibs for otool -L execution and dependency parsing.
Native script integration
apps/ccusage/scripts/ensure-native-binary.nu, apps/ccusage/scripts/stage-native-package.nu
Replaces local binary naming and dylib inspection logic with the shared helpers while preserving packaging and system-library validation flows.

GitHub output scripts

Layer / File(s) Summary
Output serialization
.github/scripts/generate-e2e-fixture.nu, .github/scripts/pricing-lock.nu
Uses direct list flattening or text conversion when writing fixture and GITHUB_OUTPUT content.

Pull request comment API

Layer / File(s) Summary
Pipeline request bodies
.github/scripts/upsert-pr-comment.nu
Serializes request bodies to JSON and passes them through pipeline input to gh api instead of using a temporary file.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

Suggested reviewers: copilot

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main Nushell script refactor toward functional pipelines.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/nushell-functional-pipelines

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.

@pullfrog pullfrog 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.

✅ No new issues found.

Reviewed changes — replaces side-effecting imperative patterns in Nushell CI scripts with functional pipelines, extracts shared Mach-O dylib parsing into a new module, and fixes a latent fat-binary bug in otool -L parsing.

  • Functional pipelines in pricing-lock.nu and generate-e2e-fixture.nu — to text | save replaces per-line each + save --append; removed a redundant let binding and unnecessary $"($expr)" interpolations. Byte-identical output confirmed.
  • Stdin-driven gh api in upsert-pr-comment.nu — gh_api_complete accepts pipeline input via $in and forwards it to gh api --input -, eliminating the temp-file dance. gh_api_json callers (GET, no --input) pipe nothing → empty stdin, so behavior is unchanged.
  • apps/ccusage/scripts/native-binary.nu module — binary-name (kebab-case) and linked-dylibs extracted from the two native package scripts, following the pricing-lock.nu module precedent.
  • Fat-binary fix in linked-dylibs — where {|line| $line | str starts-with (char tab)} replaces skip 1, correctly filtering repeated architecture headers instead of letting them leak into dylib results.

Pullfrog  | ⚠️ this action is pinned to a commit SHA, which freezes the cleanup step — switch to @v0 or keep the SHA fresh with Dependabot | View workflow run | Using DeepSeek Pro (free via Pullfrog for OSS) | 𝕏

@pkg-pr-new

pkg-pr-new Bot commented Jul 28, 2026

Copy link
Copy Markdown

Open in StackBlitz

ccusage

npx https://pkg.pr.new/ccusage@1524

@ccusage/ccusage-darwin-arm64

npx https://pkg.pr.new/@ccusage/ccusage-darwin-arm64@1524

@ccusage/ccusage-darwin-x64

npx https://pkg.pr.new/@ccusage/ccusage-darwin-x64@1524

@ccusage/ccusage-linux-arm64

npx https://pkg.pr.new/@ccusage/ccusage-linux-arm64@1524

@ccusage/ccusage-linux-x64

npx https://pkg.pr.new/@ccusage/ccusage-linux-x64@1524

@ccusage/ccusage-win32-x64

npx https://pkg.pr.new/@ccusage/ccusage-win32-x64@1524

commit: 411fded

@cubic-dev-ai cubic-dev-ai 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.

No issues found across 6 files

Re-trigger cubic

@github-actions

Copy link
Copy Markdown
Contributor

ccusage performance comparison

PR SHA: 411fded72613
Base SHA: 64932e726ab8

Performance comparison skipped.

Base package URL was not ready before 300.000s. Fixture performance comparison requires a base package when --base-dir is not provided.

Base package: 64932e726ab8

@github-actions

Copy link
Copy Markdown
Contributor

ccusage performance comparison

PR SHA: 411fded72613
Base SHA: 64932e726ab8

Performance comparison skipped.

Base package URL was not ready before 300.000s. Fixture performance comparison requires a base package when --base-dir is not provided.

Base package: 64932e726ab8

@ryoppippi
ryoppippi merged commit 731c741 into main Jul 28, 2026
39 checks passed
@ryoppippi
ryoppippi deleted the refactor/nushell-functional-pipelines branch July 28, 2026 13:07
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.

2 participants