DEV Community

Cover image for mani, a CLI Tool to Manage Multiple Repositories
Samir Alajmovic
Samir Alajmovic

Posted on

mani, a CLI Tool to Manage Multiple Repositories

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:

  1. a central place for your repositories, containing name, URL, and a small description of the repository
  2. ability to clone all repositories in 1 command
  3. 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
  4. 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 
Enter fullscreen mode Exit fullscreen mode

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 
Enter fullscreen mode Exit fullscreen mode

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 
Enter fullscreen mode Exit fullscreen mode

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 # 
Enter fullscreen mode Exit fullscreen mode

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" 
Enter fullscreen mode Exit fullscreen mode

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 
Enter fullscreen mode Exit fullscreen mode

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 
Enter fullscreen mode Exit fullscreen mode

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 
Enter fullscreen mode Exit fullscreen mode

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) | | | | | | +--------------------+------------+-------------------------------------------+-----------------------------------+ 
Enter fullscreen mode Exit fullscreen mode

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 
Enter fullscreen mode Exit fullscreen mode

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)