TL;DR - Mani is a many-repo tool that helps you manage multiple repositories. It's useful when you are working with microservices, multi-project systems, or just a bunch of personal repositories and want a central place for pulling all repositories and running commands over them.
In mani, you specify repositories and commands in a config file and then run the commands over all or a subset of the projects.
Don't worry, this post isn't going to be about the old age debate of whether you should be using a mono- or a many-repo setup. I think there's a place for both, and the two approaches have their pros and cons.
Anyway, even if you're using a mono-repo in your current workplace, you're probably using a many-repo setup for your projects (work, personal projects, etc.), so you still might find Mani useful (or some of the alternatives).
Mani came about because I needed a CLI tool to manage multiple repositories, both at work and for my projects. The premise is, you have a bunch of repositories and want the following:
- a central place for your repositories, containing name, URL, and a small description of the repository
- ability to clone all repositories in 1 command
- ability to run ad-hoc and custom commands (perhaps
git status
to see working tree status) on 1, a subset, or all of the repositories - ability to get an overview of 1, a subset, or all of the repositories and commands
Mani also standardizes one of the recurring patterns that I've seen in the workplace: on your first day, you're given access to an organization on Github, and perhaps if you're lucky, there's an outdated bash script which pulls some of the repositories you're supposed to work on. Other times, you're simply given a README document with links to all the projects you're supposed to visit manually and clone.
Usage
Let's install Mani, binaries are available on Github release page, or you can install it via cURL (only Linux & MacOS):
curl -sfL https://raw.githubusercontent.com/alajmo/mani/main/install.sh | sh
There's also additional install methods in manicli.com.
Now, let's say you have a bunch git repositories:
$ tree -L 2 . ├── frontend │ ├── dashgrid │ └── pinto └── template-generator
We'll start by initializing Mani in this directory:
$ mani init Initialized mani repository in /home/samir/tmp/init - Created mani.yaml - Created .gitignore Following projects were added to mani.yaml Project | Path --------------------+-------------------- init | . dashgrid | frontend/dashgrid pinto | frontend/pinto template-generator | template-generator
Let's see the content of the two files generated:
$ cat mani.yaml projects: init: path: . dashgrid: path: frontend/dashgrid url: https://github.com/alajmo/dashgrid.git pinto: path: frontend/pinto url: https://github.com/alajmo/pinto.git template-generator: url: https://github.com/alajmo/template-generator.git tasks: hello: desc: Print Hello World cmd: echo "Hello World" $ cat .gitignore # mani # template-generator frontend/pinto frontend/dashgrid # mani #
the mani init
command created a mani.yaml
file that contains our repositories as well as an example task named hello-world
and a .gitignore
file that contains all the projects. This is because when we initialize this directory as a git repository (which is recommended, as other users can simply clone this repository and then run mani sync
to clone all repositories), we want to prevent the directories to be added to our Mani repository.
Mani has a bunch of different sub-commands that helps us view and manage our repositories:
# Open mani.yaml in your preferred editor $ mani edit # List projects $ mani list projects Project ------------------- init dashgrid pinto template-generator # List repositories in a tree-like format $ mani list projects --tree ┌─ frontend │ ├─ dashgrid │ └─ pinto └─ template-generator # Describe all tasks $ mani describe tasks Name: hello Description: Print Hello World Theme: default Target: All: false Cwd: false Projects: Paths: Tags: Spec: Output: text Parallel: false IgnoreError: false OmitEmpty: false Cmd: echo "Hello World"
Now, let's adds some tags and descriptions to our projects, and some new tasks:
projects: example: path: . desc: A mani example pinto: path: frontend/pinto url: https://github.com/alajmo/pinto.git desc: A vim theme editor tags: [frontend, node] template-generator: url: https://github.com/alajmo/template-generator.git desc: A simple bash script used to manage boilerplates tags: [cli, bash] env: branch: master themes: custom: table: options: draw_border: true separate_columns: true separate_header: true separate_rows: true tasks: git-status: desc: show working tree status cmd: git status git-last-commit-msg: desc: show last commit cmd: git log -1 --pretty=%B git-last-commit-date: desc: show last commit date cmd: | git log -1 --format="%cd (%cr)" -n 1 --date=format:"%d %b %y" \ | sed 's/ //' git-branch: desc: show current git branch cmd: git rev-parse --abbrev-ref HEAD npm-install: desc: run npm install in node repos target: tags: [node] cmd: npm install git-overview: desc: show branch, local and remote diffs, last commit and date theme: custom commands: - task: git-branch - task: git-last-commit-msg - task: git-last-commit-date
Run git-status
task and target projects with the tag bash
:
$ mani run git-status --tags bash TASK [git-status: show working tree status] ************************** template-generator | On branch master template-generator | Your branch is up to date with 'origin/master'. template-generator | template-generator | nothing to commit, working tree clean Name: git-status Description: Show git status Shell: sh -c Env: Command: git status
Run task git-status
for repositories under the frontend
directory:
TASK [git-status: show working tree status] ************* pinto | On branch main pinto | Your branch is up to date with 'origin/main'. pinto | pinto | nothing to commit, working tree clean
Run another task that has multiple commands and display the output in a table:
$ mani run git-overview -t bash -d frontend/ -o table +--------------------+------------+-------------------------------------------+-----------------------------------+ | Project | Git-Branch | Git-Last-Commit-Msg | Git-Last-Commit-Date | +--------------------+------------+-------------------------------------------+-----------------------------------+ | pinto | main | Update readme | 22 Mar 22 (6 weeks ago) | | | | | | +--------------------+------------+-------------------------------------------+-----------------------------------+ | template-generator | master | Edit command should work without argument | 24 Jan 20 (2 years, 3 months ago) | | | | | | +--------------------+------------+-------------------------------------------+-----------------------------------+
Now if we want to execute an ad-hoc command, for instance, count the number of files in all projects, we can use the mani exec
sub-command:
$ mani exec --all --output table --parallel 'find . -type f | wc -l' Project | Output --------------------+-------- example | 486 pinto | 361 template-generator | 42
Conclusion
I hope you find this intro to Mani useful, and if you want to learn more, head to github.com/alajmovic/mani.
Alternatives
Mani isn't the first of its kind, check out the following alternatives!
Top comments (0)