b3a7f98e5a
CI / E2E Cloudflare (4/8) (push) Failing after 0s
CI / E2E Cloudflare (8/8) (push) Failing after 1s
CI / Lint (push) Failing after 1s
Auto Extract / Extract (push) Failing after 4s
CI / Version Check (push) Failing after 9s
CI / Integration Tests (push) Failing after 1s
CI / E2E tests (1/8) (push) Failing after 1s
CI / E2E tests (2/8) (push) Failing after 2s
CI / E2E tests (3/8) (push) Failing after 2s
CI / Browser Tests (push) Failing after 1s
CI / E2E tests (5/8) (push) Failing after 1s
CI / E2E Cloudflare (2/8) (push) Failing after 2s
CI / Typecheck (push) Failing after 1s
CI / Changeset Validation (push) Failing after 2s
CI / E2E Cloudflare (5/8) (push) Failing after 1s
CI / E2E Cloudflare (6/8) (push) Failing after 1s
CI / E2E Cloudflare (7/8) (push) Failing after 1s
CodeQL / Analyze (javascript-typescript) (push) Failing after 1s
Format / Format (push) Failing after 0s
CodeQL / Analyze (actions) (push) Failing after 4s
CI / E2E tests (4/8) (push) Failing after 1s
CI / E2E tests (6/8) (push) Failing after 1s
CI / E2E tests (7/8) (push) Failing after 2s
CI / E2E tests (8/8) (push) Failing after 1s
CI / E2E Cloudflare (1/8) (push) Failing after 1s
CI / E2E Cloudflare (3/8) (push) Failing after 2s
Preview Releases / Publish Preview (push) Failing after 0s
zizmor / Run zizmor (push) Failing after 1s
Release / Release (push) Failing after 2s
CI / Smoke Tests (push) Failing after 5m36s
CI / Tests (push) Failing after 6m36s
Release / Sync Templates (push) Has been skipped
CI / E2E Tests (push) Has been cancelled
123 lines
4.3 KiB
JavaScript
123 lines
4.3 KiB
JavaScript
// Attach sandboxed-plugin tarballs to the GitHub releases that
|
|
// `changesets/action` creates during a release run.
|
|
//
|
|
// The decentralized plugin registry (RFC 0001) stores only a *link* to the
|
|
// plugin bytes, not the bytes themselves. By bundling each published
|
|
// sandboxed plugin and uploading the tarball as a release asset, every
|
|
// version automatically gets a stable public URL that an `emdash-plugin
|
|
// publish --url ...` step (or a human) can point a registry record at.
|
|
//
|
|
// Input: the `publishedPackages` output from changesets/action, passed via
|
|
// the PUBLISHED_PACKAGES env var as a JSON array of `{ name, version }`.
|
|
// Only packages under `packages/plugins/*` that expose a `./sandbox` export
|
|
// and are not private are processed; everything else (native plugins, test
|
|
// fixtures) is skipped.
|
|
//
|
|
// Set DRY_RUN=1 to bundle and resolve tarballs without calling `gh`.
|
|
|
|
import { execFileSync } from "node:child_process";
|
|
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
import { join } from "node:path";
|
|
|
|
const PLUGINS_DIR = "packages/plugins";
|
|
const BUNDLER = "packages/plugin-cli/dist/index.mjs";
|
|
|
|
const SLASH_RE = /\//g;
|
|
const LEADING_AT_RE = /^@/;
|
|
|
|
const repo = process.env.GITHUB_REPOSITORY;
|
|
const dryRun = process.env.DRY_RUN === "1";
|
|
|
|
if (!dryRun && !repo) {
|
|
console.error("GITHUB_REPOSITORY is not set; cannot target `gh release upload`.");
|
|
process.exit(1);
|
|
}
|
|
|
|
// `?? "[]"` only catches undefined/null. An unset Actions output arrives as
|
|
// an empty string, which would make JSON.parse throw, so coalesce that too.
|
|
const raw = process.env.PUBLISHED_PACKAGES?.trim() || "[]";
|
|
let published;
|
|
try {
|
|
published = JSON.parse(raw);
|
|
} catch (error) {
|
|
console.error(`Could not parse PUBLISHED_PACKAGES as JSON: ${error.message}`);
|
|
process.exit(1);
|
|
}
|
|
|
|
if (!Array.isArray(published) || published.length === 0) {
|
|
console.log("No published packages to process.");
|
|
process.exit(0);
|
|
}
|
|
|
|
// name -> version for the packages that were just published.
|
|
const publishedVersions = new Map(published.map((p) => [p.name, p.version]));
|
|
|
|
/** Slugify a manifest id the same way the bundler names its tarball. */
|
|
const slugify = (id) => id.replace(SLASH_RE, "-").replace(LEADING_AT_RE, "");
|
|
|
|
const failures = [];
|
|
let attached = 0;
|
|
|
|
for (const entry of readdirSync(PLUGINS_DIR, { withFileTypes: true })) {
|
|
if (!entry.isDirectory()) continue;
|
|
|
|
const dir = join(PLUGINS_DIR, entry.name);
|
|
const pkgPath = join(dir, "package.json");
|
|
if (!existsSync(pkgPath)) continue;
|
|
|
|
// We read every plugin dir, so a single malformed package.json must not
|
|
// abort the whole step. Treat an unreadable manifest as a skip.
|
|
let pkg;
|
|
try {
|
|
pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
} catch {
|
|
console.warn(`Skipping ${entry.name}: could not read/parse package.json`);
|
|
continue;
|
|
}
|
|
|
|
// Only published, public, sandboxed plugins.
|
|
if (!publishedVersions.has(pkg.name)) continue;
|
|
if (pkg.private === true) continue;
|
|
if (!pkg.exports?.["./sandbox"]) {
|
|
console.log(`Skipping ${pkg.name}: no ./sandbox export (not a sandboxed plugin).`);
|
|
continue;
|
|
}
|
|
|
|
const version = publishedVersions.get(pkg.name);
|
|
const tag = `${pkg.name}@${version}`;
|
|
console.log(`\n=== ${pkg.name}@${version} ===`);
|
|
|
|
try {
|
|
// Bundle. This rebuilds from source and writes dist/<slug>-<version>.tar.gz
|
|
// plus dist/manifest.json, so we can read the exact id/version back out
|
|
// rather than guessing the filename (stale tarballs may linger in dist/).
|
|
execFileSync("node", [BUNDLER, "bundle", "--dir", dir], { stdio: "inherit" });
|
|
|
|
const manifest = JSON.parse(readFileSync(join(dir, "dist", "manifest.json"), "utf-8"));
|
|
const tarball = join(dir, "dist", `${slugify(manifest.id)}-${manifest.version}.tar.gz`);
|
|
if (!existsSync(tarball)) {
|
|
throw new Error(`Expected tarball not found: ${tarball}`);
|
|
}
|
|
|
|
if (dryRun) {
|
|
console.log(`[dry-run] would upload ${tarball} to release ${tag}`);
|
|
} else {
|
|
// --clobber so re-runs replace the asset instead of failing.
|
|
execFileSync("gh", ["release", "upload", tag, tarball, "--clobber", "--repo", repo], {
|
|
stdio: "inherit",
|
|
});
|
|
console.log(`Attached ${tarball} to ${tag}`);
|
|
}
|
|
attached++;
|
|
} catch (error) {
|
|
console.error(`Failed to attach tarball for ${pkg.name}: ${error.message}`);
|
|
failures.push(pkg.name);
|
|
}
|
|
}
|
|
|
|
console.log(`\nAttached ${attached} plugin tarball(s).`);
|
|
if (failures.length > 0) {
|
|
console.error(`Failed: ${failures.join(", ")}`);
|
|
process.exit(1);
|
|
}
|