Visitar URL original
feat(cloud-sync): move app publishing into @deepnote/cloud-sync by tkislan · Pull Request #566 · deepnote/deepnote · GitHub
Skip to content

feat(cloud-sync): move app publishing into @deepnote/cloud-sync - #566

Open
tkislan wants to merge 4 commits into
mainfrom
feat/cloud-sync-publish-app
Open

tkislan wants to merge 4 commits into
mainfrom
feat/cloud-sync-publish-app

Conversation

@tkislan

@tkislan tkislan commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Closes #564.

deepnote publish ran its whole upload flow inside a commander action: it printed as it went, signalled failure through process.exitCode, and the "Deepnote changed these files since the last sync" check existed only as an error message. This moves the flow into @deepnote/cloud-sync as publishApp(options), which reports per-file progress through onEvent, returns a structured result, and throws PublishError / PublishDivergedError. deepnote publish is now an adapter over it.

CLI behavior is unchanged: no change to flags, output, exit codes or the manifest format.

Changes

  • packages/cloud-sync/src/publish-app.ts (new): publishApp, PublishError (reason: invalid-input | unreadable-directory | project-unavailable), PublishDivergedError (syncRoot, sorted paths), and the PublishAppOptions / PublishAppEvent / PublishAppResult types. PublishDivergedError is thrown before any delete or upload request unless force is set. The file helpers (collectFiles, isEnvFile, normalizeTargetPrefix, preparePublishFiles, appUrlWithPath) moved over unchanged.
  • packages/cloud-sync/src/publish-mirror.ts and its test: moved with git mv from packages/cli/src/utils/. resolvePublishMirror takes an optional onMirrorSkipped callback in place of the CLI's debug call, and SyncRootOption is now string | false | undefined. Of its symbols, PublishMirrorError and SyncRootOption are exported from index.ts; PublishAppOptions.syncRoot and the CLI's publish options use SyncRootOption.
  • packages/cli/src/commands/publish.ts: loads .env, resolves the token, calls publishApp, renders each event with the previous text, and maps errors to the previous exit codes. It no longer imports @deepnote/cloud.
  • packages/cloud-sync/README.md: adds a publishApp usage example and rows for publishApp, PublishError, PublishDivergedError and PublishMirrorError to the API reference table. Options, events and result fields are documented on the exported types.
  • packages/cloud-sync/src/index.ts: exports publishApp, PublishError, PublishDivergedError, PublishMirrorError and the PublishApp*, PublishErrorReason and SyncRootOption types.

Judgment calls

  • index.ts keeps main's export set. After merging feat(cloud-sync): move the workspace sync engine into @deepnote/cloud-sync #568 and feat(cloud-sync): move Streamlit app registration into @deepnote/cloud-sync #573, nothing outside packages/cloud-sync imports sha256, baselineDiverged, assertNoSymbolicLinkAncestors, saveSyncManifest, isSafeRelativeFilePath or projectFilesDir, so issue step 5 would remove them. They stay because the README on main lists them as public helpers.
  • PublishMirrorError and SyncRootOption are exported, unlike the rest of publish-mirror.ts (issue step 1). PublishMirrorError never reaches publishApp callers: publishApp rethrows it as PublishError with reason invalid-input.
  • Events are emitted outside the per-file try. A throwing onEvent listener would otherwise be recorded as a failed upload. PublishAppOptions.onEvent documents that the listener must not throw.
  • PublishOptions.quiet guards are kept in the adapter although Commander never populates it, to keep the diff a pure move.
  • Beyond the seven contract tests the issue lists: failed removal and sharing paths, stale-file pruning (including the divergence check over stale paths), syncRoot: false, mirror-skipped, a failed manifest save reported before sharing, apiAccess true/false, and input errors. One extra publish-mirror test covers onMirrorSkipped.

Verification

