Skip to content

fix(publish): normalize string repository field to object form#12109

Merged
zkochan merged 2 commits into
mainfrom
fix/12099
Jun 1, 2026
Merged

fix(publish): normalize string repository field to object form#12109
zkochan merged 2 commits into
mainfrom
fix/12099

Conversation

@zkochan

@zkochan zkochan commented Jun 1, 2026

Copy link
Copy Markdown
Member

Problem

pnpm publish fails with a 500 Internal Server Error when publishing to registries such as Gitea/Codeberg, while npm publish of the same package succeeds. Reported in #12099.

Root cause

These registries decode the published package metadata into a typed struct where repository is an object ({ type, url, directory }) — see Gitea's creator.go. When repository arrives as a string (e.g. "https://codeberg.org/tao-cumplido/binary-tools"), JSON decoding into that struct fails and the server returns a 500.

npm avoids this because normalize-package-data rewrites a string repository into { type: 'git', url } before publishing. pnpm's exportable manifest did not apply that normalization, so it sent the bare string and tripped the registry. This is also why the documented workaround pnpm pack && npm publish *.tgz works — npm normalizes the manifest it reads from the tarball.

Fix

Add a transformRepository step to the exportable-manifest pipeline that converts a string repository into { type: 'git', url }, matching npm. Object-form repository values are left untouched.

Test

Added unit tests for the new transform (absent / string / object cases).

Close #12099


Written by an agent (Claude Code, claude-opus-4-8).

Summary by CodeRabbit

  • Bug Fixes
    • Repository field in publish manifests is now normalized from string format to object format containing type and url properties.

zkochan added 2 commits June 1, 2026 16:31
Some registries (e.g. Gitea) reject a string `repository` field with a
500 Internal Server Error, since they decode it into an object-typed
struct. npm normalizes a string repository into { type, url } before
publishing; pnpm did not, so `pnpm publish` failed where npm succeeded.

Close #12099
Copilot AI review requested due to automatic review settings June 1, 2026 14:33
@coderabbitai

coderabbitai Bot commented Jun 1, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 1f8b9d8d-9ce3-4908-a8fd-f6927609f98e

📥 Commits

Reviewing files that changed from the base of the PR and between 6f382f4 and a72bf71.

📒 Files selected for processing (5)
  • .changeset/publish-normalize-repository.md
  • cspell.json
  • releasing/exportable-manifest/src/transform/index.ts
  • releasing/exportable-manifest/src/transform/repository.ts
  • releasing/exportable-manifest/test/transformRepository.test.ts
📜 Recent review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Agent
  • GitHub Check: Compile & Lint
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Follow Standard Style with trailing commas, preferring functions over classes, and declaring functions after they are used (relying on hoisting)
Use a single options object instead of multiple parameters when a function needs more than two or three arguments
Follow Import Order: Standard libraries first, then external dependencies (alphabetically), then relative imports
Write self-documenting code where function names, parameters, and types explain what a function does without requiring prose comments
Do not write comments that restate what the code already says; refactor via renaming, splitting helpers, or restructuring instead
Do not repeat documentation at call sites that already exists in JSDoc on the callee; update JSDoc once for all call sites to benefit
Use JSDoc only for a function's contract (preconditions, postconditions, edge cases, why the function exists), not for re-narrating the body
Do not record past implementation shape, refactor history, or 'the previous code did X' framing in code; use git log and git blame instead
Write comments only when: the reason for code is non-obvious (hidden invariant, workaround for known bug, deliberate exception), or the right name doesn't fit (temporary technical constraint)

Files:

  • releasing/exportable-manifest/src/transform/repository.ts
  • releasing/exportable-manifest/test/transformRepository.test.ts
  • releasing/exportable-manifest/src/transform/index.ts
**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use util.types.isNativeError() instead of instanceof Error for error type checking in Jest tests

Files:

  • releasing/exportable-manifest/test/transformRepository.test.ts
