• Stars
    star
    2,026
  • Rank 22,851 (Top 0.5 %)
  • Language
    JavaScript
  • License
    MIT License
  • Created almost 8 years ago
  • Updated 4 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

tool for turning many repos into a meta repo. why choose many repos or a monolithic repo, when you can have both with a meta repo?

Build Status npm version Latest Release Date

Dependency Status Dev Dependency Status

NPM downloads Contributors Gitter

meta

meta is a tool for managing multi-project systems and libraries. It answers the conundrum of choosing between a mono repo or many repos by saying "both", with a meta repo!

meta is powered by plugins that wrap common commands, letting you execute them against some or all of the repos in your solution at once. meta is built on loop, and as such inherits loops ability to easily target a particular set of directories for executing a common command (eg meta git status --include-only dir1,dir2. See loop for more available options).

meta is packaged with a few of these core plugins by default: https://github.com/mateodelnorte/meta/blob/master/package.json#L63-L66

Why meta?

  • clone a many-project architecture in one line
  • give every engineer on your team the same project setup, regardless of where it's cloned
  • npm / yarn install against all your projects at once
  • execute arbitrary commands against many repos to manage your projects
  • super simple plugin architecture using commander.js
  • easily wrap commands for working with any platform, not just Node!
  • meta repo keeps code in per project repos, benefiting deployment and reuse
  • use the same tools you always use. no strange side effects of git submodules or subtree
  • give different teams different slices of your architecture, with multiple metarepos!
  • use meta project migrate to migrate mono-repos to a meta repo consisting of many repos

getting started

installing

npm i -g meta will install a meta command on your system.

initializing a new meta project

To create a new meta project:

  1. create a new directory for your meta project mkdir my-meta-repo
  2. initialize a new git repository in your new dir: cd my-meta-repo && git init
  3. initialize your new repository as a meta repo: meta init

meta will have created a .meta file to hold references to any child repositories you add.

  1. (a) to create a new project, use meta project create [folder] [repo url] (b) to import an existing project, use meta project import [folder] [repo url]

for each project added, meta will update your .gitignore file and the .meta file with references to the new child repo

asciicast

You can now perform commands against all of the repositories that make up your meta repository by using meta exec.

For example, to list all of the files in each project:

meta exec "ls -la"

cloning an existing meta project

To clone an existing meta repo, rather than git clone like you are used to, simply execute meta git clone [meta repo url] instead. meta will clone your meta repo and all child repositories at once.

meta git clone [email protected]:mateodelnorte/meta.git

asciicast

Getting meta project updates

If you are working on a team and another members adds a project to the meta repository, to get the project, run meta git update.

# get new .meta file
git pull origin master

# clone missing projects
meta git update

working with meta

meta exec

The most basic way to interact with meta repositories is to use the meta exec command. This will let you run any command against the projects that make up your meta repo.

meta exec "git checkout master"

In many cases, that is enough. There are also special cases where the functionality provided by the initial tool wasn't quite meta-y enough, and for those, there are plugins.

Even meta-exec, itself is a plugin, but it comes with meta by default.

plugins

All meta functionality is contributed by plugins - node modules that begin with meta- and are either installed globally or in your meta repo's node_modules directory. We recommend you install them as devDependencies in your meta repo's package.json. Plugins add additional sub commands to meta, and can leverage loop or meta-loop to easily execute a common command against your meta repo and all child repos.

Here's how easy it is to install meta-npm as a plugin, and gain the ability to meta npm install all your repos at once:

asciicast

Going deeper - meta plugins are able to wrap common commands for a friendly user experience, such as meta npm install. They are also able to extend the native tool's capabilities. For example, git update is not a git command, but meta git update will clone any repos that exist in your .meta file that aren't cloned locally - a problem that doesn't exist with a single git repo.

You shouldn't have much new syntax to memorize for some crazy new utilities nobody knows about. For instance, if you want to check the git status of all your repositories at once, you can just type meta git status:

asciicast

In the case a command has not been wrapped with a plugin, just use meta exec instead.

Available Plugins

Third-party Plugins

Available Templates

Usage Scenarios

Product Development Team

Your product consists of multiple applications and services. As the project lead, you can use meta to group together the projects so every developer is able to meta git clone a single project to get everything they need for development.

Furthermore, you could add a docker-compose file at this root level to run all of the services and applications:

version: '3.7'

services:

  app1:
    image: app1
    build:
      context: projects/app1
    ports:
    - 1234:1234
    env_file: projects/app1/.env

  app2:
    image: app2
    build:
      context: projects/app2
    ports:
    - 1234:1234
    env_file: projects/app2/.env

  service1:
    image: service1
    build:
      context: projects/service1
    ports:
    - 1236:1234
    env_file: projects/service1/.env

  service1:
    image: service1
    build:
      context: src/service2
    ports:
    - 1237:1234
    env_file: src/service2/.env

