dashkite / tempo

Polyrepo project and package management
Other
1 stars 0 forks source link

Tempo

Metarepo project and package management.

Hippocratic License HL3-CORE

You’ve heard of monorepos? A metarepo (also referred to as a polyrepo) is similar except that it doesn’t require everything to be in a single repo. (Hat tip to the creators of Meta for both the term metarepo and for influencing Tempo.) Instead, you create a repo that references a collection of existing repos and perform operations against them together. Basically, it’s the best of both worlds: the benefits of a monorepo without the drawbacks.

Installation

npm i -g @dashkite/tempo

Usage

Usage: tempo [options] [command]

Options:
  -V, --version                            output the version number
  -h, --help                               display help for command

Commands:
  add|a [options] <repo>                   add a project to a metarepo
  remove|rm [options] <repo>               remove a project from a metarepo
  clone [options] <metarepo>               clone a metarepo
  sync [options]                           sync a metarepo with remote
  import [options] <path>                  import respositories from a list
  exec [options] <command> [arguments...]  run a command across repos
  run [options] <script> [arguments...]    run a saved script
  tag [options] <tags...>                  add tags to a repository
  untag [options] <tags...>                remove tags from a repository
  help [command]                           display help for command

Create A Metarepo

You can create a new metarepo by simply creating a new repo.

Add A Repo

To add another repo to your metarepo, use the add subcommand with a GitHub repo path:

tempo add dashkite/url-codex

Remove A Repo

You can similarly remove a repo with remove.

Importing Repos

You can add a bunch of repos all at once with import:

tempo import repos.yaml

The input file should contain a YAML formatted array of GitHub repo paths.

Cloning A Metarepo

To work from an existing metarepo, use clone with the GitHub repo path:

tempo clone vedic-dolphin

This will clone the metarepo and all the metarepos it contains.

Synchronizing Metarepos

You can sync meta repos—which is equivalent to pulling and adding/removing repos—using the sync command.

Running Commands

You can run arbitrary commands across all the repos in a metarepo with exec:

tempo exec git pull

You can also define scripts for more complex commands and run them using the run command:

tempo run pull

Both run and exec allow you to use files to target a subset of repos with the targets option:

tempo run --include core.yaml build

Targeting files should be YAML arrays with only the repo names (not the relative path).

You can also use tags to target repositories:

tempo run --tags module publish

Use the tag and untag commands to add and remove tags from repos. You can also target individual repositories with the --repos option or exclude them with --exclude which works like --include.

Defining Run Scripts

Run scripts are defined in scripts.yaml file within the .tempo directory. Positional arguments can be applied using $ and index of the argument. You can reference all the arguments together with $@.

For example, to define a commit command that takes a commit message, you might have a tempo.yaml file that looks something like this:

commit: git add -A . && git commit -m '$0'

Scenarios

Targeting Repos

You can use jq and yq to query your repos and target run or exec commands.

For example, to update a specific dependency, we want to target repos that have that dependency. The most direct way to do that is to use exec and the -e option of jq to chain the commands with &&. However, this gets messy because of the levels of quoting involved. Instead, we would add a script, which also allows us to make it more general:

scripts:
  update: jq -e '.dependencies["$0"]' package.json && pnpm add $0@latest

We can thus run:

tempo run update @dashkite/url-codex

However, sometimes the queries are more complex, in which case we can use jq or yq to build a list that we can pass to run (or exec) instead. Of course, we can use any tool to build our list, or even simply compile it manually.

Roadmap