diff --git a/package.json b/package.json index 5704bbdf..906a68c8 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "version": "0.0.0", "packageManager": "pnpm@9.4.0", "scripts": { - "mopub": "tsx scripts/publish", + "npmono": "cd tools/npmono && pnpm dogfood", "build": "turbo build", "test": "pnpm --recursive --workspace-concurrency 1 test" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1c71ad0e..eef2d067 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -61,13 +61,13 @@ importers: dependencies: next: specifier: ^14.2.4 - version: 14.2.4(@playwright/test@1.42.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.71.0) + version: 14.2.4(@babel/core@7.23.9)(@playwright/test@1.42.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.71.0) nextra: specifier: ^2.13.4 - version: 2.13.4(next@14.2.4(@playwright/test@1.42.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.71.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + version: 2.13.4(next@14.2.4(@babel/core@7.23.9)(@playwright/test@1.42.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.71.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0) nextra-theme-docs: specifier: ^2.13.4 - version: 2.13.4(next@14.2.4(@playwright/test@1.42.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.71.0))(nextra@2.13.4(next@14.2.4(@playwright/test@1.42.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.71.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + version: 2.13.4(next@14.2.4(@babel/core@7.23.9)(@playwright/test@1.42.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.71.0))(nextra@2.13.4(next@14.2.4(@babel/core@7.23.9)(@playwright/test@1.42.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.71.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: specifier: ^18.2.0 version: 18.2.0 @@ -714,6 +714,40 @@ importers: specifier: ^1.2.2 version: 1.2.2(@types/node@20.12.12)(sass@1.71.0) + tools/npmono: + dependencies: + '@listr2/prompt-adapter-enquirer': + specifier: ^2.0.2 + version: 2.0.2(enquirer@2.4.1) + '@rebundled/execa': + specifier: 8.0.2-next.2 + version: 8.0.2-next.2 + listr2: + specifier: ^8.0.2 + version: 8.0.2 + semver: + specifier: ^7.6.0 + version: 7.6.0 + sort-package-json: + specifier: ^2.8.0 + version: 2.8.0 + trpc-cli: + specifier: https://pkg.pr.new/mmkal/trpc-cli@38 + version: https://pkg.pr.new/mmkal/trpc-cli@38(@trpc/server@10.45.2)(zod@3.23.8) + devDependencies: + '@types/semver': + specifier: ^7.5.8 + version: 7.5.8 + eslint: + specifier: ^8.57.0 + version: 8.57.0 + eslint-plugin-mmkal: + specifier: 0.7.0 + version: 0.7.0(eslint@8.57.0)(typescript@5.3.3)(vitest@1.2.2(@types/node@20.11.21)) + tsx: + specifier: ^4.19.0 + version: 4.19.0 + packages: '@aashutoshrathi/word-wrap@1.2.6': @@ -12521,6 +12555,48 @@ snapshots: - typescript - vitest + eslint-plugin-mmkal@0.7.0(eslint@8.57.0)(typescript@5.3.3)(vitest@1.2.2(@types/node@20.11.21)): + dependencies: + '@eslint/js': 8.57.0 + '@next/eslint-plugin-next': 14.2.3 + '@rushstack/eslint-config': 3.6.5(eslint@8.57.0)(typescript@5.3.3) + '@rushstack/eslint-plugin': 0.13.1(eslint@8.57.0)(typescript@5.3.3) + '@rushstack/eslint-plugin-packlets': 0.8.1(eslint@8.57.0)(typescript@5.3.3) + '@rushstack/eslint-plugin-security': 0.7.1(eslint@8.57.0)(typescript@5.3.3) + '@types/eslint': 8.56.6 + '@typescript-eslint/eslint-plugin': 7.3.1(@typescript-eslint/parser@7.3.1(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0)(typescript@5.3.3) + '@typescript-eslint/parser': 7.3.1(eslint@8.57.0)(typescript@5.3.3) + eslint-config-prettier: 9.1.0(eslint@8.57.0) + eslint-config-xo: 0.43.1(eslint@8.57.0) + eslint-config-xo-react: 0.27.0(eslint-plugin-react-hooks@4.6.0(eslint@8.57.0))(eslint-plugin-react@7.34.1(eslint@8.57.0))(eslint@8.57.0) + eslint-config-xo-typescript: 1.0.1(@typescript-eslint/eslint-plugin@7.3.1(@typescript-eslint/parser@7.3.1(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0)(typescript@5.3.3))(@typescript-eslint/parser@7.3.1(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0)(typescript@5.3.3) + eslint-plugin-codegen: 0.28.0(eslint@8.57.0) + eslint-plugin-functional: 6.1.1(eslint@8.57.0)(typescript@5.3.3) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.3.1(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0) + eslint-plugin-jest: 27.9.0(@typescript-eslint/eslint-plugin@7.3.1(@typescript-eslint/parser@7.3.1(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0)(typescript@5.3.3) + eslint-plugin-jsx-a11y: 6.8.0(eslint@8.57.0) + eslint-plugin-markdown: 4.0.1(eslint@8.57.0) + eslint-plugin-prettier: 5.1.3(@types/eslint@8.56.6)(eslint-config-prettier@9.1.0(eslint@8.57.0))(eslint@8.57.0)(prettier@3.2.5) + eslint-plugin-promise: 6.1.1(eslint@8.57.0) + eslint-plugin-react: 7.34.1(eslint@8.57.0) + eslint-plugin-react-hooks: 4.6.0(eslint@8.57.0) + eslint-plugin-unicorn: 49.0.0(eslint@8.57.0) + eslint-plugin-vitest: 0.3.26(@typescript-eslint/eslint-plugin@7.3.1(@typescript-eslint/parser@7.3.1(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0)(typescript@5.3.3)(vitest@1.2.2(@types/node@20.11.21)) + eslint-plugin-wrapper: 0.1.0-1 + globals: 14.0.0 + lodash: 4.17.21 + prettier: 3.2.5 + typescript-eslint: 7.3.1(eslint@8.57.0)(typescript@5.3.3) + transitivePeerDependencies: + - babel-plugin-macros + - eslint + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - jest + - supports-color + - typescript + - vitest + eslint-plugin-mmkal@0.7.0(eslint@8.57.0)(typescript@5.3.3)(vitest@1.2.2(@types/node@20.12.12)(sass@1.71.0)): dependencies: '@eslint/js': 8.57.0 @@ -12685,6 +12761,17 @@ snapshots: - supports-color - typescript + eslint-plugin-vitest@0.3.26(@typescript-eslint/eslint-plugin@7.3.1(@typescript-eslint/parser@7.3.1(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0)(typescript@5.3.3)(vitest@1.2.2(@types/node@20.11.21)): + dependencies: + '@typescript-eslint/utils': 7.3.1(eslint@8.57.0)(typescript@5.3.3) + eslint: 8.57.0 + optionalDependencies: + '@typescript-eslint/eslint-plugin': 7.3.1(@typescript-eslint/parser@7.3.1(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0)(typescript@5.3.3) + vitest: 1.2.2(@types/node@20.11.21) + transitivePeerDependencies: + - supports-color + - typescript + eslint-plugin-vitest@0.3.26(@typescript-eslint/eslint-plugin@7.3.1(@typescript-eslint/parser@7.3.1(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0)(typescript@5.3.3)(vitest@1.2.2(@types/node@20.12.12)(sass@1.71.0)): dependencies: '@typescript-eslint/utils': 7.3.1(eslint@8.57.0)(typescript@5.3.3) @@ -14877,15 +14964,15 @@ snapshots: transitivePeerDependencies: - supports-color - next-seo@6.5.0(next@14.2.4(@playwright/test@1.42.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.71.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + next-seo@6.5.0(next@14.2.4(@babel/core@7.23.9)(@playwright/test@1.42.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.71.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: - next: 14.2.4(@playwright/test@1.42.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.71.0) + next: 14.2.4(@babel/core@7.23.9)(@playwright/test@1.42.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.71.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - next-themes@0.2.1(next@14.2.4(@playwright/test@1.42.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.71.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + next-themes@0.2.1(next@14.2.4(@babel/core@7.23.9)(@playwright/test@1.42.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.71.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: - next: 14.2.4(@playwright/test@1.42.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.71.0) + next: 14.2.4(@babel/core@7.23.9)(@playwright/test@1.42.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.71.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -14896,7 +14983,7 @@ snapshots: next-tick@1.1.0: {} - next@14.2.4(@playwright/test@1.42.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.71.0): + next@14.2.4(@babel/core@7.23.9)(@playwright/test@1.42.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.71.0): dependencies: '@next/env': 14.2.4 '@swc/helpers': 0.5.5 @@ -14906,7 +14993,7 @@ snapshots: postcss: 8.4.31 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - styled-jsx: 5.1.1(react@18.2.0) + styled-jsx: 5.1.1(@babel/core@7.23.9)(react@18.2.0) optionalDependencies: '@next/swc-darwin-arm64': 14.2.4 '@next/swc-darwin-x64': 14.2.4 @@ -14923,7 +15010,7 @@ snapshots: - '@babel/core' - babel-plugin-macros - nextra-theme-docs@2.13.4(next@14.2.4(@playwright/test@1.42.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.71.0))(nextra@2.13.4(next@14.2.4(@playwright/test@1.42.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.71.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + nextra-theme-docs@2.13.4(next@14.2.4(@babel/core@7.23.9)(@playwright/test@1.42.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.71.0))(nextra@2.13.4(next@14.2.4(@babel/core@7.23.9)(@playwright/test@1.42.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.71.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@headlessui/react': 1.7.19(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@popperjs/core': 2.11.8 @@ -14934,16 +15021,16 @@ snapshots: git-url-parse: 13.1.1 intersection-observer: 0.12.2 match-sorter: 6.3.4 - next: 14.2.4(@playwright/test@1.42.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.71.0) - next-seo: 6.5.0(next@14.2.4(@playwright/test@1.42.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.71.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - next-themes: 0.2.1(next@14.2.4(@playwright/test@1.42.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.71.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - nextra: 2.13.4(next@14.2.4(@playwright/test@1.42.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.71.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + next: 14.2.4(@babel/core@7.23.9)(@playwright/test@1.42.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.71.0) + next-seo: 6.5.0(next@14.2.4(@babel/core@7.23.9)(@playwright/test@1.42.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.71.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + next-themes: 0.2.1(next@14.2.4(@babel/core@7.23.9)(@playwright/test@1.42.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.71.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + nextra: 2.13.4(next@14.2.4(@babel/core@7.23.9)(@playwright/test@1.42.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.71.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) scroll-into-view-if-needed: 3.1.0 zod: 3.23.8 - nextra@2.13.4(next@14.2.4(@playwright/test@1.42.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.71.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + nextra@2.13.4(next@14.2.4(@babel/core@7.23.9)(@playwright/test@1.42.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.71.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@headlessui/react': 1.7.19(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@mdx-js/mdx': 2.3.0 @@ -14957,7 +15044,7 @@ snapshots: gray-matter: 4.0.3 katex: 0.16.11 lodash.get: 4.4.2 - next: 14.2.4(@playwright/test@1.42.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.71.0) + next: 14.2.4(@babel/core@7.23.9)(@playwright/test@1.42.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.71.0) next-mdx-remote: 4.4.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) p-limit: 3.1.0 react: 18.2.0 @@ -16574,10 +16661,12 @@ snapshots: dependencies: inline-style-parser: 0.1.1 - styled-jsx@5.1.1(react@18.2.0): + styled-jsx@5.1.1(@babel/core@7.23.9)(react@18.2.0): dependencies: client-only: 0.0.1 react: 18.2.0 + optionalDependencies: + '@babel/core': 7.23.9 stylis@4.3.1: {} @@ -17336,6 +17425,24 @@ snapshots: - supports-color - terser + vite-node@1.2.2(@types/node@20.11.21): + dependencies: + cac: 6.7.14 + debug: 4.3.4 + pathe: 1.1.2 + picocolors: 1.0.1 + vite: 5.1.1(@types/node@20.11.21)(sass@1.71.0) + transitivePeerDependencies: + - '@types/node' + - less + - lightningcss + - sass + - stylus + - sugarss + - supports-color + - terser + optional: true + vite-node@1.2.2(@types/node@20.11.21)(sass@1.71.0): dependencies: cac: 6.7.14 @@ -17478,6 +17585,41 @@ snapshots: - supports-color - terser + vitest@1.2.2(@types/node@20.11.21): + dependencies: + '@vitest/expect': 1.2.2 + '@vitest/runner': 1.2.2 + '@vitest/snapshot': 1.2.2 + '@vitest/spy': 1.2.2 + '@vitest/utils': 1.2.2 + acorn-walk: 8.3.2 + cac: 6.7.14 + chai: 4.4.1 + debug: 4.3.4 + execa: 8.0.1 + local-pkg: 0.5.0 + magic-string: 0.30.7 + pathe: 1.1.2 + picocolors: 1.0.1 + std-env: 3.7.0 + strip-literal: 1.3.0 + tinybench: 2.6.0 + tinypool: 0.8.2 + vite: 5.1.1(@types/node@20.11.21)(sass@1.71.0) + vite-node: 1.2.2(@types/node@20.11.21) + why-is-node-running: 2.2.2 + optionalDependencies: + '@types/node': 20.11.21 + transitivePeerDependencies: + - less + - lightningcss + - sass + - stylus + - sugarss + - supports-color + - terser + optional: true + vitest@1.2.2(@types/node@20.11.21)(sass@1.71.0): dependencies: '@vitest/expect': 1.2.2 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 4e708bd3..28fa9afa 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,3 +1,4 @@ packages: - 'packages/*' - 'apps/*' + - 'tools/*' diff --git a/scripts/readme.md b/scripts/readme.md deleted file mode 100644 index 4f1a3340..00000000 --- a/scripts/readme.md +++ /dev/null @@ -1,16 +0,0 @@ -# npmono - -Intended to be the [np](https://npmjs.com/package/np) for monorepos. - -The main reason for its existence, rather than using changesets, which is the usual recommendation: I wanted something more suitable for process-light repos. Changesets requires commiting changesets files along with changes. There's plenty of tooling to help with this, but that tooling needs to be installed and correctly configured. And much of it doesn't work with local branches, and it can be difficult to work around when commits have gone in that _don't_ use changeset. In practice that means every contributor needs to install the changesets tooling and consistently use it. And in my experience, with the right git hygiene (meaningful commits to master, via squash-merged pull requests with full descriptions), there's no actual value to "changeset" files other than the changesets tool itself. So, I wanted a tool that avoided all that overhead, and could just publish packages in a monorepo sensibly. - -Some principles: - -- no other tooling/infrastructure required -- dry-run by default - only perform any side-effects when explicitly requested: - - pre-publish version bumping is done in a "staging area" - a temp directory, so that any aborted attempts _can't_ have an affect on the source repo - - publishing is skipped unless an explicit CLI argument is passed -- use git commit messages for changelogs -- preview offline -- work with any registry -- no "one-way doors" - switch at-will between fixed and independent versioning \ No newline at end of file diff --git a/tools/npmono/eslint.config.js b/tools/npmono/eslint.config.js new file mode 100644 index 00000000..dc2b151f --- /dev/null +++ b/tools/npmono/eslint.config.js @@ -0,0 +1 @@ +module.exports.defualt = require('eslint-plugin-mmkal').recommendedFlatConfigs diff --git a/tools/npmono/package.json b/tools/npmono/package.json new file mode 100644 index 00000000..07aed3cc --- /dev/null +++ b/tools/npmono/package.json @@ -0,0 +1,22 @@ +{ + "name": "npmono", + "version": "0.0.1", + "private": true, + "scripts": { + "dogfood": "tsx src/cli" + }, + "dependencies": { + "@listr2/prompt-adapter-enquirer": "^2.0.2", + "@rebundled/execa": "8.0.2-next.2", + "listr2": "^8.0.2", + "semver": "^7.6.0", + "sort-package-json": "^2.8.0", + "trpc-cli": "https://pkg.pr.new/mmkal/trpc-cli@38" + }, + "devDependencies": { + "@types/semver": "^7.5.8", + "eslint": "^8.57.0", + "eslint-plugin-mmkal": "0.7.0", + "tsx": "^4.19.0" + } +} \ No newline at end of file diff --git a/tools/npmono/readme.md b/tools/npmono/readme.md new file mode 100644 index 00000000..8ae81218 --- /dev/null +++ b/tools/npmono/readme.md @@ -0,0 +1,56 @@ +# npmono + +Intended to be the [np](https://npmjs.com/package/np) for monorepos. (So it's pronounced "np mono", not "npm, oh no!") + +The main reason for its existence, rather than using changesets, which is the usual recommendation: I wanted something more suitable for process-light repos. Changesets requires commiting changesets files along with changes. There's plenty of tooling to help with this, but that tooling needs to be installed and correctly configured. And much of it doesn't work with local branches, and it can be difficult to work around when commits have gone in that _don't_ use changeset. In practice that means every contributor needs to install the changesets tooling and consistently use it. And in my experience, with the right git hygiene (meaningful commits to master, via squash-merged pull requests with full descriptions), there's no actual value to "changeset" files other than the changesets tool itself. So, I wanted a tool that avoided all that overhead, and could just publish packages in a monorepo sensibly. + +Some principles: + +- no other tooling/infrastructure required +- dry-run by default - only perform any side-effects when explicitly requested: + - pre-publish version bumping is done in a "staging area" - a temp directory, so that any aborted attempts _can't_ have an affect on the source repo + - publishing is skipped unless an explicit CLI argument is passed +- use git commit messages for changelogs +- preview offline +- work with any registry +- no "one-way doors" - switch at-will between fixed and independent versioning + +## Usage + +``` +npx npmono +``` + +The above is a dry run. What it will do under the hood: + +1. Find all packages in your (pnpm) monorepo, ordered topologically (most depended-on packages first) +1. Build each package - assuming a `pnpm build` script on each +1. Create a temp directory on your filesystem. This directory will be printed to stdout so you can explore it to confirm it looks right. +1. Pack each package into a tarball inside its own folder in the temp directory +1. Pull the latest package published to the registry for each +1. Prompt you for the new version for the packages. Options here are + 1. Fixed versioning. Each package will be published with the same version, based on a "bump" of the _latest_ version of all packages from the registry. Bump types are: + 1. Any valid semver increment string [(see `semver.inc(...)` docs)](https://www.npmjs.com/package/semver#functions). + 1. `Other` - type in the new version yourself. Note that it must be greater than the latest published version of all packages. + 1. Independent versioning. Each package will be published with a version based on the "bump" of its own latest published version from the registry. Options are: + 1. Any valid semver increment string [(see `semver.inc(...)` docs)](https://www.npmjs.com/package/semver#functions). + 1. `Ask` - you will be given a similar prompt for the new version of each package. You will be able to select to skip publishing any given package. +1. Update the package.json files in each package in the temp directory, prompting if necessary (if using independent versioning) +1. Diff packages and create changelogs: + 1. Look for a `.git.sha` property in each package.json file, falling back to the first commit to the package folder. + 1. Use git to find all commits between the `.git.sha` reference and the current HEAD. + 1. Creates a changelog file for each package, based on: + 1. The commits to the package since the last published version + 1. The changelog of any dependencies that have been updated + 1. Use `git diff` to write diff files: + 1. `source.diff` - the changes to source files (i.e. not gitignore'd) - often, `.ts` files and so on + 1. `package.diff` - the changes to the actual package files - compiled `.js` files etc. +1. If you pass the `--publish` flag: + 1. You will be prompted to enter an OTP for each package unless you pass the `--otp` flag via the CLI (if you don't have MFA enabled, just press enter to publish without a OTP - not recommended) + 1. Publish the packages to the registry + +Note that at no point does it modify any files outside of the temp directory. You don't need to worry about abandoning halfway through and leaving your repo in a messy state where the version is bumped but the publish hasn't happened. + +## Caveats/limitations + +- Only works on pnpm monorepos diff --git a/tools/npmono/src/cli.ts b/tools/npmono/src/cli.ts new file mode 100644 index 00000000..5bb2ad35 --- /dev/null +++ b/tools/npmono/src/cli.ts @@ -0,0 +1,17 @@ +import * as trpcCli from 'trpc-cli' +import {publish} from './publish' + +const t = trpcCli.trpcServer.initTRPC.meta().create() + +const router = t.router({ + publish: t.procedure.mutation(async () => { + return publish() + }), +}) + +const cli = trpcCli.createCli({ + router, + default: {procedure: 'publish'}, +}) + +cli.run() diff --git a/scripts/publish.ts b/tools/npmono/src/publish.ts similarity index 98% rename from scripts/publish.ts rename to tools/npmono/src/publish.ts index 2c5ebfb8..86d336db 100644 --- a/scripts/publish.ts +++ b/tools/npmono/src/publish.ts @@ -7,12 +7,13 @@ import * as semver from 'semver' import {inspect} from 'util' import {sortPackageJson} from 'sort-package-json' -const main = async () => { +export const publish = async () => { + process.chdir('../..') const tasks = new Listr( [ { title: 'Building', - task: async (_ctx, task) => pipeExeca(task, 'pnpm', ['--workspace', 'build']), + task: async (_ctx, task) => pipeExeca(task, 'pnpm', ['-w', 'build']), }, { title: 'Get temp directory', @@ -452,7 +453,10 @@ const main = async () => { ...commitBullets, uncommitedChanges.trim() && 'Uncommitted changes:\n' + uncommitedChanges, ] - return sections.filter(Boolean).join('\n') + return ( + sections.filter(Boolean).join('\n').trim() || + `No ${pkg.name} changes since last publish (${fromRef}..${localRef})` + ) } const changelogFilepath = (pkg: Pkg) => path.join(pkg.folder, 'changes/changelog.md') @@ -623,7 +627,3 @@ const pipeExeca = async (task: ListrTaskWrapper, file: string, ar cmd.stdout.pipe(task.stdout()) return cmd } - -if (require.main === module) { - main() -}