Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/oe/lerna-ci
The essential toolkit for monorepo managed by lerna/yarn/pnpm/turbo/etc
https://github.com/oe/lerna-ci
lerna monorepo npm pnpm turbo typescript yarn
Last synced: 25 days ago
JSON representation
The essential toolkit for monorepo managed by lerna/yarn/pnpm/turbo/etc
- Host: GitHub
- URL: https://github.com/oe/lerna-ci
- Owner: oe
- License: mit
- Created: 2019-04-01T05:45:56.000Z (over 5 years ago)
- Default Branch: main
- Last Pushed: 2024-05-17T13:21:14.000Z (6 months ago)
- Last Synced: 2024-09-30T15:13:11.837Z (about 1 month ago)
- Topics: lerna, monorepo, npm, pnpm, turbo, typescript, yarn
- Language: TypeScript
- Homepage:
- Size: 369 KB
- Stars: 5
- Watchers: 2
- Forks: 1
- Open Issues: 2
-
Metadata Files:
- Readme: readme.md
- License: LICENSE
Awesome Lists containing this project
README
lerna-ci
The essential toolkit for monorepo managed by lerna/npm/yarn/pnpm/turbo/etc
- [Features](#features)
- [Install](#install)
- [Usage](#usage)
- [Cli commands](#cli-commands)
- [synclocal](#synclocal)
- [syncdeps](#syncdeps)
- [canpublish](#canpublish)
- [fixpack](#fixpack)
- [changed](#changed)
- [API](#api)
- [getAllPackageDigests](#getallpackagedigests)
- [syncLocal](#synclocal-api)
- [syncDeps](#syncdeps-api)
- [fixpack](#fixpack-api)
- [getChanged](#getChanged)
- [getRepoNpmClient](#getreponpmclient)
- [getVersionFormRegistry](#getversionformregistry)
- [getVersionsFromRegistry](#getversionsfromregistry)
- [getPackageVersionsFromGit](#getpackageversionsfromgit)
- [isLernaAvailable](#islernaavailable)
- [getGitRoot](#getgitroot)
- [getProjectRoot](#getprojectroot)
- [maxVersion](#maxversion)
- [pickOne](#pickone)
- [Configuration file](#configuration-file)
- [Breaking changes](#breaking-changes)## Features
* sync versions of packages in monorepo (with cli command)
* sync(update) dependencies versions of all packages (with cli command)
* can update to latest version
* can update to specified version
* can specify packages with wildcard characters
* format all package.json files (with cli command)
* check if all packages are qualified to publish to npm (with cli command)
* list all packages(requires `lerna` or `@changesets/cli`) (with cli command)
* get all packages' meta info
* some other useful utilities**`lerna-ci` is designed for monorepo, but it can also be used in standard repo.**
## Install
```sh
# with yarn, install as a devDependency
yarn add lerna-ci -D# with npm, install as a devDependency
npm install lerna-ci -D
```
you may also install it to global if you use cli commands frequently(not recommended)Notice: **lerna-ci requires node `>=14.6`**
## Usage
```sh
# sync versions of packages in monorepo, to fix versions of packages in monorepo when they are messed up
yarn lerna-ci synclocal# sync all packages' dependencies versions
# following command will sync all @babel scoped npm packages and typescript to latest version, but react and react-dom will be set to 16.x
yarn lerna-ci syncremote "@babel/*" "[email protected]" "[email protected]" typescript# format all package.json files
yarn lerna-ci fixpack```
## Cli commands
`lerna-ci` also provide some cli commands, so that you do some task with a single line code.### synclocal
sync versions of packages in monorepo, using [syncLocal](#synclocal-api) under the hood.```sh
# with yarn
yarn lerna-ci synclocal [source] [--check-only]# version source, determine where to get the packages' versions, could be:
# git, npm, local, or all, default local
# if check-only is true, it will only check if packages' versions are synced, exit 1 if not synced# or if you prefer npm
npx lerna-ci synclocal [source] [--check-only]# check for more options and examples
yarn lerna-ci synclocal --help# demo
yarn lerna-ci synclocal
```It's very useful when local packages versions are messed up, this may lead to some unexpected errors, it can happens in some cases:
1. publish a beta version inside a package without using lerna(or other monorepo tools)
2. partial success when publish packages with lerna(or other monorepo tools), you may use `yarn lerna-ci synclocal all` to fix itYou may need to run `yarn` or `npm install` to make your changes take effect.
### syncdeps
sync all packages' dependencies versions in monorepo, using [syncDeps](#syncdeps-api) under the hood.It will update following kinds of dependencies:
* dependencies
* devDependencies
* optionalDependencies
* peerDependencies```sh
# with yarn
yarn lerna-ci syncdeps [--check-only]
# packageNames could be a list of package names, or a list of package name with version range, such as:
# "@babel/*" "@babel/core@^7.0.0" "parcel@^2.0.0" "rollup-plugin*"
# package name with asterisk(*) must be quoted
# packageNames not found or not matched will be ignored
# if check-only is true, it will check if any package's dependencies need be synced, exit 1 if found# or if you prefer npm, must use quotes when specify scoped wildcard package name
npx lerna-ci syncdeps [--check-only]# check for more options and examples
yarn lerna-ci syncdeps --help# demo
## sync all babel related packages' versions to `^7.0.0`, all packages that start with `eslint-plugin-` to latest, and react react-dom to `18.2.0`
yarn lerna-ci syncdeps "@babel/*@^7.0.0" "eslint-plugin-*" [email protected] [email protected]
```You may need to run `yarn` or `npm install` to make your changes take effect.
### canpublish
check if all packages are qualified to publish to npm, using [getChanged](#getChanged) under the hood if `lerna` or `@changesets/cli` is available, it will check:
1. whether local has uncommitted changes when in git repo if `--check-git` is true
2. whether local has conflicts when in git repo
3. whether local is behind of remote when in git repo
4. whether local packages' versions are synced with the latest version when `use-max-version` is true
5. whether next versions(can be configured via `releaseType` and `period`) of local packages are occupied on npm and gitit will exit 1 if any of the above conditions is satisfied
```sh
yarn lerna-ci canpublish [--releaseType=patch] [--period=alpha]
# releaseType: patch, minor, major, prepatch, preminor, premajor, prerelease
# default patch
# period: a string like alpha, beta, rc, etc, default alpha, only available when releaseType is pre*# check for more options and examples
yarn lerna-ci canpublish --help# demo
# check if all (changed) packages are qualified to publish a beta version in patch
yarn lerna-ci canpublish --releaseType=patch --period=beta
```### fixpack
format all packages' package.json, using [fixpack](#fixpack-api) under the hood```sh
# with yarn
yarn lerna-ci fixpack# or if you prefer npm
npx lerna-ci fixpack
```
above command will format all package.json files with default configuration, you can configure `fixpack`'s params via [configuration file](#configurationfile)### changed
list all changed packages, using [getChanged](#getChanged) under the hood```sh
# with yarn
yarn lerna-ci changed# or if you prefer npm
npx lerna-ci changed
```
above command requires package [`lerna`](https://www.npmjs.com/package/lerna) or [`@changesets/cli`](https://www.npmjs.com/package/@changesets/cli) to be installed, or it will exit 1.You should configure `lerna` or `@changesets/cli` following their documentations and manage your packages under their official guidelines, or this command will not work as expected.
## API
### getAllPackageDigests
get all packages info in monorepo(including the root package), you can filter with custom optionse.g.
```js
import { getAllPackageDigests } from 'lerna-ci'// get all packages
getAllPackageDigests().then(res => console.log(res))
// [{name: 'my-package', version: '1.0.1', private: false, location: '/Users/xx/work/monorepo/my-package'}]// find packages with custom filter function
getAllPackageDigests((digest => digest.name.startWith('@inner/a-'))).then(res => console.log(res))// find public packages which package name contains '@inner/'
getAllPackageDigests({ignorePrivate: true, keyword: '@inner/'}).then(res => console.log(res))
```Type Declarations:
```ts
getAllPackageDigests(filter?: IPackageFilterOptions) => Promise/** package filter object */
export interface IPackageFilterObject {
/** whether need private package */
ignorePrivate?: boolean
/** search package contains the keyword */
keyword?: string
}
/** package filter function */
export type IPackageFilter = (pkg: IPackageDigest, index: number, arr: IPackageDigest[]) => booleanexport type IPackageFilterOptions = IPackageFilterObject | IPackageFilter
/**
* package digest info
*/
export interface IPackageDigest {
/** package name */
name: string
/** package version */
version: string
/** whether package is private */
private: boolean
/** package folder full path */
location: string
}
```
### syncLocal
sync versions of packages in monorepo(version info can be fetch from npm or git tag), if they depend each other and dependence version will be rematched.> also available as command [synclocal](#synclocal)
e.g.
```js
import { syncLocal } from 'lerna-ci'
// return all changed package infos
const updatedPkgs = await syncLocal({ versionSource: 'npm' })
// [{name: 'my-package', version: '1.0.1', private: false, location: '/Users/xx/work/monorepo/my-package'}]
```Type Declarations:
```ts
syncLocal(options?: ISyncPackageOptions) => Promiseexport interface ISyncPackageOptions {
/**
* version source, default to `local`
* how to get latest locale package versions: npm, git, local or all
* @default 'all'
*/
versionSource?: EVerSource
/**
* npm/git version strategy
* @default 'latest'
*/
versionStrategy?: IVersionPickStrategy
/**
* filter which package should be synced
*/
packageFilter?: IPackageFilterOptions
/**
* version range strategy
* @default 'retain'
*/
versionRangeStrategy?: IUpgradeVersionStrategy
/**
* only check, with package.json files untouched
* validate package whether need to update, don't change package.json file actually
*/
checkOnly?: boolean
/**
* check whether packages' versions are exactly same
*/
exact?: boolean
}/**
* upgrade version strategy
* retain: retain the original version range
*/
export type IUpgradeVersionStrategy = '>' | '~' | '^' | '>=' | '' | 'retain' | IVerTransform/**
* custom version transform
*/
export type IVerTransform = (name: string, newVersion: string, oldVersion: string) => string```
Tips: you may need to reinstall your workspace dependence if anything changed
### syncDeps
sync packages dependencies(e.g. babel, react, typescript, etc) versions at once> also available as command [syncdeps](#syncdeps)
```js
import { syncDeps } from 'lerna-ci'// update all packages that depend `react` and `react-dom` to their latest version(will fetch from npm)
// return all changed package infos(aka all packages that depend on these packageNames and be updated)
const updatedPkgs = await syncDeps({ packageNames: ['react', 'react-dom'] })
// [{name: 'my-package', version: '1.0.1', private: false, location: '/Users/xx/work/monorepo/my-package'}]// as above, but will also update dependence typescript to a fixed version 3.1.0 and parcel to ^2.0.0
const updatedPkgs = await syncDeps({ packageNames: ['react', 'react-dom'], versionMap: { typescript: '=3.1.0', parcel: '2.0.0' } })
// [{name: 'my-package', version: '1.0.1', private: false, location: '/Users/xx/work/monorepo/my-package'}]
```Type Declarations:
```ts
syncDeps(syncOptions: ISyncDepOptions)=> Promiseexport interface ISyncDepOptions {
/**
* package names that should update
* will fetch its version from npm by default
* package name can use asterisk, e.g. @babel/*
*
* @example
* ['duplex-message', '@typescript-eslint/parser', '@babel/*', '*plugin*', 'react*']
*/
packageNames?: string[]
/**
* version map
* prefer use this as version map if provided
* pkgName can be a pattern like @babel/*
* if packageNames also provided, will fetch missing versions
* @example
* {'@babel/*': '7.0.0', 'parcel': '^2.0.0', '@types/react': '~18.0.0'}
*/
versionMap?: IVersionMap
/**
* npm version strategy
* default to 'max-stable'
*/
versionPickStrategy?: IVersionPickStrategy
/**
* version range strategy, use retain by default
*/
versionRangeStrategy?: IVersionRangeStrategy
/** only check, with package.json files untouched */
checkOnly?: boolean
/**
* update version to the exact given version
* set to false only update when existing version range is not satisfied
* @default true
*/
exact?: boolean
}
```Tips: you may need to reinstall your workspaces dependence if anything changed
### fixpack
Make all your package.json files are written in same criterion: sorting fields, validating required fields.
This feature is powered by [fixpack](https://github.com/HenrikJoreteg/fixpack).> also available as command [fixpack](#fixpack)
e.g.
```js
import { fixpack } from 'lerna-ci'const updatedPkgs = await fixpack()
// [{name: 'my-package', version: '1.0.1', private: false, location: '/Users/xx/work/monorepo/my-package'}]```
Type Declarations:
```ts
fixpack (options?: IFixPackOptions) => Promiseexport interface IFixPackOptions {
/**
* which package's should be fixed
*/
packageFilter?: IPackageFilterOptions
/**
* package fix configuration
* check source for default configuration
* see https://github.com/HenrikJoreteg/fixpack#configuration for details
*/
config?: any
}
```### getChanged
List all changed packages since last release, it requires package `lerna` or `@changesets/cli` to be installed.> also available as command [changed](#changed)
e.g.
```js
import { getChanged } from 'lerna-ci'const changedPkgs = await getChanged()
// [{name: 'my-package', version: '1.0.1', private: false, location: '/Users/xx/work/monorepo/my-package'}]```
Type Declarations:
```ts
getChanged() => Promise```
### getRepoNpmClient
get current monorepo preferred npm cliente.g.
```js
import { getRepoNpmClient } from 'lerna-ci'// will return npm for default if not specified
// get `yarn-next` when yarn version >= 2.0 found
getRepoNpmClient().then(client => console.log(client))
// yarn
```
### getVersionFormRegistry
get version from npm registry, you can get the latest version or the max versione.g.
```js
import { getVersionFormRegistry } from 'lerna-ci'getVersionFormRegistry(options: IGetPkgVersionFromRegistryOptions) => Promise
export interface IGetPkgVersionFromRegistryOptions {
/** package name */
pkgName: string
/** strategy: latest or max */
versionStrategy?: IVersionPickStrategy
/**
* specified version, to check for existence
* return itself if found, otherwise return empty string
*/
version?: string
/**
* preferred npm client, auto detect if omitted
*/
npmClient?: 'yarn' | 'yarn-next' | 'npm' | 'pnpm'
}
```
tips: if you want to fetch version from a npm mirror or custom registry, you should specify the mirror in the `.yarnrc` or `.npmrc` file### getVersionsFromRegistry
batch version of `getVersionFormRegistry`, but return an object(key is package name, value is version)Type Declarations:
```ts
getVersionsFromRegistry(options: IGetPkgVersionsFromRegistryOptions) => Promiseexport interface IGetPkgVersionsFromRegistryOptions {
/**
* package names
*/
pkgNames: string[]
/**
* version pick strategy
* max: max package version
* max-stable: max stable package version
* latest: latest release package version
* @default max
*/
versionStrategy?: 'max' | 'latest' | 'max-stable'
/**
* preferred npm client, detect automatically if not provided
*/
npmClient?: 'yarn' | 'yarn-next' | 'npm' | 'pnpm'
}
```### getPackageVersionsFromGit
get monorepo package version map from git tag list(only tags in `packageName@versionNumber` like `[email protected]` will be recognized).
**caution**: this api will run `git fetch origin --prune --tags` to sync tags from server, local un-pushed tags will be removede.g.
```js
import { getPackageVersionsFromGit } from 'lerna-ci'// will return npm for default if not specified
getPackageVersionsFromGit().then(ver => console.log(ver))
// {'duplex-message': '1.1.2', 'simple-electron-ipc': '1.1.2'}
```Type Declarations:
```ts
getPackageVersionsFromGit(type: 'latest' | 'max' = 'latest') => Promise>
```### isLernaAvailable
check whether lerna is installed in current repoe.g.
```js
import { isLernaAvailable } from 'lerna-ci'isLernaAvailable().then(isInstalled => console.log(isInstalled))
// true
```### getGitRoot
get git root path of current repoe.g.
```js
import { getGitRoot } from 'lerna-ci'// return false if not in a git repo
const maxVer = await getGitRoot()
// /User/xx/work/monorepo
```### getProjectRoot
get current project's root path (which contains a `package.json` file)e.g.
```js
import { getProjectRoot } from 'lerna-ci'// throw error if not in a valid frontend project
const maxVer = await getProjectRoot()
// /User/xx/work/monorepo
```### maxVersion
get max version(compare in semver) from a version liste.g.
```js
import { maxVersion } from 'lerna-ci'const maxVer = maxVersion('0.1', '0.0.1', '1.0.0-alpha.1', '1.0.0')
// 1.0.0
```### pickOne
pick a value from a list with a custom compare methode.g.
```js
import { pickOne } from 'lerna-ci'const picked = pickOne([{name: 'Lisa', age: 10}, {name: 'Janie', age: 12}, {name: 'Marry', age: 9}], (a, b) => a.age - b.age)
// {name: 'Janie', age: 12}
```Type Declarations:
```ts
pickOne(list: V[], compare: ICompare) => V | undefined// return `a` if result >= 0, or return `b`
type ICompare = ((a: V, b: V) => -1 | 0 | 1
```## Configuration file
You may also add config for these commands via following ways(powered by [cosmiconfig](https://github.com/davidtheclark/cosmiconfig)) so that you don't need to specify the arguments:
* add `lerna-ci` field to `package.json` in the root of the project
* add `.lerna-circ` file in the root of the project with json or yaml format
* add `.lerna-circ.json`, `.lerna-circ.yaml`, `.lerna-circ.yml` or `.lerna-circ.cjs` file in the root of the project
* add `lerna-ci.config.js` or `lerna-ci.config.cjs` file in the root of the projectall these configurations should return an object with the following properties:
* `synclocal`: same as the params of [syncPackageVersions](#syncpackageversions)
* `syncremote`: same as the params of [syncPackageDependenceVersion](#syncpackagedependenceversion)
* `fixpack`: same as the params of [fixpack](#fixpack-api)## Breaking changes
If you are updating from `0.0.x`, you should be careful about following changes:1. default configuration for `fixpack` has been changed, you may restore the former behavior by setting `fixpack.config` to [old configuration](https://github.com/oe/lerna-ci/blob/legacy/src/fixpack/config.ts) in [configuration file](#configurationfile)
2. if you are using APIs, most useful APIs are renamed for better understanding, but no feature is removed, you may read docs above to upgrade