Skip to content

ci: host plugin tarballs as release assets, drop marketplace seed#1353

Merged
ascorbic merged 2 commits into
mainfrom
ci/plugin-tarball-hosting
Jun 5, 2026
Merged

ci: host plugin tarballs as release assets, drop marketplace seed#1353
ascorbic merged 2 commits into
mainfrom
ci/plugin-tarball-hosting

Conversation

@ascorbic

@ascorbic ascorbic commented Jun 5, 2026

Copy link
Copy Markdown
Collaborator

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 bundle and uploads dist/<slug>-<version>.tar.gz to the GitHub release changesets/action just created. Native plugins and test fixtures are skipped automatically (no ./sandbox export / 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 publish step 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

  • Bug fix
  • Feature (requires maintainer-approved Discussion)
  • Refactor (no behavior change)
  • Translation
  • Documentation
  • Performance improvement
  • Tests
  • Chore (dependencies, CI, tooling)

Checklist

  • I have read CONTRIBUTING.md
  • pnpm typecheck passes — n/a, CI script only (plain JS, no typed sources changed)
  • pnpm lint passes — lint:json reports 0 diagnostics
  • pnpm test passes (or targeted tests for my change) — n/a, no runtime code; verified the script via DRY_RUN=1 against a mixed publishedPackages set
  • pnpm format has been run
  • I have added/updated tests for my changes (if applicable) — n/a, CI glue
  • User-visible strings in the admin UI are wrapped for translation (if applicable) — n/a, no admin UI
  • I have added a changeset (if this PR changes a published package) — n/a, no published package changed (CI only)
  • New features link to an approved Discussion — n/a, CI tooling

AI-generated code disclosure

  • This PR includes AI-generated code — model/tool: Claude Opus 4.8

Screenshots / test output

DRY_RUN=1 against a mixed published set (three sandboxed plugins + plugin-forms + emdash):

=== @emdash-cms/plugin-atproto@0.2.0 ===
[dry-run] would upload packages/plugins/atproto/dist/atproto-0.2.0.tar.gz to release @emdash-cms/plugin-atproto@0.2.0
=== @emdash-cms/plugin-audit-log@0.2.0 ===
[dry-run] would upload packages/plugins/audit-log/dist/audit-log-0.2.0.tar.gz to release @emdash-cms/plugin-audit-log@0.2.0
Skipping @emdash-cms/plugin-forms: no ./sandbox export (not a sandboxed plugin).
=== @emdash-cms/plugin-webhook-notifier@0.2.0 ===
[dry-run] would upload packages/plugins/webhook-notifier/dist/webhook-notifier-0.2.0.tar.gz to release @emdash-cms/plugin-webhook-notifier@0.2.0
Attached 3 plugin tarball(s).

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.
Copilot AI review requested due to automatic review settings June 5, 2026 07:11
@changeset-bot

changeset-bot Bot commented Jun 5, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 38f310d

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 5, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
docs 38f310d Jun 05 2026, 09:46 AM

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 5, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
❌ Deployment failed
View logs
emdash-playground 38f310d Jun 05 2026, 09:46 AM

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 5, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
emdash-demo-cache 38f310d Jun 05 2026, 09:47 AM

@pkg-pr-new

pkg-pr-new Bot commented Jun 5, 2026

Copy link
Copy Markdown

Open in StackBlitz

@emdash-cms/admin

npm i https://pkg.pr.new/@emdash-cms/admin@1353

@emdash-cms/auth

npm i https://pkg.pr.new/@emdash-cms/auth@1353

@emdash-cms/auth-atproto

npm i https://pkg.pr.new/@emdash-cms/auth-atproto@1353

@emdash-cms/blocks

npm i https://pkg.pr.new/@emdash-cms/blocks@1353

@emdash-cms/cloudflare

npm i https://pkg.pr.new/@emdash-cms/cloudflare@1353

@emdash-cms/contentful-to-portable-text

npm i https://pkg.pr.new/@emdash-cms/contentful-to-portable-text@1353

emdash

npm i https://pkg.pr.new/emdash@1353

create-emdash

npm i https://pkg.pr.new/create-emdash@1353

@emdash-cms/gutenberg-to-portable-text

npm i https://pkg.pr.new/@emdash-cms/gutenberg-to-portable-text@1353

@emdash-cms/plugin-cli

npm i https://pkg.pr.new/@emdash-cms/plugin-cli@1353

@emdash-cms/plugin-types

npm i https://pkg.pr.new/@emdash-cms/plugin-types@1353

@emdash-cms/registry-client

npm i https://pkg.pr.new/@emdash-cms/registry-client@1353

@emdash-cms/registry-lexicons

npm i https://pkg.pr.new/@emdash-cms/registry-lexicons@1353

@emdash-cms/sandbox-workerd

npm i https://pkg.pr.new/@emdash-cms/sandbox-workerd@1353

@emdash-cms/x402

npm i https://pkg.pr.new/@emdash-cms/x402@1353

@emdash-cms/plugin-ai-moderation

npm i https://pkg.pr.new/@emdash-cms/plugin-ai-moderation@1353

@emdash-cms/plugin-atproto

npm i https://pkg.pr.new/@emdash-cms/plugin-atproto@1353

@emdash-cms/plugin-audit-log

npm i https://pkg.pr.new/@emdash-cms/plugin-audit-log@1353

@emdash-cms/plugin-color

npm i https://pkg.pr.new/@emdash-cms/plugin-color@1353

@emdash-cms/plugin-embeds

npm i https://pkg.pr.new/@emdash-cms/plugin-embeds@1353

@emdash-cms/plugin-field-kit

npm i https://pkg.pr.new/@emdash-cms/plugin-field-kit@1353

@emdash-cms/plugin-forms

npm i https://pkg.pr.new/@emdash-cms/plugin-forms@1353

@emdash-cms/plugin-webhook-notifier

npm i https://pkg.pr.new/@emdash-cms/plugin-webhook-notifier@1353

commit: 38f310d

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

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.yml workflow.

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.

Comment on lines +84 to 94
- 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
Comment on lines +31 to +38
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);
}
Comment on lines +28 to +29
const repo = process.env.GITHUB_REPOSITORY;
const dryRun = process.env.DRY_RUN === "1";