The meta repo is a good place for things like this, including scripts and a Makefile that are responsible for meta things, like gettings secrets for each project, like .env files for local development.

Take this example Makefile at the root of a meta repo:

onboard:
	meta exec "make setup"

setup: install-tools get-secrets

install-tools:
  echo "add install scripts here"

get-secrets:
	echo "get secrets via SOPS/Vault/however and cp into appropriate projects"

The command make onboard would start the setup task in the root and all of the child directories.

Each project can then contain a Makefile like so:

setup:
  npm ci
  npm run dev

To get new projects up and running you can give them the instructions:

meta git clone [email protected]/yourorg/metaproject
cd metaproject
make onboard

And they would have a fully running dev environment.

Developing a Library with many modules

Meta itself is developed with meta. This way you have a monorepo like feel while developing, but with individual components with their own release cycles.

It takes advantage of npm link, just like tools like Lerna do.

Using meta npm link && meta npm link --all enables a good development experience by creating symlinks so each project uses the development version of any other project in the meta repo:

# install meta
npm i -g meta

# clone and enter the meta repo
meta git clone [email protected]:mateodelnorte/meta.git
cd ./meta

# install plugins
npm install

# run install for all child repos
meta npm install

# create symlinks to/from all child repos
meta npm link --all

# link meta itself globally
npm link

There is admittedly now the problem of updating each repository to use the newly published versions of each other. For this, we recommend using a tool like Renovate, Dependabot, or Greenkeeper.

See this article for an example: Bring In The Bots, And Let Them Maintain Our Code!

Migrating a Monorepo to many repos

'meta project migrate' helps you move from a monorepo to a meta repo by moving directories from your existing repo into separate child repos, with git history intact. These are then referenced in your '.meta' file and cloned, making the operation transparent to your codebase.

For example, given the following monorepo structure:

- monorepo-base
  - project-a
  - project-b
  - project-c

Create git repos for project-a, project-b, and project-c, then run:

cd monorepo-base
meta init
meta project migrate project-a [email protected]/yourorg/project-a
meta project migrate project-b [email protected]/yourorg/project-b
meta project migrate project-c [email protected]/yourorg/project-c

This will keep the git history of each subproject in tact, using some git magic:

How it works

  1. Migrate will first create a copy of your project in a temporary directory and replace the remote 'origin' with the provided
  2. It will split the history from and push to the provided : https://help.github.com/en/articles/splitting-a-subfolder-out-into-a-new-repository
  3. Next is removed from your monorepo, and then cloned back into the same location.

In the eyes of the monorepo, the only thing that has changed is the .meta file, however, now also has it's own distinct history.

Migration Phase

If you need the monorepos structure to stay in tact for any extended duration, such as supporting legacy CI systems, you can stop here.

While in this 'migration' phase, you need to commit to the child directory's git history as well as the monorepo's git history. These commits can literally be made twice by cd-ing around or both can be made at once using 'meta git commit'.

Finishing the Migration

When the monorepo no longer needs to be maintained you can simply add the migrated project to your '.gitignore'.

This will cause changes to only be tracked in the child repo, rather than both, such as during the migration phase.

FAQs

How can I create a group of repositories, to, for example, run npm install on only node projects?

There are two ways to do this:

  1. Meta repos can contain other meta repos. Make smaller groups of repos that only contain projects with commands that will be executed together. This is commonly not an option such as in migrating legacy monorepos.
  2. Use a Makefile to declare the groups, and use make commands:
NODE_APPS=app1,service1,app2,service2

node-install:
	meta npm install --include-only $(NODE_APPS)

Then you can run make node-install

Can I run things in parallel?

Yes.

meta exec "npm ci" --parallel

Output is even grouped nicely together for you at the end! :)

How to escape expressions

If you try to evaluate an expression run in meta exec, you'll notice that the expression is evaluated before being run in the target projects.

➜  meta exec "echo `pwd`" --include-only=plugins/meta-loop

plugins/meta-loop:
/Users/patrickleet/dev/mateodelnorte/meta
plugins/meta-loop ✓

In these cases, simply escape the expression so that it is not executed until being run against each project rather than ahead of time:

➜  meta exec "echo \`pwd\`" --include-only=plugins/meta-loop

plugins/meta-loop:
/Users/patrickleet/dev/mateodelnorte/meta/plugins/meta-loop
plugins/meta-loop ✓

Or...

➜  meta exec "echo \$(pwd)" --include-only=plugins/meta-loop 

