Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 0 additions & 7 deletions .changeset/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,6 @@
"@executor/ir",
"@executor/runtime-deno-subprocess",
"@executor/runtime-quickjs",
"@executor-js/plugin-file-secrets",
"@executor-js/plugin-google-discovery",
"@executor-js/plugin-graphql",
"@executor-js/plugin-keychain",
"@executor-js/plugin-mcp",
"@executor-js/plugin-onepassword",
"@executor-js/plugin-openapi",
"@executor/marketing"
]
}
13 changes: 13 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ jobs:
uses: actions/setup-node@v4
with:
node-version: 24
registry-url: https://registry.npmjs.org

- name: Update npm for trusted publishing
run: |
npm install -g npm@latest
npm --version

- name: Install dependencies
run: bun install --frozen-lockfile
Expand All @@ -50,6 +56,13 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Publish @executor-js library packages
if: steps.changesets.outputs.hasChangesets == 'false'
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: bun run release:publish:packages

- name: Detect release version change
if: steps.changesets.outputs.hasChangesets == 'false'
id: detect_release
Expand Down
26 changes: 18 additions & 8 deletions RELEASING.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Releasing

This repo uses Changesets for version orchestration and a custom publish script for the generated `executor` npm package plus its platform packages.
This repo uses Changesets for version orchestration and two publish paths:
the CLI (`executor` npm package plus its platform packages) and the
`@executor-js/*` library packages (`core`, `sdk`, and the public plugins).

## Normal release flow

Expand All @@ -9,12 +11,16 @@ This repo uses Changesets for version orchestration and a custom publish script
2. Merge that PR to `main`.
3. `.github/workflows/release.yml` opens or updates a `Version Packages` PR.
4. Merge the `Version Packages` PR.
5. The release workflow tags the commit and dispatches `.github/workflows/publish-executor-package.yml`.
6. The publish workflow:
- runs `bun run release:check`
- performs a full dry-run release build before publish
- publishes npm packages under the correct dist-tag
- creates or updates the GitHub release with build artifacts
5. The release workflow then does two things in parallel:
- Publishes every `@executor-js/*` library package whose current version
is not already on npm, via `bun run release:publish:packages`
(see `scripts/publish-packages.ts`).
- If `apps/cli/package.json` bumped, tags the commit and dispatches
`.github/workflows/publish-executor-package.yml`, which:
- runs `bun run release:check`
- performs a full dry-run release build before publish
- publishes the CLI npm package under the correct dist-tag
- creates or updates the GitHub release with build artifacts

## Beta releases

Expand All @@ -33,7 +39,7 @@ Beta versions publish to npm under `beta`.

## Local dry run

To build the full release payload without publishing to npm or GitHub:
To build the full CLI release payload without publishing to npm or GitHub:

- `bun run release:publish:dry-run`

Expand All @@ -42,6 +48,10 @@ That produces:
- platform archives in `apps/cli/dist`
- the packed wrapper tarball in `apps/cli/dist/release`

To pack the `@executor-js/*` library packages without publishing:

- `bun run release:publish:packages:dry-run`

## Notes

