At Tapsi, we have multiple frontend teams (or "tribes") working on different parts of our products. One thing we all have in common? We deal with merge requests that need to follow some basic rules, like:
- Does a new feature has tests?
- Did you update the changelog?
- Is this MR too big?
- Did you forget to assign reviewers?
We've been using Danger JS to automate these
checks in our CI pipelines. But after a while, our dangerfile.ts started to
look... messy. Different teams had different rules, the logic was scattered, and
nobody really wanted to touch that file. Sound familiar?
Danger JS is great for small projects or teams with simple needs. But in a company with multiple teams, each with their own standards, it quickly becomes a maintenance nightmare.
We needed something:
- Modular
- Easy to extend
- Flexible enough that each team could plug in their own rules
We open-sourced it here if you want to check it out: 👉 https://github.com/Tap30/danger
Basically, we wrapped Danger JS with a plugin system — inspired by how tools like ESLint or Vite let you extend functionality cleanly.
Instead of dumping everything in dangerfile.ts, you write self-contained
plugins:
const mergeRequestSizePlugin = createPlugin<{ size?: number }>(
(client, options) => {
const threshold = options?.size || 200;
const filesChanged = [
...client.git.modified_files,
...client.git.created_files,
];
if (filesChanged.length > threshold) {
client.warn(
`Whoa, that's a big MR: ${filesChanged.length} files changed!`,
);
}
},
);
Then in your dangerfile.ts:
import danger from "danger";
import DangerClient from "@tapsioss/danger";
const dangerClient = new DangerClient(danger);
dangerClient
.use(mergeRequestSizePlugin, { size: 100 })
.use(yourOtherPlugin)
.use(yetAnotherPlugin);
dangerClient.analyze();
Simple, clean, and easy to read.
Each tribe could write and maintain their own plugins without worrying about breaking someone else's checks. (Shared plugins are published as packages in organization's registery.)
Instead of scrolling through hundreds of lines of conditionals, you just look at the plugin list to know what's being checked.
New devs didn't have to understand "the giant Dangerfile" anymore. They could just peek at the plugin folder and see real examples.
Since plugins are just functions, writing unit tests for them was super straightforward.
Before this, people would often ignore the Danger checks because they weren't sure what was running or why it failed. Now:
- The rules are clear.
- Teams have ownership of their checks.
- And the CI feedback actually helps, rather than annoys.
I'm thinking about:
- Adding conditional plugins (like: run this check only if the MR touches certain files)
- A CLI to list all available plugins with descriptions
- Maybe caching results between runs to make it faster
It's open source: 👉 https://github.com/Tap30/danger