plugins/meta-loop:
/Users/patrickleet/dev/mateodelnorte/meta/plugins/meta-loop
plugins/meta-loop ✓

Developing meta locally

The best way to get started is to do the following:

npm i -g meta
meta git clone [email protected]:mateodelnorte/meta.git
cd ./meta
npm install
meta npm install
meta npm link --all
npm link

This will clone the meta project, meta, enter the directory, and then use meta to perform npm install, npm link --all in each directory listed in projects of the .meta JSON configuration file, and link meta itself to be used as a global command.

You can then write your command and test using ./bin/meta git gh [subcommand].

You can run the above as a single command:

meta git clone [email protected]:mateodelnorte/meta.git && cd ./meta && npm i && meta npm install && meta npm link --all && npm link

Yarn lovers can do the same:

npm i -g meta
meta git clone [email protected]:mateodelnorte/meta.git
cd ./meta
yarn
meta yarn install
meta yarn link --all
yarn link

Or

meta git clone [email protected]:mateodelnorte/meta.git && cd ./meta && yarn && meta yarn install && meta yarn link --all && yarn link

See discussion here for more details

More resources

More Repositories

1

servicebus

Simple service bus for sending events between processes using amqp.
JavaScript
420
star
2

sourced

Tiny framework for building models with the event sourcing pattern (events and snapshots).
JavaScript
284
star
3

loop

loop through commands in fun and amazing ways!
JavaScript
126
star
4

forecast.io

wrapper for the forecast.io API
JavaScript
117
star
5

sourced-repo-mongo

mongo data store and repository for sourced-style event sourcing models
JavaScript
55
star
6

coinbase

wrapper for the coinbase bitcoin wallet & exchange API
JavaScript
48
star
7

meta-git

git plugin for meta
JavaScript
23
star
8

servicebus-retry

JavaScript
18
star
9

mockrequire

Simple module for mocking required dependencies. Works with any testing suite.
JavaScript
17
star
10

node-paypal-masspayments

Node PayPal Mass Payment NVM
JavaScript
14
star
11

servicebus-register-handlers

JavaScript
11
star
12

microsvc

tiny reusable framework for building microservices with messaging and rest
JavaScript
11
star
13

servicebus-trace

servicebus middleware to publish message receipt information to a central store, for message tracking and tracing purposes.
JavaScript
10
star
14

filecoin-lotus-docker

Dockerfile
9
star
15

meta-npm

npm plugin for meta
JavaScript
8
star
16

meta-yarn

yarn plugin for meta
JavaScript
6
star
17

node_hands_on-unit_testing

6
star
18

meta-project

JavaScript
6
star
19

july3rd

6
star
20

SeattleNodejs.SimpleServerWHerokuDeploy

JavaScript
5
star
21

amqp-match

transforms amqp routing keys to regular expressions for more convenient runtime matching
JavaScript
4
star
22

selenium-webdriver-slug

Starter project for getting rolling with Selenium Webdriver and PhantomJS
JavaScript
4
star
23

meta-gh

gh command plugin for meta
JavaScript
3
star
24

cconfig

JavaScript
3
star
25

kill-all-node-on-windows

JavaScript
3
star
26

meta-init

plugin for initializing new meta repositories
JavaScript
2
star
27

sample-service

JavaScript
2
star
28

servicebus-message-domain

JavaScript
2
star
29

gitslave

fork of gitslave from http://gitslave.sourceforge.net/ modified to work with current versions of git
Perl
2
star
30

meta-exec

exec plugin for meta
JavaScript
2
star
31

llog

JavaScript
2
star
32

find-file-recursively-up

returns the path at which a provided filename exists, checking the current directory and any parent folders recursively up.
JavaScript
2
star
33

pidler

simple module to create process pids
JavaScript
1
star
34

meta-loop

helper function to loop-exec in a meta repository and all child repositories
JavaScript
1
star
35

sample-site

CSS
1
star
36

microsvc-slave

JavaScript
1
star
37

objectify-folder

return all non index.js modules in a folder as a single object
JavaScript
1
star
38

thenodejsmeetup.com

JavaScript
1
star
39

servicebus-rabbitmq

rabbitmq bus provider for servicebus
JavaScript
1
star
40

get-meta-file

JavaScript
1
star
41

brb

1
star
42

symlink-meta-dependencies

symlink all of a project's dependencies which appear in the project's .meta file
JavaScript
1
star
43

sourced-queued-repo

JavaScript
1
star
44

google-cloud-run

google cloud run example project with build and deployment helpers
Makefile
1
star
45

find-module-bin

scan known node_modules directories to find installation directory of a particular bin file
JavaScript
1
star
46

microsvc-example

JavaScript
1
star