Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 104 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,107 @@
# mono
# Mono

A release management tool to be used in all Zensical projects. This tool is
heavily opinionated and optimized for the workflows we have at Zensical. It
supports Rust, as well as NPM projects.
**Mono repository automation toolkit**

If you need flexibility, you might rather want to use off-the-shelf solutions
like:
`mono` is a release management tool built specifically for monorepos. It validates commits, determines versions, generates changelogs, and orchestrates publishing – all with zero configuration needed for standard workflows. Rust and Node workspaces are supported out of the box, with more languages coming soon.

- [cocogitto](https://github.com/cocogitto/cocogitto)
- [git-cliff](https://github.com/orhun/git-cliff)
- [release-plz](https://github.com/release-plz/release-plz)
- [lerna](https://github.com/lerna/lerna)
## Installation

```bash
cargo install mono
```

Or use our GitHub Action:

```yaml
- uses: zensical/mono@v0
```

## Usage

### Version management

```bash
# Create a new version and update all packages
mono version create

# Generate the changelog of a version in Markdown format
mono version changelog

# List the names of changed packages in topological order
mono version changed

# List versions in reverse chronological order
mono version list
```

### Package discovery

```bash
# List the names of all packages in topological order
mono list
```

### Commit validation

```bash
# Validate a commit message summary
mono validate commit "feature: add authentication"

# Validate a commit message in a file
mono validate commit --file .git/COMMIT_EDITMSG

# Validate a commit by identifier
mono validate commit --id 7b5e433
```

## Features

### Monorepo-first design

- **Automatic package discovery** from `Cargo.toml` workspaces or `package.json` workspaces
- **Automatic scope detection** from directory structure based on packages
- **Topological sorting** ensures dependencies are published before dependents

### Conventional commits validation

- Validates commit messages against Conventional Commits format
- Suggests valid scopes based on actual packages in your monorepo
- Works as a git hook or in CI
- Clear, actionable error messages

### Multi-language support

- **Rust** (Cargo workspaces)
- **Node.js** (npm/pnpm/yarn workspaces)
- **More coming:** Python, ...

### Interactive version bumping

- Visual prompt showing suggested version increments
- Computes suggestions from Conventional Commits types
- Understands `0.0.z` (patch-only) and `0.y.z` (breaking changes = minor) ranges
- Batch version bumping for related packages

### Intelligent changelog generation

- Generates changelogs from Conventional Commits
- Groups changes by package and type (Features, Fixes, Breaking Changes)
- Supports **changelog summaries** attached to commits for curated release notes
- Links to issues and pull requests automatically

### Change detection

- Detects which packages changed since last release
- Returns packages in topological order for publishing
- Integrates with `cargo publish`, `npm publish`, or custom scripts

## Comparison

| Tool | Focus | Why mono |
|------|-------|------------|
| **Lerna** | JavaScript monorepos, publishing | Language-agnostic, opinionated defaults, no Node.js required |
| **changesets** | Developer-written changelogs | Fully automated from git history, no manual changeset files |
| **cocogitto** | Git Conventional Commits | Monorepo-first with automatic scopes and multi-package releases |
| **git-cliff** | Changelog generation | Interactive version selection, package-aware changelogs, topological publishing |
| **cargo-release** | Single Rust crate releases | Multi-package workspaces with dependency ordering |
| **semantic-release** | Automated releases | Simpler, faster, designed for monorepo batch operations |
2 changes: 1 addition & 1 deletion crates/mono/src/cli/command/validate/commit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ use crate::Context;
#[command(group(
ArgGroup::new("input")
.required(true)
.args(&["message", "file", "id"])
.args(&["summary", "file", "id"])
))]
pub struct Arguments {
/// Commit message summary.
Expand Down
8 changes: 6 additions & 2 deletions crates/mono/src/cli/command/version/changed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,12 @@ where
let mut increments = changeset.increments().to_vec();
if self.version.is_some() {
let scopes = changeset.scopes();
if let Some(first) = changeset.revisions().first() {
for delta in first.commit().deltas()? {
if let Some(head) = changeset.revisions().first() {
let commit = head.commit();

// Traverse all deltas in the commit, and mark corresponding
// scopes as changed with at least a patch increment
for delta in commit.deltas()? {
if let Some(node) = scopes.get(delta.path()) {
increments[node] =
cmp::max(increments[node], Some(Increment::Patch));
Expand Down