Run on this branch after merging main (#568, #573):

  • pnpm typecheck, pnpm prettier:check exit 0. pnpm biome:check and pnpm spell-check report nothing in any file this PR touches.
  • pnpm install --frozen-lockfile accepts the lockfile. package.json, tsdown.config.ts and pnpm-lock.yaml no longer differ from main, which already declares @deepnote/database-integrations as a dependency and a tsdown external.
  • pnpm build succeeds; the built @deepnote/cloud-sync exports PublishMirrorError from ESM, CJS and index.d.ts.
  • pnpm test: 3569 passed in 189 files. This workspace had a python shim on PATH for the three cli/run.test.ts cases that need it.
  • All 44 tests in commands/publish.test.ts pass with the file unchanged; all 18 original mirror tests pass.
  • packages/cloud-sync/src (non-test) has no import of commander, chalk, ora, @inquirer/prompts, dotenv or @deepnote/cli, and no process. reference.
  • Mutation checks (on 6f33d9e, before the merge, which changes no publish code). I broke publish-app.ts and publish-mirror.ts 22 ways (dropped divergence check, reordered mirror-incomplete before the save, unsorted divergent paths, wrong mirrorUpdated, skipped .env refusal, wrong hash, …); the new tests failed on every one. A first run of the tests passed everything, so this is what shows they can fail.
  • Old-vs-new parity (on 6f33d9e). A throwaway harness (not committed) ran origin/main's publish.ts and the new adapter side by side over 47 scenarios (happy path, prune, every failure class, divergence with and without --force, mirror warnings, quiet/debug, bad flags, missing token). Console and stderr output, exit codes, API call order and arguments, and resulting file trees were identical.
  • Reviewed by five reviewers (behavior parity, spec compliance, tests, robustness, design), each using /code-review-typescript, with two skeptics per finding. The one blocker (type errors in the new test file, which vitest does not catch) and the README inaccuracies are fixed.

Not verified: a live run against Deepnote Cloud, and Windows path behavior.

Pre-existing behavior, moved unchanged

Noticed during review and deliberately not changed here:

  • A file over the 100 MiB buffered upload limit has its live remote copy deleted before the upload is rejected.
  • The .env refusal is case-sensitive: .ENV and .envrc are published.
  • Symlinked files and directories in the build directory are skipped without an event.
  • Pruning a stale project file exactly at the target prefix prints ✓ removed with an empty name.

🤖 Generated with Claude Code

https://claude.ai/code/session_01BYyMrxsMPw3Yu9zmWuusYP

Summary by CodeRabbit

  • New Features
    • Added app publishing through the cloud sync package, with progress and result reporting, optional pruning, and sharing and API-access settings.
    • Publishing can update a matching sync mirror. Diverged files are detected unless force overwrite is enabled.
    • Publishing reports errors for invalid builds and failed uploads or removals; an app URL is provided when sharing succeeds.
  • Documentation
    • Added publishing guidance, an example workflow, and descriptions of publishing-related errors.

Add publishApp(options), which uploads a local build directory into a
project's app folder and keeps the sync mirror up to date. It reports
per-file progress through events, returns a structured result, and throws
PublishError and PublishDivergedError instead of printing and setting
process.exitCode.

deepnote publish becomes an adapter over publishApp with unchanged output
and exit codes. publish-mirror.ts and its tests move into the package, and
the package no longer exports projectFilesDir, which nothing outside it
imports.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BYyMrxsMPw3Yu9zmWuusYP
@tkislan
tkislan requested a review from a team as a code owner October 8, 2026 10:38
@codecov

codecov Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.62385% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 90.44%. Comparing base (149da7f) to head (9ecc18a).

Files with missing lines Patch % Lines
packages/cloud-sync/src/publish-app.ts 98.14% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #566      +/-   ##
==========================================
+ Coverage   90.36%   90.44%   +0.08%     
==========================================
  Files         215      216       +1     
  Lines       12546    12584      +38     
  Branches     3517     3636     +119     
==========================================
+ Hits        11337    11382      +45     
+ Misses       1206     1199       -7     
  Partials        3        3              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@tkislan
tkislan marked this pull request as draft October 8, 2026 12:35
tkislan and others added 3 commits October 9, 2026 13:29
…n its types

Export PublishMirrorError from the package and list it in the README.

The README now follows the package's API-reference table, so the option,
event, result and error details of publishApp live on the exported types.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RC56T3VN4kVv9pmUBgeuf3
PublishAppOptions.syncRoot and the CLI's publish options now use the
exported SyncRootOption instead of restating its union.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RC56T3VN4kVv9pmUBgeuf3
@tkislan

tkislan commented Oct 9, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor
✅ Action performed

Full review finished.

@coderabbitai

coderabbitai Bot commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Essentials
  • Run ID: 3f8994b1-35c4-49a5-8694-4b515849a4cd

📥 Commits

Reviewing files that changed from the base of the PR and between 149da7f and 9ecc18a.


📒 Files selected for processing (7)
  • packages/cli/src/commands/publish.ts
  • packages/cloud-sync/README.md
  • packages/cloud-sync/src/index.ts
  • packages/cloud-sync/src/publish-app.test.ts
  • packages/cloud-sync/src/publish-app.ts
  • packages/cloud-sync/src/publish-mirror.test.ts
  • packages/cloud-sync/src/publish-mirror.ts

Included review availability: This review used your included allowance. Your plan provides up to 8 included reviews per hour; 7 remain after this review.



📝 Walkthrough

Walkthrough

cloud-sync adds publishApp to validate and publish local builds, detect sync-mirror divergence, perform file operations, and return publishing results and events. The CLI delegates its publish command to this API. The package exports and documents the API, and tests cover publishing, mirror behavior, input validation, project loading, and sharing settings.

Priority: ➖ Normal

Estimated code review effort: 4 (Complex) | ~45 minutes

Change: Feature

Sequence Diagram(s)

sequenceDiagram
  participant CLI as deepnote publish
  participant API as publishApp
  participant Mirror as Sync mirror
  participant Cloud as Cloud operations
  CLI->>API: Submit publish options and event callback
  API->>Mirror: Resolve mirror and check divergence
  API->>Cloud: Upload build files and remove stale files
  API->>Mirror: Save successful file changes
  API->>Cloud: Update sharing and API-access settings
  API-->>CLI: Return publish results and events
Loading

Suggested reviewers: jamesbhobbs


Merge Risk: ⚪ Minimal · up to 9ecc1

This change moves the app publishing flow into the cloud-sync package and keeps the CLI as a thin adapter. No actionable merge-blocking risk was found in the supplied context.

🚥 Pre-merge checks | ✅ 5 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 29.41% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 17 functions across 6 files. (1 skipped: … Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check Passed Issue #564 requirements are implemented. publishApp is exported with events, structured results, PublishError, and PublishDivergedError. The divergence check runs before delete or upload unless …
Out of Scope Changes check Passed The changes stay within issue #564. The changed files contain the cloud-sync publish API, mirror extraction, tests, exports, documentation, and the CLI adapter. The supplied whole-PR scope reports no …
Updates Docs Passed The OSS documentation is updated in packages/cloud-sync/README.md. It adds a publishApp example and API-reference entries for publishApp, PublishError, PublishDivergedError, and `PublishMirr…
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly and concisely describes the main change: moving app publishing into @deepnote/cloud-sync.

Full details: Docstring Coverage

Explanation

Docstring coverage is 29.41% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 17 functions across 6 files. (1 skipped: 1 unsupported.)



  • Fix all pre-merge checks with AI
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

@tkislan
tkislan marked this pull request as ready for review October 9, 2026 16:38

This branch has not been deployed

No deployments
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.

Move app publishing into @deepnote/cloud-sync

1 participant