🧠 Learnings (2)
📚 Learning: 2026-05-26T21:01:06.666Z
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11966
File: .changeset/require-tarball-integrity.md:6-6
Timestamp: 2026-05-26T21:01:06.666Z
Learning: In pnpm lockfile-related release notes/docs (especially changeset markdown), preserve URL hostnames exactly as they appear in pnpm-lock.yaml tarball resolution entries—keep hosts like `codeload.github.com`, `bitbucket.org`, and `gitlab.com` in lowercase. Do not “correct” them to title-case/preserve brand capitalization (e.g., LanguageTool rules like `GITHUB` capitalization) because these are literal URL fragments, not platform brand names.

Applied to files:

  • .changeset/publish-normalize-repository.md
📚 Learning: 2026-05-14T09:04:00.133Z
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11622
File: resolving/npm-resolver/test/publishedBy.test.ts:350-354
Timestamp: 2026-05-14T09:04:00.133Z
Learning: In the pnpm/pnpm repository, ESLint is the authoritative style linter. Do not raise review findings for missing trailing commas in multiline function calls (e.g., `fs.writeFileSync(...)`) when this repo’s ESLint configuration does not report them and lint passes. Prefer deferring to the ESLint results for this specific trailing-comma rule rather than enforcing it manually in code review.

Applied to files:

  • releasing/exportable-manifest/src/transform/repository.ts
  • releasing/exportable-manifest/test/transformRepository.test.ts
  • releasing/exportable-manifest/src/transform/index.ts
🔇 Additional comments (6)
.changeset/publish-normalize-repository.md (1)

1-7: LGTM!

cspell.json (1)

38-38: LGTM!

releasing/exportable-manifest/src/transform/repository.ts (1)

1-26: LGTM!

releasing/exportable-manifest/test/transformRepository.test.ts (1)

1-39: LGTM!

releasing/exportable-manifest/src/transform/index.ts (2)

7-7: LGTM!


16-17: LGTM!


📝 Walkthrough

Walkthrough

This PR fixes a publish failure on Codeberg and similar registries by normalizing the repository field in export manifests from string format to an npm-compatible object format { type: 'git', url }. A new transformRepository function is introduced, wired into the export pipeline, and tested with comprehensive cases.

Changes

Repository Normalization in Publish Manifests

Layer / File(s) Summary
Repository transformation function and tests
releasing/exportable-manifest/src/transform/repository.ts, releasing/exportable-manifest/test/transformRepository.test.ts
transformRepository accepts a manifest, returns it unchanged if repository is absent or already an object, and converts string repositories to { type: 'git', url }. Tests validate all three cases with strict equality.
Pipeline integration
releasing/exportable-manifest/src/transform/index.ts
Import and append transformRepository to the pipe() chain after transformPeerDependenciesMeta so the export manifest pipeline normalizes repositories before output.
Release notes and configuration
.changeset/publish-normalize-repository.md, cspell.json
Changeset marks @pnpm/releasing.exportable-manifest and pnpm for patch bumps and documents the new repository normalization behavior. Codeberg is added to the spell-check word list.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Poem

A rabbit hops with glee so bright, 🐰
The repository field now feels quite right,
From string to object, what a treat,
Codeberg publishes, victory sweet! 🎉
The registry can't complain no more,
Normalization opens the door.

🚥 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 'fix(publish): normalize string repository field to object form' clearly and concisely summarizes the main change: converting repository field from string to object format for publish compatibility.
Linked Issues check ✅ Passed The PR addresses all key requirements from issue #12099: transforms string repository values to { type: 'git', url } format (matching npm behavior), includes unit tests for the transformation, and fixes the 500 error on registries expecting object-form repository.
Out of Scope Changes check ✅ Passed All changes are scoped to the repository normalization objective: repository transformation logic, corresponding test suite, changeset documentation, and a spell-check addition for 'Codeberg' are all directly related.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/12099

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install failed. For unrecoverable errors, disable the tool in CodeRabbit configuration.


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.

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Review Summary by Qodo

