Skip to content

Fix external package publish ancestry check - #365

Merged
kentcdodds merged 2 commits into
mainfrom
cursor/codemode-publish-external-push-b16b
May 5, 2026
Merged

kentcdodds merged 2 commits into
mainfrom
cursor/codemode-publish-external-push-b16b

Conversation

@kentcdodds

@kentcdodds kentcdodds commented May 5, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • Use the repo session shell git adapter for external publish fast-forward ancestry checks
  • Remove the direct isomorphic-git filesystem call that could receive an incompatible workspace filesystem shape
  • Add a regression test for the external publish fast-forward path
  • Use Number.POSITIVE_INFINITY for the full-history ancestry walk instead of a negative depth sentinel

Root cause

package_publish_external_push takes the external publish path and checks fast-forward ancestry after cloning/checking out the pushed Artifacts commit. That path called isomorphic-git.isDescendent directly with WorkspaceFileSystem; in the execute/codemode callback path, isomorphic-git treated that object as a filesystem and attempted to bind missing fs methods, producing Cannot read properties of undefined (reading 'bind'). The working repo_run_commands publish path stays on the @cloudflare/shell git adapter, so it did not hit the incompatible direct fs usage.

Validation

  • npm test -- packages/worker/src/repo/repo-session-do.node.test.ts packages/worker/src/mcp/capabilities/packages/publish-external-push.node.test.ts
  • npm run typecheck
Open in Web Open in Cursor 

Summary by CodeRabbit

  • Tests

    • Added a unit test verifying ancestry checking when publishing from an external ref without an expected head (ensures fast‑forward detection).
  • Chores

    • Improved ancestry-checking logic to treat identical commits as matching and to traverse full commit history for accurate results.
    • Removed an unused Git helper dependency.

Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
@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: a0b57161-22f2-4857-b469-c2d3e037d46c

📥 Commits

Reviewing files that changed from the base of the PR and between cda5e84 and 2f1da6c.

📒 Files selected for processing (2)
  • packages/worker/src/repo/repo-session-do.node.test.ts
  • packages/worker/src/repo/repo-session-do.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/worker/src/repo/repo-session-do.ts
  • packages/worker/src/repo/repo-session-do.node.test.ts

📝 Walkthrough

Walkthrough

Replaced isomorphic-git ancestry check with a shell-based traversal using the DurableObject git adapter (this.git.log) and added a Vitest that verifies fast‑forward ancestry via the shell adapter when no expectedHead is provided.

Changes

Ancestry Checking Refactor & Test

Layer / File(s) Summary
Data / API shape
packages/worker/src/repo/repo-session-do.ts
Removed top-level isomorphic-git import; isAncestorCommit now treats identical OIDs as equal and uses the DurableObject git adapter API for log traversal.
Core Implementation
packages/worker/src/repo/repo-session-do.ts
Reimplemented ancestry check: call this.git.log from descendant with depth: Number.POSITIVE_INFINITY and return true if any logged commit oid equals ancestor.
Integration / Wiring
packages/worker/...repo-session-do.ts, packages/worker/...session
Ancestry check path now relies on the DurableObject git.log behavior and its dir/ref/depth parameters (callsite expectations adjusted accordingly).
Tests
packages/worker/src/repo/repo-session-do.node.test.ts
Added Vitest publishFromExternalRef checks fast-forward ancestry through shell git adapter that stubs getEntitySourceById (published_commit: commit-old), mocks git.log to return [{ oid: 'commit-new' }, { oid: 'commit-old' }], calls publishFromExternalRef without expectedHead, asserts status: 'published', checks git.log called with { dir: '/session', ref: 'commit-new', depth: Number.POSITIVE_INFINITY }, and verifies updateEntitySource gets publishedCommit: 'commit-new'.

Sequence Diagram

sequenceDiagram
    autonumber
    participant Client as rgba(66,135,245,0.5) Client
    participant RepoSession as rgba(39,174,96,0.5) RepoSessionBase
    participant DOgit as rgba(231,76,60,0.5) DurableObject.git

    Client->>RepoSession: publishFromExternalRef(newCommit)
    RepoSession->>RepoSession: getEntitySourceById -> published_commit: commit-old
    RepoSession->>DOgit: log(dir: '/session', ref: 'commit-new', depth: Infinity)
    DOgit-->>RepoSession: [{oid: 'commit-new'}, {oid: 'commit-old'}]
    RepoSession->>RepoSession: find ancestor == 'commit-old' in log -> true
    RepoSession->>Client: return { status: 'published' }
    RepoSession->>RepoSession: updateEntitySource(publishedCommit: 'commit-new')
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • kentcdodds/kody#352: Modifies RepoSessionBase.isAncestorCommit and related tests; overlaps with the same ancestry-checking behavior and shell git adapter usage.

Poem

🐰 I nibbled logs beneath the moonlit tree,

No iso-git, just shell calls set me free.
I chased new commits until I found the old,
Fast-forwarded, tidy, brave and bold.
Hooray — the publish hops and sings with glee!

🚥 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 external package publish ancestry check' clearly and directly summarizes the main change—fixing the ancestry checking logic for external package publishing.
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.

✏️ 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 cursor/codemode-publish-external-push-b16b

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.

@kentcdodds
kentcdodds marked this pull request as ready for review May 5, 2026 05:28
@github-actions

github-actions Bot commented May 5, 2026 •

Copy link
Copy Markdown
Contributor

🔎 Preview deployed: https://kody-pr-365.kentcdodds.workers.dev

Worker: kody-pr-365
D1: kody-pr-365-db
KV: kody-pr-365-oauth-kv

Mocks:

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/worker/src/repo/repo-session-do.node.test.ts (1)

927-965: 💤 Low value

New test looks correct; note git.log is not reset in setCommonSessionFixtures

The test correctly uses mockResolvedValueOnce (one call to git.log in the publishFromExternalRef path), exercises the real publishExternalRefSource implementation for integration coverage, and asserts the expected call shape.

Minor hygiene: setCommonSessionFixtures clears pull, push, updateRepoSession, and updateEntitySource, but git.log is left uncleaned. If a future test queues multiple mockResolvedValueOnce calls on git.log without clearing, stale queued values could bleed across test boundaries. Adding mockModule.git.log.mockClear() to setCommonSessionFixtures would make test isolation explicit.

🔧 Suggested addition to `setCommonSessionFixtures`
 	mockModule.git.pull.mockClear()
 	mockModule.git.push.mockClear()
+	mockModule.git.log.mockClear()
 	mockModule.updateRepoSession.mockClear()
 	mockModule.updateEntitySource.mockClear()
🤖 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 `@packages/worker/src/repo/repo-session-do.node.test.ts` around lines 927 -
965, The test-suite setup function setCommonSessionFixtures leaves
mockModule.git.log mocks queued which can leak stubbed responses between tests;
update setCommonSessionFixtures to call mockModule.git.log.mockClear() (or
mockReset()) so that any previously queued mockResolvedValueOnce entries are
cleared before each test, ensuring publishFromExternalRef and other tests get
isolated git.log behavior.
🤖 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 `@packages/worker/src/repo/repo-session-do.ts`:
- Around line 459-464: In isAncestorCommit replace the undocumented hardcoded
depth: -1 with a documented unlimited positive value (e.g., Infinity or
Number.POSITIVE_INFINITY) so the git.log call traverses the full history; update
the options passed in the commits = await this.git.log(...) call to use that
unlimited depth constant instead of -1 and add a brief comment referencing
parseOptionalDepth to note why negatives are disallowed and we use Infinity to
request the full history.

---

Nitpick comments:
In `@packages/worker/src/repo/repo-session-do.node.test.ts`:
- Around line 927-965: The test-suite setup function setCommonSessionFixtures
leaves mockModule.git.log mocks queued which can leak stubbed responses between
tests; update setCommonSessionFixtures to call mockModule.git.log.mockClear()
(or mockReset()) so that any previously queued mockResolvedValueOnce entries are
cleared before each test, ensuring publishFromExternalRef and other tests get
isolated git.log behavior.
🪄 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 Plus

Run ID: 06b096e1-951d-4830-a8cd-8e12eb36f5c2

📥 Commits

Reviewing files that changed from the base of the PR and between 780564f and cda5e84.

📒 Files selected for processing (2)
  • packages/worker/src/repo/repo-session-do.node.test.ts
  • packages/worker/src/repo/repo-session-do.ts

Comment thread packages/worker/src/repo/repo-session-do.ts
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
@kentcdodds
kentcdodds merged commit a6c7f8a into main May 5, 2026
9 checks passed
@kentcdodds
kentcdodds deleted the cursor/codemode-publish-external-push-b16b branch May 5, 2026 12:32
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