@emdashbot emdashbot Bot 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.

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;

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.

[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:

Suggested change
let pkg;
try {
pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
} catch {
console.warn(`Skipping ${entry.name}: could not read/parse package.json`);
continue;
}

@github-actions github-actions Bot added review/awaiting-author Reviewed; waiting on the author to respond and removed review/needs-review No maintainer or bot review yet labels Jun 5, 2026
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.
@github-actions github-actions Bot added review/needs-rereview Author pushed changes since the last review size/L and removed size/M review/awaiting-author Reviewed; waiting on the author to respond labels Jun 5, 2026
@ascorbic ascorbic added the bot:review Trigger an emdashbot code review on this PR label Jun 5, 2026

@emdashbot emdashbot Bot 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.

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 stale dist/ artifacts), and uploads with --clobber for idempotent re-runs. It skips native plugins and private fixtures correctly via ./sandbox export and private checks. 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 after changesets/action and before the manual publish-only recovery path. The inline comment accurately documents the out-of-scope recovery path. Permissions (contents: write) are already present.
  • deploy-marketplace.yml deletion — No remaining references in the repo. Removing the broken workflow is clean.

No new issues found. This is ready to merge.

@github-actions github-actions Bot added review/approved Approved; no new commits since and removed review/needs-rereview Author pushed changes since the last review labels Jun 5, 2026
@ascorbic ascorbic merged commit bb9bc26 into main Jun 5, 2026
46 of 47 checks passed
@ascorbic ascorbic deleted the ci/plugin-tarball-hosting branch June 5, 2026 10:08
@ascorbic

ascorbic commented Jun 5, 2026

Copy link
Copy Markdown
Collaborator Author

Thanks both. Addressed in 38f310d:

  • Unguarded JSON.parse of per-plugin package.json (emdashbot, Copilot): wrapped the read/parse in try/catch so a malformed manifest in any plugin dir is skipped with a warning instead of aborting the step.
  • Empty PUBLISHED_PACKAGES (Copilot): ?? "[]" only catches null/undefined; an unset Actions output is an empty string. Now coalesces empty/whitespace via ?.trim() || "[]". Verified a PUBLISHED_PACKAGES='' run no-ops cleanly.
  • Missing GITHUB_REPOSITORY (Copilot): fail fast with a clear message when not in dry-run.
  • publish-only path (Copilot): that recovery path runs neither changesets/action nor GitHub-release creation, so there's no release to attach to in that run. Left it out deliberately and documented it inline in release.yml; assets for a publish-only run get backfilled manually.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/ci bot:review Trigger an emdashbot code review on this PR review/approved Approved; no new commits since size/L

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants