One of the biggest problems with keeping separate repositories is that smaller changes, such as a dependency update or a change in a file like the pull request template, may require a lot of tedious manual labor. However, this should not be the case, and we should be able to automate these tasks, even if they are spread out over multiple repositories. This article will explain how to handle changes over multiple repositories, like all repositories in a GitHub organisation.
Change different repos with one command
The solution to the problem of making similar changes over many repositories is multi-gitter. It allows you to make changes by running a script or program in the context of all repositories in your GitHub/GitLab organization or in a list of repositories. For all repositories where a change was made, a pull request will be created. All pull requests can then be verified to be correct by a Continuous integration pipeline and then potentially merged with another part of the tool.
Script once, run everywhere
The script can do any type of change. As long as you can script something for one repository, you can do the change for any number of repositories. For example, you can replace apples with oranges using bash:
Your changes, your tooling
Multi-gitter is agnostic to the tool you use to make these changes. A simple bash script might be enough for some of the times. But if you prefer to modify your file with a Node.js or Python script, that works excellently too.
Example 1: Replace the pull request template file (if it exists)
#!/bin/bash
# Absolute path to the file that should replace the one in the repo
REPLACE_FILE=~/test/pull_request_template.md
# Relative to any repo's root
FILE=.github/pull_request_template.md
# Don't replace this file if it does not already exist in the repo
if [ ! -f "$FILE" ]; then
exit 1
fi
cp $REPLACE_FILE $FILE
Run the script with multi-gitter:
multi-gitter run ./replace.sh -O my-org -m "update pr-template" -B update-pr-template
Example 2: Replace text in multiple repositories with Node.js
const { readFile, writeFile } = require("fs").promises;
async function replace() {
let data = await readFile("./README.md", "utf8");
data = data.replace("apple", "orange");
await writeFile("./README.md", data, "utf8");
}
replace();
Run the script with multi-gitter:
multi-gitter run "node $PWD/script.js" -O my-org -m "replace apples with oranges" -B fruit-replace
This will find and replace all occurrences in the GitHub organisation.
Example 3: Update npm dependency in an entire organization
It's highly recommended to use an updated dependency management tool such as Renovate or Dependabot. But sometimes it is not possible, or you need to update a specific dependency right now, across a lot of repositories. This script will allow you to do just that.
#!/bin/bash
### Change these values ###
PACKAGE=webpack
VERSION=4.43.0
if [ ! -f "package.json" ]; then
echo "package.json does not exist"
exit 1
fi
# Check if the package already exist (without having to install all packages first), abort if it does not
current_version=`jq ".dependencies[\"$PACKAGE\"]" package.json`
if [ "$current_version" == "null" ];
then
echo "Package \"$PACKAGE\" does not exist"
exit 2
fi
npm install --save $PACKAGE@$VERSION
Run the script with multi-gitter:
multi-gitter run "node $PWD/script.js" -O my-org -m "replace apples with oranges" -B fruit-replace
Many ways to run
Since any type of script can be made to modify the files in a cloned repository, multi-gitter also accommodates many ways of running that code. It allows you to run the script in any collection of repositories, such as everything in an organization, by specifying a list of repositories, all repositories owned by a user, or a combination of these. If you want to speed up the process, you can make the run parallel, or you might want to specify reviewers of the created pull requests if needed.
A very useful extra option is the --interactive
flag. It allows you to preview the changes before they are pushed. This way, you can ensure that the script is doing the right changes if you are ever unsure.
Comments (0)