feat: monorepo#3
Merged
Merged
Conversation
## What's new
### Zero dependencies — for real
- Removed `semver` package — implemented own `inc()` + `satisfies()` with 595 cross-validated tests against original
- Removed `npm version` command — direct file writing for `package.json`, `package-lock.json` (v1/v2/v3), `npm-shrinkwrap.json`
- Removed `eslint` (8 packages) — migrated to `oxlint` with type-aware linting via `tsgolint`
- Removed `ts-node` — using `tsx`
### Workspace / Monorepo support
- Auto-detect workspaces from `package.json` (npm, yarn, bun) and `pnpm-workspace.yaml` (pnpm)
- Independent versioning — each package bumped based on its own changes
- Topological sort — dependencies released before dependents
- Per-package CHANGELOG.md, git tags (`@org/pkg@1.2.0`), GitHub/GitLab releases
- Single git commit for all version bumps
- Cross-package dependency cascade with 3 modes:
- `--cascade full` (default) — always bump + publish dependents
- `--cascade lazy` — bump only when version range doesn't cover new version
- `--cascade none` — only release packages with actual code changes
- Smart range handling: preserves `^`, `~`, exact, `>=` prefixes
- `workspace:*` / `workspace:^` / `workspace:~` protocol support
- `--workspace` to select specific packages, `--contents` to publish from subdirectory
### Bun / pnpm / yarn support
- Auto-detect package manager by lockfile for publish
- Registry per PM: `--registry` (npm/pnpm/bun), `YARN_REGISTRY` + `YARN_NPM_REGISTRY_SERVER` (yarn)
- Multiple registries in one run — `publish-github publish-npmjs --publish-custom URL`
- Lifecycle scripts (`preversion`, `version`, `postversion`) run via shell directly — no dependency on any PM
- `npm_package_version` env variable available in scripts
### New features
- `dry-run` — preview what would happen without making changes (shows changed vs skipped packages)
- `verbose` — detailed output with commits, tags, changelog preview
- `provenance` — npm provenance attestation support
- Config in `package.json` — `"simple-release": { "contents": "dist", "cascade": "full" }`
- GitHub Action — `uses: askuzminov/simple-release@v1`
- OIDC Trusted Publishing support for npmjs.org (no tokens needed)
- GitHub App support for protected branch bypass
### Bug fixes
- `getDate()` now returns `YYYY-MM-DD` (zero-padded) instead of `YYYY-M-D`
- `sp()` handles ENOENT errors (command not found)
- GitLab release logs correctly say "Gitlab" instead of "Github"
- `arg()` no longer reads out of bounds for trailing options
- `markdown.ts` `last()` safe on empty arrays
### Robustness
- Git tag already exists — skip instead of crash
- No commits in repo — fallback to empty tree hash
- Detached HEAD — warning before git operations
- Partial publish failure — continue all registries, report failures, exit 1
- Preversion script modifies package.json — re-read after hook
- Symlink recursion in workspace discovery — cycle detection via `realpathSync`
- BOM in package.json — `parseJSON()` strips UTF-8 BOM
- Windows support — `cmd /c` for lifecycle scripts, `NUL` for empty tree hash
### CI / Auth
- Updated workflow: `actions/checkout@v4`, `actions/setup-node@v4`, Node 22
- GitHub App setup guide for protected branches (no service accounts needed)
- OIDC Trusted Publishing guide for npmjs.org (no token rotation)
- npm 2FA / passkey documentation
### Tests
- 906 tests (was 0), 0 lint errors, 0 warnings
- Unit tests: semver, workspace discovery, topological sort, cascade deps, satisfies, lifecycle scripts, CLI flags, changelog, config parsing, extractPrefix, resolveWorkspace
- Integration tests: real git repo — getHash, getTag, getCommitsRaw, parseCommits, writeGit, writeWorkspaceGit, detectPackageChanges, checkBranch, sp(), parseJSON, full single-package flow
- Cross-validated: 595 tests comparing our `inc()` against original `semver` package
### Documentation
- Complete README rewrite with comparison table, cascade mode guide, decision tree
- GitHub App setup guide, OIDC Trusted Publishing guide
- Migration guide from Lerna
- Edge cases, environment variables, generated CHANGELOG example
- npm 2FA / passkey / security key documentation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What's new
Zero dependencies — for real
semverpackage — implemented owninc()+satisfies()with 595 cross-validated tests against originalnpm versioncommand — direct file writing forpackage.json,package-lock.json(v1/v2/v3),npm-shrinkwrap.jsoneslint(8 packages) — migrated tooxlintwith type-aware linting viatsgolintts-node— usingtsxWorkspace / Monorepo support
package.json(npm, yarn, bun) andpnpm-workspace.yaml(pnpm)@org/pkg@1.2.0), GitHub/GitLab releases--cascade full(default) — always bump + publish dependents--cascade lazy— bump only when version range doesn't cover new version--cascade none— only release packages with actual code changes^,~, exact,>=prefixesworkspace:*/workspace:^/workspace:~protocol support--workspaceto select specific packages,--contentsto publish from subdirectoryBun / pnpm / yarn support
--registry(npm/pnpm/bun),YARN_REGISTRY+YARN_NPM_REGISTRY_SERVER(yarn)publish-github publish-npmjs --publish-custom URLpreversion,version,postversion) run via shell directly — no dependency on any PMnpm_package_versionenv variable available in scriptsNew features
dry-run— preview what would happen without making changes (shows changed vs skipped packages)verbose— detailed output with commits, tags, changelog previewprovenance— npm provenance attestation supportpackage.json—"simple-release": { "contents": "dist", "cascade": "full" }uses: askuzminov/simple-release@v1Bug fixes
getDate()now returnsYYYY-MM-DD(zero-padded) instead ofYYYY-M-Dsp()handles ENOENT errors (command not found)arg()no longer reads out of bounds for trailing optionsmarkdown.tslast()safe on empty arraysRobustness
realpathSyncparseJSON()strips UTF-8 BOMcmd /cfor lifecycle scripts,NULfor empty tree hashCI / Auth
actions/checkout@v4,actions/setup-node@v4, Node 22Tests
inc()against originalsemverpackageDocumentation