- Changesets owns the published CLI version via `apps/cli/package.json`.
Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
"dev:cli": "bun run apps/cli/src/main.ts",
"test": "turbo run test",
"test:release:bootstrap": "vitest run tests/release-bootstrap-smoke.test.ts",
"build:packages": "bun run --filter='@executor-js/core' build && bun run --filter='@executor-js/sdk' --filter='@executor/plugin-*' build",
"build:packages": "bun run --filter='@executor-js/core' build && bun run --filter='@executor-js/sdk' --filter='@executor-js/plugin-*' build",
"typecheck": "bun run --filter='*' typecheck",
"lint": "oxlint -c .oxlintrc.jsonc . --deny-warnings",
"lint:fix": "oxlint -c .oxlintrc.jsonc --fix .",
Expand All @@ -77,6 +77,8 @@
"release:beta:stop": "changeset pre exit",
"release:publish:dry-run": "bun run --cwd apps/cli release:publish:dry-run",
"release:publish": "bun run --cwd apps/cli release:publish",
"release:publish:packages": "bun run scripts/publish-packages.ts",
"release:publish:packages:dry-run": "bun run scripts/publish-packages.ts --dry-run",
"prepare": "effect-language-service patch"
},
"devDependencies": {
Expand Down
10 changes: 10 additions & 0 deletions packages/core/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@
"name": "@executor-js/core",
"version": "1.4.0",
"type": "module",
"license": "MIT",
"repository": {
"type": "git",
"url": "git+https://github.com/RhysSullivan/executor.git",
"directory": "packages/core/core"
},
"homepage": "https://github.com/RhysSullivan/executor/tree/main/packages/core/core",
"bugs": {
"url": "https://github.com/RhysSullivan/executor/issues"
},
"exports": {
".": "./src/index.ts"
},
Expand Down
10 changes: 10 additions & 0 deletions packages/plugins/file-secrets/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@
"name": "@executor-js/plugin-file-secrets",
"type": "module",
"version": "1.4.2",
"license": "MIT",
"repository": {
"type": "git",
"url": "git+https://github.com/RhysSullivan/executor.git",
"directory": "packages/plugins/file-secrets"
},
"homepage": "https://github.com/RhysSullivan/executor/tree/main/packages/plugins/file-secrets",
"bugs": {
"url": "https://github.com/RhysSullivan/executor/issues"
},
"exports": {
".": "./src/promise.ts",
"./core": "./src/index.ts"
Expand Down
10 changes: 10 additions & 0 deletions packages/plugins/google-discovery/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@
"name": "@executor-js/plugin-google-discovery",
"type": "module",
"version": "1.4.2",
"license": "MIT",
"repository": {
"type": "git",
"url": "git+https://github.com/RhysSullivan/executor.git",
"directory": "packages/plugins/google-discovery"
},
"homepage": "https://github.com/RhysSullivan/executor/tree/main/packages/plugins/google-discovery",
"bugs": {
"url": "https://github.com/RhysSullivan/executor/issues"
},
"exports": {
".": "./src/promise.ts",
"./core": "./src/sdk/index.ts",
Expand Down
10 changes: 10 additions & 0 deletions packages/plugins/graphql/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@
"name": "@executor-js/plugin-graphql",
"type": "module",
"version": "1.4.2",
"license": "MIT",
"repository": {
"type": "git",
"url": "git+https://github.com/RhysSullivan/executor.git",
"directory": "packages/plugins/graphql"
},
"homepage": "https://github.com/RhysSullivan/executor/tree/main/packages/plugins/graphql",
"bugs": {
"url": "https://github.com/RhysSullivan/executor/issues"
},
"exports": {
".": "./src/promise.ts",
"./core": "./src/sdk/index.ts",
Expand Down
10 changes: 10 additions & 0 deletions packages/plugins/keychain/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@
"name": "@executor-js/plugin-keychain",
"type": "module",
"version": "1.4.2",
"license": "MIT",
"repository": {
"type": "git",
"url": "git+https://github.com/RhysSullivan/executor.git",
"directory": "packages/plugins/keychain"
},
"homepage": "https://github.com/RhysSullivan/executor/tree/main/packages/plugins/keychain",
"bugs": {
"url": "https://github.com/RhysSullivan/executor/issues"
},
"exports": {
".": "./src/promise.ts",
"./core": "./src/index.ts"
Expand Down
10 changes: 10 additions & 0 deletions packages/plugins/mcp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@
"name": "@executor-js/plugin-mcp",
"type": "module",
"version": "1.4.2",
"license": "MIT",
"repository": {
"type": "git",
"url": "git+https://github.com/RhysSullivan/executor.git",
"directory": "packages/plugins/mcp"
},
"homepage": "https://github.com/RhysSullivan/executor/tree/main/packages/plugins/mcp",
"bugs": {
"url": "https://github.com/RhysSullivan/executor/issues"
},
"exports": {
".": "./src/promise.ts",
"./core": "./src/sdk/index.ts",
Expand Down
10 changes: 10 additions & 0 deletions packages/plugins/onepassword/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@
"name": "@executor-js/plugin-onepassword",
"type": "module",
"version": "1.4.2",
"license": "MIT",
"repository": {
"type": "git",
"url": "git+https://github.com/RhysSullivan/executor.git",
"directory": "packages/plugins/onepassword"
},
"homepage": "https://github.com/RhysSullivan/executor/tree/main/packages/plugins/onepassword",
"bugs": {
"url": "https://github.com/RhysSullivan/executor/issues"
},
"exports": {
".": "./src/promise.ts",
"./api": "./src/api/index.ts",
Expand Down
10 changes: 10 additions & 0 deletions packages/plugins/openapi/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@
"name": "@executor-js/plugin-openapi",
"type": "module",
"version": "1.4.2",
"license": "MIT",
"repository": {
"type": "git",
"url": "git+https://github.com/RhysSullivan/executor.git",
"directory": "packages/plugins/openapi"
},
"homepage": "https://github.com/RhysSullivan/executor/tree/main/packages/plugins/openapi",
"bugs": {
"url": "https://github.com/RhysSullivan/executor/issues"
},
"exports": {
".": "./src/promise.ts",
"./core": "./src/sdk/index.ts",
Expand Down
10 changes: 10 additions & 0 deletions packages/published/sdk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@
"name": "@executor-js/sdk",
"version": "1.4.0",
"type": "module",
"license": "MIT",
"repository": {
"type": "git",
"url": "git+https://github.com/RhysSullivan/executor.git",
"directory": "packages/published/sdk"
},
"homepage": "https://github.com/RhysSullivan/executor/tree/main/packages/published/sdk",
"bugs": {
"url": "https://github.com/RhysSullivan/executor/issues"
},
"exports": {
".": "./src/index.ts"
},
Expand Down
122 changes: 122 additions & 0 deletions scripts/publish-packages.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
#!/usr/bin/env bun
/**
* Publishes the public @executor-js/* workspace packages to npm.
*
* Walks a hard-coded list of publishable package directories, determines the
* dist-tag from the version string (anything containing `-` is treated as beta),
* and packs + publishes each package whose current version is not already on npm.
*
* Invoked from `.github/workflows/release.yml` via the `publish:` input on
* changesets/action after the Version Packages PR has been merged, and locally
* via `bun run release:publish:packages` (or `--dry-run`).
*/
import { $ } from "bun";
import { existsSync } from "node:fs";
import { dirname, join, resolve } from "node:path";
import { fileURLToPath } from "node:url";

type Channel = "latest" | "beta";

const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");

/**
* Workspace-relative paths of the public packages. Kept explicit so a new
* directory under `packages/plugins/` does not accidentally ship to npm.
*/
const PUBLIC_PACKAGE_DIRS = [
"packages/core/core",
"packages/published/sdk",
"packages/plugins/file-secrets",
"packages/plugins/google-discovery",
"packages/plugins/graphql",
"packages/plugins/keychain",
"packages/plugins/mcp",
"packages/plugins/onepassword",
"packages/plugins/openapi",
] as const;

const parseArgs = (argv: ReadonlyArray<string>): { dryRun: boolean } => {
let dryRun = false;
for (const arg of argv) {
if (arg === "--dry-run") {
dryRun = true;
continue;
}
throw new Error(`Unknown argument: ${arg}`);
}
return { dryRun };
};

const resolveChannel = (version: string): Channel =>
version.includes("-") ? "beta" : "latest";

const readPackageMeta = async (pkgDir: string) => {
const pkgJsonPath = join(pkgDir, "package.json");
const pkg = await Bun.file(pkgJsonPath).json() as {
name?: string;
version?: string;
private?: boolean;
};

if (!pkg.name || !pkg.version) {
throw new Error(`Missing name/version in ${pkgJsonPath}`);
}
if (pkg.private === true) {
throw new Error(`${pkg.name} is marked private and cannot be published`);
}

return { name: pkg.name, version: pkg.version };
};

const packageAlreadyPublished = async (name: string, version: string): Promise<boolean> => {
const proc = Bun.spawn(["npm", "view", `${name}@${version}`, "version"], {
stdio: ["ignore", "ignore", "ignore"],
});
return (await proc.exited) === 0;
};

const publishPackage = async (pkgDir: string, channel: Channel, dryRun: boolean) => {
const { name, version } = await readPackageMeta(pkgDir);

if (!existsSync(join(pkgDir, "dist"))) {
throw new Error(`Missing dist/ in ${pkgDir}. Did you run 'bun run build:packages'?`);
}

if (await packageAlreadyPublished(name, version)) {
console.log(`[skip] ${name}@${version} already on npm`);
return;
}

console.log(`[publish] ${name}@${version} (${channel})${dryRun ? " [dry-run]" : ""}`);

await $`bun pm pack`.cwd(pkgDir);

if (dryRun) {
return;
}

const args = ["publish", "*.tgz", "--access", "public", "--tag", channel];
if (process.env.GITHUB_ACTIONS === "true") {
args.push("--provenance");
}
await $`npm ${args}`.cwd(pkgDir);
};

const main = async () => {
const { dryRun } = parseArgs(process.argv.slice(2));

// Use the @executor-js/sdk version as the source of truth for the channel.
// All @executor-js packages version together (they're not in the changeset
// ignore list), so they share a release channel.
const sdkMeta = await readPackageMeta(join(repoRoot, "packages/published/sdk"));
const channel = resolveChannel(sdkMeta.version);
console.log(`Publishing @executor-js packages (${channel})${dryRun ? " [dry-run]" : ""}`);

await $`bun run build:packages`.cwd(repoRoot);

for (const relDir of PUBLIC_PACKAGE_DIRS) {
await publishPackage(join(repoRoot, relDir), channel, dryRun);
}
};

await main();