Normalize string repository field to object form for registry compatibility

🐞 Bug fix

Grey Divider

Walkthroughs

Description
• Normalize string repository field to object form before publishing
• Prevents 500 errors on registries like Gitea/Codeberg that expect object format
• Matches npm's normalize-package-data behavior for compatibility
• Adds comprehensive unit tests for the new transform function
Diagram
flowchart LR
  A["String repository<br/>e.g. URL"] -->|transformRepository| B["Object repository<br/>{type: git, url}"]
  C["Object repository<br/>unchanged"] -->|transformRepository| C
  D["Missing repository<br/>unchanged"] -->|transformRepository| D
  B --> E["Compatible with<br/>Gitea/Codeberg"]

Loading

Grey Divider

File Changes

1. releasing/exportable-manifest/src/transform/index.ts ✨ Enhancement +3/-1

Add repository transform to pipeline

• Imports new transformRepository function from repository.js
• Adds transformRepository to the transform pipeline after transformPeerDependenciesMeta

releasing/exportable-manifest/src/transform/index.ts


2. releasing/exportable-manifest/src/transform/repository.ts ✨ Enhancement +26/-0

Implement repository field normalization transform

• New file implementing transformRepository function
• Converts string repository values to { type: 'git', url } object format
• Leaves object-form and missing repository fields unchanged
• Includes detailed JSDoc explaining the fix and registry compatibility issue

releasing/exportable-manifest/src/transform/repository.ts


3. releasing/exportable-manifest/test/transformRepository.test.ts 🧪 Tests +39/-0

Add comprehensive tests for repository transform

• New test file with three test cases covering all scenarios
• Tests missing repository field (returns manifest unchanged)
• Tests string repository normalization to git object form
• Tests object repository preservation (no transformation)

releasing/exportable-manifest/test/transformRepository.test.ts


View more (2)
4. .changeset/publish-normalize-repository.md 📝 Documentation +6/-0

Document repository normalization fix in changeset

• New changeset documenting the fix for issue #12099
• Marks patch version bump for @pnpm/releasing.exportable-manifest and pnpm
• Explains the registry compatibility issue and the normalization solution

.changeset/publish-normalize-repository.md


5. cspell.json ⚙️ Configuration changes +1/-0

Add Codeberg to spell-check dictionary

• Adds "Codeberg" to the spell-check dictionary
• Maintains alphabetical ordering in the word list

cspell.json


Grey Divider

Qodo Logo

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 fixes pnpm publish compatibility with registries (notably Gitea/Codeberg) that expect package.json’s repository field to be an object in published metadata, by normalizing a string repository into { type: 'git', url } during exportable-manifest generation (matching npm’s publish behavior).

Changes:

  • Add transformRepository to convert a string repository into { type: 'git', url } in the exportable-manifest transform pipeline.
  • Add unit tests covering absent / string / object repository cases.
  • Update cspell.json to allow “Codeberg”, and add a changeset for patch releases.

Reviewed changes

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

Show a summary per file
File Description
releasing/exportable-manifest/test/transformRepository.test.ts Adds unit tests for repository normalization behavior.
releasing/exportable-manifest/src/transform/repository.ts Implements transformRepository to normalize string repository into object form.
releasing/exportable-manifest/src/transform/index.ts Wires transformRepository into the exportable-manifest transform pipeline.
cspell.json Adds “Codeberg” to the spelling dictionary.
.changeset/publish-normalize-repository.md Declares patch releases for the affected packages and documents the fix.

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

@zkochan zkochan merged commit 33921c8 into main Jun 1, 2026
19 checks passed
@zkochan zkochan deleted the fix/12099 branch June 1, 2026 15:05
@zkochan zkochan mentioned this pull request Jun 2, 2026
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.

can’t publish to codeberg registry with v11

2 participants