Skip to content

CLI tool for scaffolding a TypeScript monorepo, powered with scripts and generators

License

Notifications You must be signed in to change notification settings

michaelyali/mrepo

Repository files navigation

MREPO

Awesome TypeScript monorepository swiss knife

Built with πŸ’œ by @MichaelYali
🌟 πŸ‘€ ⚑ πŸ’₯

Mrepo makes it easy to create new TypeScript packages monorepository, generate new packages, build, test, link/unlink to try them locally, publish either to GitHub or NPM package registry.

Features

Mrepo demo

  • πŸš€ Generate TypeScript monorepository
  • ✈️ Package generator with references between other packages included, and sub-generators support
  • 🚦 Build, clean, link/unlink, release packages commnads
  • 🍦 Jest testing ready (unit, e2e, coverage commands included)
  • 🍭 Lint and format (eslint & prettier)
  • 🍬 Husky hooks ready (pre-commit hook included)
  • πŸ‰ Conventional commits and changelogs
  • 🍍 GitHub actions included (tests & release)
  • β˜• Issues and Pull Request templates

Install

$ npm i @zmotivat0r/mrepo -g

Commands

mrepo new

Generate new TypeScript monorepository.

Info:

mrepo new|n [options] <name>

Arguments:
  name               Monorepo name

Options:
  -y, --yes          Skip prompts and use default options (default: false)
  --dry-run          Dry run (default: false)
  --skip-scripts     Skip post-generator scripts (default: false)
  --skip-git         Skip git init (default: false)
  --skip-git-commit  Skip git initial commit (default: false)
  --skip-install     Skip dependencies installation (default: false)
  -h, --help         display info

Usage:

$ mrepo new awesome-monorepo
$ mrepo new awesome-monorepo --yes --skip-git

mrepo generate

Generate new package, update root tsconfig.json, add references to other packages, if needed.

Info:

mrepo generate|g [options] [package]

Arguments:
  package                    Package name, optional

Options:
  -y, --yes                  Skip prompts and use default options (default: false)
  --dry-run                  Dry run (default: false)
  --depends-on <pacakges>    Depends on scope package(s), comma-separated
  --dependent-of <pacakges>  Dependent of scope package(s), comma-separated
  -h, --help                 display info

Usage:

$ mrepo generate
$ mrepo generate cool-new-package --yes

mrepo build

Build all packages or a specified one.

Info:

mrepo build|b [options] [package]

Arguments:
  package     Package name, optional

Options:
  -h, --help  display info

Usage:

$ mrepo build
$ mrepo build packageName

mrepo clean

Remove lib folder in all packages ot a specified one.

Info:

mrepo clean|c [options] [package]

Arguments:
  package     Package name, optional

Options:
  -h, --help  display info

Usage:

$ mrepo clean
$ mrepo clean packageName

mrepo test

Run tests using Jest for all packages or a specified one.

Info:

mrepo test|t [options] [package]

Arguments:
  package               Package name, optional

Options:
  -f, --folder <value>  Tests folder (default: "packages")
  -s, --suite <value>   Suite path to run
  -c, --config <value>  Jest config file (default: "jest.config.js")
  --coverage            Run with coverage (default: false)
  --verbose             Run verbose (default: false)
  -h, --help            display info

Usage:

$ mrepo test
$ mrepo test packageName --verbose

mrepo link

Exec npm link for all packages or a specified one.

Info:

mrepo link|l [options] [package]

Arguments:
  package     Package name, optional

Options:
  --build     Build before linking (default: false)
  -h, --help  display info

Usage:

$ mrepo link
$ mrepo link packageName --build

mrepo unlink

Exec npm unlink for all packages or a specified one.

Info:

mrepo unlink|u [options] [package]

Arguments:
  package     Package name, optional

Options:
  -h, --help  display info

Usage:

$ mrepo unlink
$ mrepo unlink packageName

mrepo digest

Install or create symlinks from mrepos to local target repositories.

Info:

mrepo digest|d [options] [from] [to]

Arguments:
  from                      Mrepo names from the digest config file, comma-separated (optional)
  to                        Target names from the digest config file, comma-separated (optional)

Options:
  -c, --config <value>      Config file name or path (optional) (default: "mrepo-digest.json")
  -m, --mode <value>        Digest mode. One of ln, install, copy. (optional)
  -p, --packages <value>    Mrepo packages to digest, comma-separated (optional)
  --withVersion <value>     Install packages with version (optional)
  --withLocalVersions       Install packages with their local versions (optional) (default: false)
  --quiet                   Run quietly (optional) (default: false)
  -h, --help  display info

Usage:

  1. Create a config json (default name "mrepo-digest.json") and place it somewhere in your system.

Example config:

{
  "paths": [
    {
      "name": "first",
      "path": "/some/path/to/first"
    },
    {
      "name": "second",
      "path": "/some/path/to/second"
    },
    {
      "name": "third",
      "path": "/some/path/to/third"
    }
  ],
  "mrepos": [
    {
      "name": "first",
      "defaultPackages": ["one-package", "another-cool-package"],
      "targets": [
        {
          "name": "second",
          "packages": ["awesome-package"]
        },
        {
          "name": "third"
        }
      ]
    },
    {
      "name": "second",
      "targets": [
        {
          "name": "third",
          "packages": ["from-second-package"],
          "noDefaultPackages": true,
          "mode": "install"
        }
      ]
    }
  ],
  "targets": [
    {
      "name": "second",
      "installExec": "yarn add -W"
    },
    {
      "name": "third",
      "installExec": "npm i"
    }
  ],
  "mode": "ln"
}

In this example first and second are both mrepo generated monorepositories, where second depends on first (e.g. one has only public packages, another has only private packages under the same npm scope) and the third is just another node project wich depends on packages from both those mrepos.

mrepos.defaultPackages and mrepos.targets.packages are merged (mrepos.targets.noDefaultPackages prevents using default packages) . Can be overridden by using --packages option.

mode and mrepos.targets.mode have two values: ln - create symbolic links for packages from mrepo, install - install packages, copy - copy lib folders to targets. Can be overridden by using --mode option.

$ mrepo digest
$ mrepo digest -c another-config.json first third --mode install

mrepo release

Start release new version: bump package(s) version, generate changelog, git commit and push.

Info:

mrepo release|r [options] <semver>

Arguments:
  semver              Package version semver type. One of: patch, minor, major,
                        prepatch, preminor, premajor, prerelease, select

Options:
  --no-git-push       Skip git commit and push
  --no-changelog      Skip changelog generation
  --preid <value>     Prerelease identifier (default: "alpha")
  --dist-tag <value>  Dist tag when Lerna version is "independent" (default: "latest")
  --force-publish     Force packages release (default: false)
  -h, --help          display info

Usage:

$ mrepo release minor
$ mrepo release premajor --preid beta

release flow

Mrepo comes with the release GitHub action wich supports independent and common packages versioning. Here is the default release flow:

  1. A developer creates a branch with the name that starts with release (e.g. release/my-new-package).
  2. Runs mrepo release <semver> [options].
  3. Creates a Pull Request.
  4. When merged, the release GitHub action executes the following:
    • Install, build, test
    • Checks latest git tag, then creates a new tag
      • if versioning is independent then a tag will be incremented from the previous one (semver minor part)
      • if versioning is common then a tag will be created from common version
    • Creates GitHub release with newly created tag
    • Publishes packages to the registry
    • Notifies in the comment of a Pull Request when packages are being published

It's worth mentioning that all of the default commands, along with some others are already added to the package.json scripts section.

Support

Any support is welcome. At least you can give it a star ⭐

License

MIT