ci: host plugin tarballs as release assets, drop marketplace seed#1353
Conversation
Attach each published sandboxed plugin's bundle to the GitHub release changesets creates, giving the decentralized registry (RFC 0001) a stable public URL per version. Remove the legacy marketplace seed workflow, which has been failing since the post-#1057 plugin layout broke its bundler and is superseded by the registry.
|
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
docs | 38f310d | Jun 05 2026, 09:46 AM |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ❌ Deployment failed View logs |
emdash-playground | 38f310d | Jun 05 2026, 09:46 AM |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
emdash-demo-cache | 38f310d | Jun 05 2026, 09:47 AM |
@emdash-cms/admin
@emdash-cms/auth
@emdash-cms/auth-atproto
@emdash-cms/blocks
@emdash-cms/cloudflare
@emdash-cms/contentful-to-portable-text
emdash
create-emdash
@emdash-cms/gutenberg-to-portable-text
@emdash-cms/plugin-cli
@emdash-cms/plugin-types
@emdash-cms/registry-client
@emdash-cms/registry-lexicons
@emdash-cms/sandbox-workerd
@emdash-cms/x402
@emdash-cms/plugin-ai-moderation
@emdash-cms/plugin-atproto
@emdash-cms/plugin-audit-log
@emdash-cms/plugin-color
@emdash-cms/plugin-embeds
@emdash-cms/plugin-field-kit
@emdash-cms/plugin-forms
@emdash-cms/plugin-webhook-notifier
commit: |
There was a problem hiding this comment.
Pull request overview
Adds an automated release-time step to bundle first-party sandboxed plugins and upload their .tar.gz bundles as GitHub Release assets (so the decentralized registry can reference stable public URLs), and removes the legacy marketplace seeding workflow.
Changes:
- Update the release workflow to run a new “attach plugin tarballs” step after a successful Changesets publish.
- Add a Node script that filters published packages to public sandboxed plugins, runs
emdash-plugin bundle, and uploads the resulting tarballs to the corresponding GitHub releases. - Delete the deprecated
deploy-marketplace.ymlworkflow.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
.github/workflows/release.yml |
Runs the new tarball-attachment script after Changesets publishes releases. |
.github/workflows/deploy-marketplace.yml |
Removes the legacy marketplace seeding workflow. |
.github/scripts/attach-plugin-tarballs.mjs |
Implements bundling + release-asset upload for published sandboxed plugins. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| - name: Attach plugin tarballs to releases | ||
| if: ${{ steps.changesets.outputs.published == 'true' }} | ||
| run: node .github/scripts/attach-plugin-tarballs.mjs | ||
| env: | ||
| GITHUB_TOKEN: ${{ steps.app-token.outputs.token }} | ||
| GITHUB_REPOSITORY: ${{ github.repository }} | ||
| PUBLISHED_PACKAGES: ${{ steps.changesets.outputs.publishedPackages }} | ||
|
|
||
| - name: Publish (manual) | ||
| if: ${{ inputs.publish-only }} | ||
| run: node .github/scripts/release.mjs publish |
| const raw = process.env.PUBLISHED_PACKAGES ?? "[]"; | ||
| let published; | ||
| try { | ||
| published = JSON.parse(raw); | ||
| } catch (error) { | ||
| console.error(`Could not parse PUBLISHED_PACKAGES as JSON: ${error.message}`); | ||
| process.exit(1); | ||
| } |
| const repo = process.env.GITHUB_REPOSITORY; | ||
| const dryRun = process.env.DRY_RUN === "1"; |
There was a problem hiding this comment.
The approach is sound. Automating tarball hosting for sandboxed plugins and removing the broken deploy-marketplace.yml is the right move — it unblocks the decentralized registry (RFC 0001) without adding runtime code, and the script correctly distinguishes sandboxed plugins via ./sandbox export while skipping native plugins and private fixtures.
I checked the new attach-plugin-tarballs.mjs script, the updated release.yml step ordering and conditional logic, and the removed marketplace workflow. The script handles dry-run, bundles from source to avoid stale artifacts, and mirrors the bundler's slugify logic exactly.
One real fragility: the script iterates all subdirectories of packages/plugins/, reads each package.json, and parses it with an unguarded JSON.parse(). If any plugin directory — even a non-published test fixture or a work-in-progress directory — contains a malformed or empty package.json, the exception bubbles up uncaught and aborts tarball attachment for every published plugin. The fix is a narrow try/catch around the per-directory read so a bad file is treated as a skip rather than a fatal error.
Otherwise the diff is clean.
| const dir = join(PLUGINS_DIR, entry.name); | ||
| const pkgPath = join(dir, "package.json"); | ||
| if (!existsSync(pkgPath)) continue; | ||
|
|
There was a problem hiding this comment.
[needs fixing] The JSON.parse() here is unprotected. The script iterates all subdirectories of packages/plugins/ (not just published ones), so a malformed, empty, or merge-conflicted package.json in any plugin directory — even a non-published test fixture — will throw an uncaught exception and abort tarball attachment for every published plugin.
Wrap the read/parse in a try/catch so a bad file is gracefully skipped instead of killing the release step:
| let pkg; | |
| try { | |
| pkg = JSON.parse(readFileSync(pkgPath, "utf-8")); | |
| } catch { | |
| console.warn(`Skipping ${entry.name}: could not read/parse package.json`); | |
| continue; | |
| } |
Address review feedback: guard per-directory package.json parsing so one bad manifest doesn't abort the step, treat an empty PUBLISHED_PACKAGES output as no-op, and fail fast when GITHUB_REPOSITORY is missing. Note the publish-only path limitation in the workflow.
There was a problem hiding this comment.
Re-review of PR #1353. The previous fragility — an unguarded JSON.parse() when iterating plugin directories that could abort the entire tarball-attachment step on a single malformed package.json — has been fixed correctly in commit 38f310d3. The script now wraps each per-directory manifest read in a narrow try/catch, warns, and skips, which is exactly the right behavior.
The same commit also added two sensible hardenings that weren't in the original diff but improve robustness: fast-failing when GITHUB_REPOSITORY is missing in non-dry-run mode, and coalescing an empty-string PUBLISHED_PACKAGES to "[]" so an unset Actions output doesn't throw.
I re-checked the full diff:
attach-plugin-tarballs.mjs— The script rebuilds each sandboxed plugin from source, reads the manifest back to determine the exact tarball filename (defensive against staledist/artifacts), and uploads with--clobberfor idempotent re-runs. It skips native plugins and private fixtures correctly via./sandboxexport andprivatechecks. Error handling is now proportionate: per-plugin failures are collected and reported at the end without killing the rest of the batch..github/workflows/release.yml— The new step is correctly placed afterchangesets/actionand before the manualpublish-onlyrecovery path. The inline comment accurately documents the out-of-scope recovery path. Permissions (contents: write) are already present.deploy-marketplace.ymldeletion — No remaining references in the repo. Removing the broken workflow is clean.
No new issues found. This is ready to merge.
|
Thanks both. Addressed in 38f310d:
|
What does this PR do?
Automates hosting for first-party sandboxed plugins on the decentralized plugin registry (RFC 0001), and removes the legacy marketplace seed workflow.
The registry stores only a link to a plugin's bytes, not the bytes themselves, so every release needs a stable public URL. This adds a release step that, for each published sandboxed plugin, bundles it with
emdash-plugin bundleand uploadsdist/<slug>-<version>.tar.gzto the GitHub releasechangesets/actionjust created. Native plugins and test fixtures are skipped automatically (no./sandboxexport /private).Result: from the next release onward, every sandboxed plugin version gets a stable asset URL the registry record can point at. The CI registry
publishstep itself is out of scope here (tracked under RFC 2); this only lands the hosting prerequisite.Also deletes
deploy-marketplace.yml. It has failed on every run since ~May 19: it uses the old core-CLI bundler, which cannot resolve the post-#1057 plugin layout, and the marketplace is superseded by the registry.Not closing an issue.
Type of change
Checklist
pnpm typecheckpasses — n/a, CI script only (plain JS, no typed sources changed)pnpm lintpasses —lint:jsonreports 0 diagnosticspnpm testpasses (or targeted tests for my change) — n/a, no runtime code; verified the script viaDRY_RUN=1against a mixedpublishedPackagessetpnpm formathas been runAI-generated code disclosure
Screenshots / test output
DRY_RUN=1against a mixed published set (three sandboxed plugins +plugin-forms+emdash):