-
-
Notifications
You must be signed in to change notification settings - Fork 3
Stephansama/ste 14 multiple deploy targets #187
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
f10ff0f
8998467
30e4950
97ded53
718e3b1
0eccd20
4fb6348
f2af774
6b1ac0e
9f58585
f2ea1be
918dba2
06c9938
445c042
d030c4d
ee65ad7
e680b7e
591203b
2897efd
b5118bf
81a90cf
1f30a1c
82d0ecf
4fe48a5
d398211
1cc5dbd
fff59de
3a61577
37623f0
57b983e
cadd823
0991446
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -25,6 +25,7 @@ | |
| "kaomojis", | ||
| "macchiato", | ||
| "manypkg", | ||
| "multipublish", | ||
| "nodemon", | ||
| "nvim", | ||
| "nvmrc", | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| # @stephansama/multipublish | ||
|
|
||
| [](https://github.com/stephansama/packages/tree/main/core/multipublish) | ||
| [](https://packages.stephansama.info/api/@stephansama/multipublish) | ||
| [](https://www.npmjs.com/package/@stephansama/multipublish) | ||
| [](https://www.npmjs.com/package/@stephansama/multipublish) | ||
|
|
||
| Publish packages to multiple providers easily | ||
|
|
||
| ##### Table of contents | ||
|
|
||
| <details><summary>Open Table of contents</summary> | ||
|
|
||
| - [Installation](#installation) | ||
| - [Usage](#usage) | ||
|
|
||
| </details> | ||
|
|
||
| ## Installation | ||
|
|
||
| ```sh | ||
| pnpm install @stephansama/multipublish | ||
| ``` | ||
|
|
||
| ## Usage | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add usage documentation for the CLI tool. The Usage section is currently empty. Please document the basic commands, configuration options, and examples for users to understand how to use this multipublish CLI tool. Would you like me to help draft initial usage documentation based on the CLI implementation? 🤖 Prompt for AI Agents |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| import * as fsp from "node:fs/promises"; | ||
| import * as path from "path"; | ||
| import { build as tsdown } from "tsdown"; | ||
| import * as z from "zod"; | ||
|
|
||
| const outDir = path.resolve("./dist"); | ||
| const schemaDir = path.resolve("./config"); | ||
|
|
||
| await build({ attw: false, entry: ["./src/index.ts"] }); | ||
|
|
||
| await build({ dts: true, entry: ["./src/schema.ts"], outDir: schemaDir }); | ||
|
|
||
| const { configSchema } = await import("./config/schema.js"); | ||
|
|
||
| const jsonSchema = z.toJSONSchema(configSchema); | ||
|
|
||
| const jsonString = JSON.stringify(jsonSchema); | ||
|
|
||
| await fsp.writeFile(path.join(schemaDir, "schema.json"), jsonString); | ||
|
|
||
| /** @param {import('tsdown').Options} opts */ | ||
| function build(opts) { | ||
| return tsdown({ | ||
| attw: { excludeEntrypoints: ["schema.json"] }, | ||
| exports: true, | ||
| format: ["esm", "cjs"], | ||
| outDir, | ||
| skipNodeModulesBundle: true, | ||
| target: "esnext", | ||
| ...opts, | ||
| }); | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,5 @@ | ||||||||||||||||||||||||||||||||
| #!/usr/bin/env node | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| "use strict"; | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| import("./dist/index.js").then((mod) => mod.run()); | ||||||||||||||||||||||||||||||||
|
Comment on lines
+1
to
+5
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial Consider adding error handling for import/run failures. If the build hasn't been run or ♻️ Suggested improvement #!/usr/bin/env node
"use strict";
-import("./dist/index.js").then((mod) => mod.run());
+import("./dist/index.js")
+ .then((mod) => mod.run())
+ .catch((err) => {
+ console.error("multipublish failed:", err.message);
+ process.exitCode = 1;
+ });📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,67 @@ | ||||||||||||||
| { | ||||||||||||||
| "name": "@stephansama/multipublish", | ||||||||||||||
| "version": "0.0.0", | ||||||||||||||
| "description": "Publish packages to multiple providers easily", | ||||||||||||||
| "keywords": [ | ||||||||||||||
| "multipublish" | ||||||||||||||
| ], | ||||||||||||||
| "homepage": "https://packages.stephansama.info/api/@stephansama/multipublish", | ||||||||||||||
| "repository": { | ||||||||||||||
| "type": "git", | ||||||||||||||
| "url": "git+https://github.com/stephansama/packages.git", | ||||||||||||||
| "directory": "core/multipublish" | ||||||||||||||
| }, | ||||||||||||||
| "license": "MIT", | ||||||||||||||
| "author": { | ||||||||||||||
| "name": "Stephan Randle", | ||||||||||||||
| "email": "stephanrandle.dev@gmail.com", | ||||||||||||||
| "url": "https://stephansama.info" | ||||||||||||||
| }, | ||||||||||||||
| "type": "module", | ||||||||||||||
| "exports": { | ||||||||||||||
| ".": { | ||||||||||||||
| "import": "./config/schema.js", | ||||||||||||||
| "require": "./config/schema.cjs" | ||||||||||||||
| }, | ||||||||||||||
| "./package.json": "./package.json" | ||||||||||||||
| }, | ||||||||||||||
| "main": "./config/schema.cjs", | ||||||||||||||
| "module": "./config/schema.js", | ||||||||||||||
| "types": "./config/schema.d.cts", | ||||||||||||||
|
stephansama marked this conversation as resolved.
stephansama marked this conversation as resolved.
|
||||||||||||||
| "bin": "./cli.mjs", | ||||||||||||||
| "files": [ | ||||||||||||||
| "./dist", | ||||||||||||||
| "./config", | ||||||||||||||
| "./cli.mjs" | ||||||||||||||
|
Comment on lines
+33
to
+35
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial Consider removing the While the ♻️ Proposed refactor "files": [
- "./dist",
- "./config",
- "./cli.mjs"
+ "dist",
+ "config",
+ "cli.mjs"
],📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||
| ], | ||||||||||||||
|
Comment on lines
+32
to
+36
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Examine build configuration and package.json exports
cd core/multipublish || exit 1
echo "=== package.json exports and files ==="
jq '.exports, .files, .bin' package.json
echo ""
echo "=== build.mjs contents ==="
if [ -f build.mjs ]; then
cat build.mjs
else
echo "build.mjs not found"
fi
echo ""
echo "=== Directory listing ==="
ls -laRepository: stephansama/packages Length of output: 1723 Remove The 🤖 Prompt for AI Agents |
||||||||||||||
| "scripts": { | ||||||||||||||
| "build": "node build.mjs", | ||||||||||||||
| "detect": "node ./test.js", | ||||||||||||||
|
stephansama marked this conversation as resolved.
Outdated
|
||||||||||||||
| "dev": "node --watch build.mjs", | ||||||||||||||
| "lint": "eslint ./ --pass-on-no-patterns --no-error-on-unmatched-pattern" | ||||||||||||||
| }, | ||||||||||||||
| "dependencies": { | ||||||||||||||
| "@manypkg/find-root": "catalog:", | ||||||||||||||
| "@manypkg/get-packages": "catalog:", | ||||||||||||||
| "cosmiconfig": "catalog:cli", | ||||||||||||||
| "dedent": "^1.7.1", | ||||||||||||||
| "obug": "catalog:cli", | ||||||||||||||
| "package-manager-detector": "^1.6.0", | ||||||||||||||
| "yaml": "^2.8.2", | ||||||||||||||
| "yargs": "catalog:cli" | ||||||||||||||
| }, | ||||||||||||||
| "devDependencies": { | ||||||||||||||
| "@types/yargs": "catalog:", | ||||||||||||||
| "jsr": "catalog:", | ||||||||||||||
| "tsdown": "catalog:", | ||||||||||||||
| "zod": "catalog:schema" | ||||||||||||||
|
stephansama marked this conversation as resolved.
Outdated
|
||||||||||||||
| }, | ||||||||||||||
| "peerDependencies": { | ||||||||||||||
| "jsr": ">=0" | ||||||||||||||
| }, | ||||||||||||||
|
stephansama marked this conversation as resolved.
|
||||||||||||||
| "packageManager": "pnpm@10.11.0", | ||||||||||||||
| "publishConfig": { | ||||||||||||||
| "access": "public", | ||||||||||||||
| "registry": "http://localhost:487" | ||||||||||||||
| } | ||||||||||||||
|
coderabbitai[bot] marked this conversation as resolved.
|
||||||||||||||
| } | ||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| import { enable } from "obug"; | ||
| import yargs, { type Options } from "yargs"; | ||
| import { hideBin } from "yargs/helpers"; | ||
|
|
||
| import { MODULE_NAME } from "./util"; | ||
|
|
||
| const args = { | ||
| config: { alias: "c", description: "Path to config file", type: "string" }, | ||
| output: { alias: "s", description: "use changesets", type: "boolean" }, | ||
|
stephansama marked this conversation as resolved.
Outdated
|
||
| verbose: { | ||
| alias: "v", | ||
| description: "Enable verbose logging", | ||
| type: "boolean", | ||
| }, | ||
|
Comment on lines
+29
to
+33
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial Potential alias conflict: The 🤖 Prompt for AI Agents |
||
| } satisfies Record<string, Options>; | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
|
|
||
| export async function parseArgs() { | ||
| const yargsInstance = yargs(hideBin(process.argv)) | ||
| .options(args) | ||
| .help("h") | ||
| .alias("h", "help") | ||
| .epilogue(`--> @stephansama open-source ${new Date().getFullYear()}`); | ||
|
|
||
| const parsed = await yargsInstance | ||
| .wrap(yargsInstance.terminalWidth()) | ||
| .parse(); | ||
|
|
||
| if (parsed.verbose) enable(`${MODULE_NAME}*`); | ||
|
|
||
| return parsed; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| import { cosmiconfig, getDefaultSearchPlaces, type Options } from "cosmiconfig"; | ||
|
|
||
| import { type Config, configSchema } from "./schema"; | ||
| import { MODULE_NAME } from "./util"; | ||
|
|
||
| const searchPlaces = getSearchPlaces(); | ||
|
|
||
| const defaultConfig = { | ||
| platforms: [["jsr", { experimentalGenerateJSR: true }]], | ||
| } satisfies Config; | ||
|
|
||
| export async function loadConfig() { | ||
| const opts: Partial<Options> = { searchPlaces }; | ||
|
|
||
| const explorer = cosmiconfig(MODULE_NAME, opts); | ||
|
|
||
| const result = await explorer.search(); | ||
|
|
||
| return configSchema.parse(result?.config || defaultConfig); | ||
| } | ||
|
|
||
| function getSearchPlaces() { | ||
| return [ | ||
| ...getDefaultSearchPlaces(MODULE_NAME), | ||
| `.config/.${MODULE_NAME}rc.json`, | ||
| `.config/.${MODULE_NAME}rc.yaml`, | ||
| `.config/.${MODULE_NAME}rc.yml`, | ||
| `.config/.${MODULE_NAME}rc`, | ||
| ]; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| import { detect } from "package-manager-detector/detect"; | ||
|
|
||
| export type AgentName = NonNullable<Awaited<ReturnType<typeof detect>>>["name"]; | ||
|
|
||
| let _detected: AgentName | null = null; | ||
|
|
||
| export async function detectPackageManager() { | ||
| if (_detected) return _detected; | ||
|
|
||
| const detected = await detect(); | ||
| if (!detected) throw new Error("unable to detect package manager"); | ||
|
|
||
| _detected = detected.name; | ||
| if (_detected === "bun") throw new Error("bun is not supported"); | ||
|
|
||
| return _detected; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| #!/usr/bin/env node | ||
|
coderabbitai[bot] marked this conversation as resolved.
Outdated
|
||
|
|
||
| import { findRoot } from "@manypkg/find-root"; | ||
| import { getPackages } from "@manypkg/get-packages"; | ||
|
|
||
| import { parseArgs } from "./args"; | ||
| import { loadConfig } from "./config"; | ||
| import { publishPlatform } from "./publish"; | ||
| import * as util from "./util"; | ||
|
|
||
| export async function run() { | ||
| const args = await parseArgs(); | ||
|
coderabbitai[bot] marked this conversation as resolved.
Outdated
stephansama marked this conversation as resolved.
Outdated
|
||
| const config = await loadConfig(); | ||
|
|
||
| const root = await findRoot(process.cwd()); | ||
| const { packages } = await getPackages(root.rootDir); | ||
| const { releases } = await util.getChangesetReleases(); | ||
|
|
||
| const releasedPackages = releases.map((release) => { | ||
| const packageJson = packages.find( | ||
| (pkg) => pkg.packageJson.name === release.name, | ||
| ); | ||
|
|
||
| if (!packageJson) { | ||
| throw new Error( | ||
| `unable to find package for released package ${release.name}`, | ||
| ); | ||
| } | ||
|
|
||
| return { | ||
| newVersion: release.newVersion, | ||
| oldVersion: release.oldVersion, | ||
| ...packageJson, | ||
| }; | ||
| }); | ||
|
|
||
| for (const pkg of releasedPackages) { | ||
| for (const platform of config.platforms) { | ||
| await publishPlatform(pkg, platform); | ||
| } | ||
| } | ||
|
Comment on lines
+10
to
+39
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The The Proposed fix export async function run() {
const args = await getArgs();
const config = await loadConfig(args);
const root = await findRoot(process.cwd());
const { packages } = await getPackages(root.rootDir);
- const { releases } = await util.getChangesetReleases();
+
+ if (!config.useChangesets) {
+ // TODO: Implement alternative release detection when changesets disabled
+ throw new Error("Publishing without changesets is not yet supported");
+ }
+
+ const { releases } = await util.getChangesetReleases();🤖 Prompt for AI Agents
Comment on lines
+30
to
+39
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing error handling for platform publishing failures. If Proposed fix with error collection+ const errors: Array<{ pkg: string; platform: string; error: unknown }> = [];
+
for (const pkg of releasedPackages) {
if (args.versionJsr) {
await updateJsrConfigVersion(pkg);
continue;
}
for (const platform of config.platforms) {
- await publishPlatform(pkg, platform);
+ try {
+ await publishPlatform(pkg, platform);
+ } catch (error) {
+ const platformKey = typeof platform === "string" ? platform : platform[0];
+ errors.push({ pkg: pkg.packageJson.name, platform: platformKey, error });
+ }
}
}
+
+ if (errors.length > 0) {
+ for (const { pkg, platform, error } of errors) {
+ console.error(`Failed to publish ${pkg} to ${platform}:`, error);
+ }
+ throw new Error(`Publishing failed for ${errors.length} package/platform combination(s)`);
+ }
}🤖 Prompt for AI Agents |
||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,48 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import * as z from "zod"; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| export const exportSchema = z.string().or( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| z.record( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| z.string(), | ||||||||||||||||||||||||||||||||||||||||||||||||||
| z.string().or( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| z.object({ | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import: z.object({ default: z.string() }), | ||||||||||||||||||||||||||||||||||||||||||||||||||
| require: z.object({ default: z.string() }), | ||||||||||||||||||||||||||||||||||||||||||||||||||
| }), | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| export const packageJsonSchema = z.object({ | ||||||||||||||||||||||||||||||||||||||||||||||||||
| exports: exportSchema, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| license: z.string().optional(), | ||||||||||||||||||||||||||||||||||||||||||||||||||
| name: z.string().min(1), | ||||||||||||||||||||||||||||||||||||||||||||||||||
| version: z.string(), | ||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+22
to
+27
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial Consider adding version format validation. The ♻️ Suggested improvement export const packageJsonSchema = z.object({
exports: exportSchema,
license: z.string().optional(),
name: z.string().min(1),
- version: z.string(),
+ version: z.string().min(1),
});📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| export const jsrTransformer = packageJsonSchema.transform((schema) => ({ | ||||||||||||||||||||||||||||||||||||||||||||||||||
| exports: convertPkgJsonExportsToJsr(schema.exports), | ||||||||||||||||||||||||||||||||||||||||||||||||||
| license: schema.license, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| name: schema.name, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| version: schema.version, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| })); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| export type JsrSchema = z.infer<typeof jsrSchema>; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| export const jsrSchema = z.object({ | ||||||||||||||||||||||||||||||||||||||||||||||||||
| exports: z | ||||||||||||||||||||||||||||||||||||||||||||||||||
| .string() | ||||||||||||||||||||||||||||||||||||||||||||||||||
| .or(z.array(z.string())) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| .or(z.record(z.string(), z.string())), | ||||||||||||||||||||||||||||||||||||||||||||||||||
| license: z.string().optional(), | ||||||||||||||||||||||||||||||||||||||||||||||||||
| name: z.string().min(1), | ||||||||||||||||||||||||||||||||||||||||||||||||||
| version: z.string(), | ||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+38
to
+49
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial Type inference order is unconventional but functional. The ♻️ Suggested reorder-export type JsrSchema = z.infer<typeof jsrSchema>;
export const jsrSchema = z.object({
exclude: z.array(z.string()).optional(),
exports: z
.string()
.or(z.array(z.string()))
.or(z.record(z.string(), z.string())),
include: z.array(z.string()).optional(),
license: z.string().optional(),
name: z.string().min(1),
version: z.string(),
});
+export type JsrSchema = z.infer<typeof jsrSchema>;📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| function convertPkgJsonExportsToJsr(exports: z.infer<typeof exportSchema>) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (typeof exports === "string") return exports; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| return Object.fromEntries( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| Object.entries(exports).map(([key, value]) => [ | ||||||||||||||||||||||||||||||||||||||||||||||||||
| key, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| typeof value === "string" ? value : value.import.default, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ]), | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+99
to
+110
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Potential runtime error if export object structure varies. Line 104 accesses Defensive check- typeof value === "string" ? value : value.import.default,
+ typeof value === "string"
+ ? value
+ : value.import?.default ?? value.require?.default,🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.