Skip to content

feat(publish): restore npm-CLI-compatible --json stdout for publish#11478

Merged
zkochan merged 1 commit into
pnpm:mainfrom
comp615:fix/publish-json-stdout
May 5, 2026
Merged

feat(publish): restore npm-CLI-compatible --json stdout for publish#11478
zkochan merged 1 commit into
pnpm:mainfrom
comp615:fix/publish-json-stdout

Conversation

@comp615

@comp615 comp615 commented May 5, 2026

Copy link
Copy Markdown
Contributor

Summary

Restores npm-CLI-compatible --json stdout output for pnpm publish, and aligns --report-summary to use the same per-package shape.

Fixes #11476.

Background

pnpm 10 transitively emitted an npm-CLI-shaped per-package JSON object on stdout for pnpm publish --json because the publish command shelled out to npm. pnpm 11 (#10591) reimplemented publish natively and the new handler returned undefined, so --json now produces 0 bytes on stdout on success — silently breaking downstream tooling that relied on that contract.

The most impactful regression is nx release publish, which parses stdout JSON to confirm success. Under the default --nx-bail=true, it aborts the rest of a release run when JSON is missing — leaving releases partially-published with no surfaced error. Full impact write-up: nrwl/nx#35575.

Output shape

Command stdout / file
pnpm publish --json single object { id, name, version, size, unpackedSize, shasum, integrity, filename, files, entryCount, bundled }, mirroring npm publish --json
pnpm publish -r --json array of those objects, mirroring pnpm pack --json's shape choice
pnpm publish -r --report-summary existing pnpm-publish-summary.json envelope { publishedPackages: [...] } is preserved, but each entry is upgraded to the same per-package shape — additive, since name and version are still present

There was no usable contract for -r --json before this change (pnpm 10 emitted multiple JSON objects interleaved with reporter noise per shelled-out npm call, which isn't parseable), so emitting the array is strictly an improvement.

Implementation

  • pack.api() computes unpackedSize while it still has the filesMap.
  • publishPackedPkg returns a PublishSummary (SHA-1 shasum + SHA-512 integrity via node:crypto, no new deps) instead of void.
  • bundled is normalized from bundledDependencies / bundleDependencies per npm's semantics (including true → expand to all dep names).
  • recursivePublish collects per-package PublishSummary objects and returns them; the existing manifest-pick fallback is kept for paths that don't produce a summary.
  • publish.handler returns { output, exitCode } with the serialized summary (object or array) when opts.json is set; pnpm/src/main.ts already writes output to stdout.
  • A changeset (patch to @pnpm/releasing.commands and pnpm) is included.

Notes

  • pnpm publish <tarball> direct path: files, entryCount, and unpackedSize are reported as empty/zero because the contents list and uncompressed sizes aren't available without re-reading the tarball. Easy to wire up if reviewers prefer.
  • I was not able to compile/test locally in this environment (pnpm 11 toolchain bootstrap blocked). Marking draft so CI can validate, and so reviewers can confirm shape choices before polish.

Verification

I checked open pnpm PRs for publish --json, publishPackedPkg, and references to #11476 / #10591 — no open PR is already pursuing this fix.

Related

🤖 Authored with assistance from Amp.

Summary by CodeRabbit

  • New Features

    • pnpm publish --json now emits npm-compatible per-package JSON summaries (includes size, unpackedSize, shasum, integrity, filename, files, entryCount, bundled).
    • Recursive publish (pnpm publish -r --json and pnpm publish -r --report-summary) now produce arrays or summary files using the per-package summary shape.
  • Documentation

    • Added a changeset documenting the restored npm-CLI-compatible JSON stdout for publish.
  • Tests

    • Added/updated tests to verify per-package JSON stdout and report-summary formats.

@coderabbitai

coderabbitai Bot commented May 5, 2026

Copy link
Copy Markdown

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: 30d7e9d2-f768-4b11-96d2-cabaca2b4e3c

📥 Commits

Reviewing files that changed from the base of the PR and between d3192a2 and 38342b7.

⛔ Files ignored due to path filters (1)
  • releasing/commands/test/publish/__snapshots__/recursivePublish.ts.snap is excluded by !**/*.snap
📒 Files selected for processing (8)
  • .changeset/restore-publish-json-stdout.md
  • releasing/commands/src/publish/pack.ts
  • releasing/commands/src/publish/publish.ts
  • releasing/commands/src/publish/publishPackedPkg.ts
  • releasing/commands/src/publish/recursivePublish.ts
  • releasing/commands/test/publish/FailedToPublishError.test.ts
  • releasing/commands/test/publish/publish.ts
  • releasing/commands/test/publish/recursivePublish.ts
✅ Files skipped from review due to trivial changes (1)
  • .changeset/restore-publish-json-stdout.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • releasing/commands/test/publish/publish.ts

📝 Walkthrough

Walkthrough

Restores npm-CLI-compatible JSON stdout for pnpm publish --json by adding per-package PublishSummary objects and threading tarball metadata (size, unpackedSize, shasum, integrity, filename, files, entryCount, bundled) through pack, publishPackedPkg, recursivePublish, and the publish handler; tests and a changeset were added.

Changes

Publish JSON Output Restoration

Layer / File(s) Summary
Data Shape
releasing/commands/src/publish/pack.ts, releasing/commands/src/publish/publishPackedPkg.ts, releasing/commands/src/publish/recursivePublish.ts
PackResult adds unpackedSize: number. New PublishSummary interface introduced (id, name, version, size, unpackedSize, shasum, integrity, filename, files, entryCount, bundled). New exported type `RecursivePublishedPackage = PublishSummary
Core Metadata Computation
releasing/commands/src/publish/pack.ts, releasing/commands/src/publish/publishPackedPkg.ts
pack() computes unpackedSize by summing file sizes (special-case for package metadata using the serialized publishManifest). publishPackedPkg() computes tarball size, shasum, SRI integrity, file list and entryCount, normalizes bundled deps, and returns a PublishSummary.
Recursive Accumulation
releasing/commands/src/publish/recursivePublish.ts
recursivePublish() accumulates publishedPackages: RecursivePublishedPackage[] from each publish result (prefers publishSummary, falls back to name/version), and returns { exitCode, publishedPackages }.
Publish Handler Integration
releasing/commands/src/publish/publish.ts
Handler imports PublishSummary/RecursivePublishedPackage, exposes json/recursive/workspaceDir options, threads publishSummary / publishedPackages through the flow (including tarball shortcut with empty contents/unpackedSize=0), and emits JSON to stdout when --json is set (single object for single-package, array for recursive).
Tests & Release Notes
.changeset/restore-publish-json-stdout.md, releasing/commands/test/publish/*
Added changeset documenting behavior. Tests added/updated: single-package --json stdout test, recursive --json stdout test, --report-summary file-shape test, and updated test fixtures to include unpackedSize where applicable.

Sequence Diagram

sequenceDiagram
    participant CLI as CLI (pnpm)
    participant Handler as publish.handler
    participant Pack as pack()
    participant PubPkg as publishPackedPkg()
    participant Recursive as recursivePublish()
    participant Stdout as stdout / pnpm-publish-summary.json

    CLI->>Handler: pnpm publish --json (or -r / --report-summary)
    Handler->>Pack: pack(manifest, ...)
    Pack->>Pack: compute contents + unpackedSize
    Pack-->>Handler: PackResult { publishedManifest, tarballPath, contents, unpackedSize }
    Handler->>PubPkg: publishPackedPkg(tarballPath, contents, unpackedSize, ...)
    PubPkg->>PubPkg: compute size, shasum, integrity, bundled, files
    PubPkg-->>Handler: PublishSummary {...}
    Handler->>Recursive: (if recursive) recursivePublish(...) collects PublishSummary items
    Handler->>Stdout: emit JSON (PublishSummary | [PublishSummary] | envelope file)
    Stdout-->>CLI: machine-readable output (or writes pnpm-publish-summary.json)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • zkochan

Poem

🐰 I counted bytes in bundles, hashed each little thing,
I hopped through packs and summaries — now stdout loves to sing.
A crunchy JSON morsel, neat metadata parade,
Hop on, dear publisher, your data's no longer delayed. 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 9.09% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ 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 'feat(publish): restore npm-CLI-compatible --json stdout for publish' directly and specifically summarizes the main change: restoring JSON stdout output for the publish command to match npm CLI behavior.
Linked Issues check ✅ Passed The PR fully addresses all primary objectives from issue #11476: restores JSON output to stdout for pnpm publish --json (single object), pnpm publish -r --json (array), and --report-summary (per-package shape), implementing the required field set (id, name, version, size, unpackedSize, shasum, integrity, filename, files, entryCount, bundled).
Out of Scope Changes check ✅ Passed All changes directly support the primary objective of restoring npm-compatible JSON stdout for publish: pack.ts computes unpackedSize, publishPackedPkg computes digests and returns PublishSummary, recursivePublish collects per-package results, and publish.ts returns output; test updates validate the feature.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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

@comp615 comp615 force-pushed the fix/publish-json-stdout branch 2 times, most recently from c9f2bba to 1a239da Compare May 5, 2026 20:28
@comp615 comp615 changed the title feat(publish): restore npm-CLI-compatible --json stdout for single-package publish feat(publish): restore npm-CLI-compatible --json stdout for publish May 5, 2026
@comp615 comp615 force-pushed the fix/publish-json-stdout branch 2 times, most recently from deae83c to a7746df Compare May 5, 2026 20:42
@comp615

comp615 commented May 5, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 5, 2026

Copy link
Copy Markdown
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@comp615 comp615 force-pushed the fix/publish-json-stdout branch from a7746df to d3192a2 Compare May 5, 2026 20:57
@comp615 comp615 marked this pull request as ready for review May 5, 2026 20:58
@comp615 comp615 requested a review from zkochan as a code owner May 5, 2026 20:58
Copilot AI review requested due to automatic review settings May 5, 2026 20:58

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

Restores machine-readable --json stdout for pnpm publish (regression in pnpm 11 vs pnpm 10) by returning and serializing an npm-CLI-shaped per-package publish summary, and aligns recursive publish --report-summary entries to the same shape.

Changes:

  • Introduces a PublishSummary returned from publishPackedPkg() (hashes, sizes, file list, bundled deps) and plumbs it through single and recursive publish flows.
  • Makes publish.handler emit serialized JSON (object for single publish, array for recursive) via { output, exitCode }.
  • Updates/extends tests to assert stdout JSON output and the upgraded report-summary per-package shape.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
releasing/commands/src/publish/pack.ts Computes unpackedSize during pack so publish can report npm-compatible size metadata.
releasing/commands/src/publish/publishPackedPkg.ts Adds PublishSummary generation (hashes, integrity, file list, bundled deps) and returns it to callers.
releasing/commands/src/publish/publish.ts Emits JSON to stdout when --json is set; propagates single/recursive publish summaries.
releasing/commands/src/publish/recursivePublish.ts Collects per-package publish summaries and returns them (and writes them into report-summary).
releasing/commands/test/publish/publish.ts Adds coverage asserting pnpm publish --json returns a parseable per-package summary on stdout.
releasing/commands/test/publish/recursivePublish.ts Updates report-summary assertions and adds tests for -r --json stdout and upgraded report-summary entries.
releasing/commands/test/publish/FailedToPublishError.test.ts Updates mocked PackResult to include the new unpackedSize field.
releasing/commands/test/publish/snapshots/recursivePublish.ts.snap Removes obsolete snapshot in favor of more stable assertions.
.changeset/restore-publish-json-stdout.md Documents the restored JSON contract and publishes patch releases.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread releasing/commands/src/publish/pack.ts Outdated
Comment thread releasing/commands/src/publish/pack.ts Outdated
Comment thread releasing/commands/src/publish/publishPackedPkg.ts
pnpm 10 transitively emitted an npm-CLI-shaped per-package JSON object on stdout for
`pnpm publish --json` because the publish command shelled out to npm. pnpm 11 (pnpm#10591)
reimplemented publish natively and the new handler returned undefined, so `--json` now
produces 0 bytes on stdout on success — silently breaking downstream tooling that grepped
that contract. The most impactful regression is `nx release publish`, which parses
stdout JSON to confirm success; under `--nx-bail=true` it aborts the rest of a release
run when JSON is missing (see nrwl/nx#35575).

This restores the contract for both single-package and recursive publish, and aligns
`--report-summary` to use the same per-package shape:

- `pnpm publish --json`         → single object `{ id, name, version, size,
                                   unpackedSize, shasum, integrity, filename, files,
                                   entryCount, bundled }`, mirroring `npm publish --json`.
- `pnpm publish -r --json`      → array of those objects, mirroring `pnpm pack --json`'s
                                   shape choice for single vs multi.
- `pnpm publish -r --report-summary` → existing `pnpm-publish-summary.json` envelope
                                       `{ publishedPackages: [...] }` is preserved, but
                                       each entry is upgraded to the same per-package shape
                                       (additive — `name` and `version` are still present).

Implementation:
- `pack.api()` computes `unpackedSize` while it still has the filesMap.
- `publishPackedPkg` returns a `PublishSummary` (SHA-1 `shasum` + SHA-512 `integrity`
  via `node:crypto`, no new deps) instead of `void`.
- `bundled` normalizes `bundledDependencies` / `bundleDependencies` per npm's semantics
  (including `true` → all dep names).
- `recursivePublish` collects per-package `PublishSummary` objects and returns them; the
  existing manifest-pick fallback is kept for paths that don't produce a summary.
- `publish.handler` returns `{ output, exitCode }` with the serialized summary (object
  or array) when `opts.json` is set; main.ts already writes `output` to stdout.

Refs pnpm#11476
Refs nrwl/nx#35575

Co-authored-by: Amp <amp@ampcode.com>
Amp-Thread-ID: https://ampcode.com/threads/T-019df90f-8f75-763f-b528-4602e870a972
@comp615 comp615 force-pushed the fix/publish-json-stdout branch from d3192a2 to 38342b7 Compare May 5, 2026 21:38
@zkochan zkochan merged commit 87b1c24 into pnpm:main May 5, 2026
9 checks passed
zkochan pushed a commit that referenced this pull request May 6, 2026
…11478)

pnpm 10 transitively emitted an npm-CLI-shaped per-package JSON object on stdout for
`pnpm publish --json` because the publish command shelled out to npm. pnpm 11 (#10591)
reimplemented publish natively and the new handler returned undefined, so `--json` now
produces 0 bytes on stdout on success — silently breaking downstream tooling that grepped
that contract. The most impactful regression is `nx release publish`, which parses
stdout JSON to confirm success; under `--nx-bail=true` it aborts the rest of a release
run when JSON is missing (see nrwl/nx#35575).

This restores the contract for both single-package and recursive publish, and aligns
`--report-summary` to use the same per-package shape:

- `pnpm publish --json`         → single object `{ id, name, version, size,
                                   unpackedSize, shasum, integrity, filename, files,
                                   entryCount, bundled }`, mirroring `npm publish --json`.
- `pnpm publish -r --json`      → array of those objects, mirroring `pnpm pack --json`'s
                                   shape choice for single vs multi.
- `pnpm publish -r --report-summary` → existing `pnpm-publish-summary.json` envelope
                                       `{ publishedPackages: [...] }` is preserved, but
                                       each entry is upgraded to the same per-package shape
                                       (additive — `name` and `version` are still present).

Implementation:
- `pack.api()` computes `unpackedSize` while it still has the filesMap.
- `publishPackedPkg` returns a `PublishSummary` (SHA-1 `shasum` + SHA-512 `integrity`
  via `node:crypto`, no new deps) instead of `void`.
- `bundled` normalizes `bundledDependencies` / `bundleDependencies` per npm's semantics
  (including `true` → all dep names).
- `recursivePublish` collects per-package `PublishSummary` objects and returns them; the
  existing manifest-pick fallback is kept for paths that don't produce a summary.
- `publish.handler` returns `{ output, exitCode }` with the serialized summary (object
  or array) when `opts.json` is set; main.ts already writes `output` to stdout.

Refs #11476
Refs nrwl/nx#35575


Amp-Thread-ID: https://ampcode.com/threads/T-019df90f-8f75-763f-b528-4602e870a972

Co-authored-by: Charlie Croom <charlie+amp@noreply.com>
Co-authored-by: Amp <amp@ampcode.com>
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.

pnpm publish --json produces empty stdout in pnpm 11 (regression from pnpm 10)

3 participants