Releasing multiple packages (CLI)
Sometimes you have more than one package in a repository, commonly called a monorepo. This tutorial will show you how to:
- Create a Knope config file
- Document changes that only impact some packages
- Document changes that impact all packages
Prerequisites
- Git: The
git
CLI must be available in your terminal. It’s helpful if you know the basics of commits and tags. - A text editor: You’ll be editing Markdown and TOML files. Visual Studio Code is a good free choice.
- Familiarity with a command line terminal, like “Terminal” on macOS or “PowerShell” Windows
- A GitHub account (you can use an alternative, but the results will be different)
- Install Knope
Create a new Git repo
Start by creating a new directory, moving into it, and initializing a Git repository.
mkdir knope-tutorialcd knope-tutorialgit init
This repo will eventually need to be on GitHub so Knope can create releases for it. You can do that with the GitHub CLI:
gh repo create --private knope-tutorial --source .
Create a Knope config file
Knope requires a config file to support multiple packages.
You could use knope --generate
to create the default config,
but it wouldn’t be quite right for multiple packages.
Instead, create this by hand:
[packages.pizza]versioned_files = ["pizza/Cargo.toml"]changelog = "pizza/CHANGELOG.md"
[packages.toppings]versioned_files = ["toppings/Cargo.toml"]changelog = "toppings/CHANGELOG.md"
[packages.calzone]versioned_files = ["calzone/Cargo.toml"]changelog = "calzone/CHANGELOG.md"
[github]owner = ""repo = "knope-tutorial"
Those referenced files must exist as well:
[package]name = "pizza"version = "3.14.15"
# Pizza Changelog
Documenting everything new in the world of Pizza.
[package]name = "toppings"version = "1.209.0"
# Toppings Changelog
New toppings are added here
[package]name = "calzone"version = "0.14.2"
# Calzone Changelog
Commit this to serve as a baseline for the rest of the tutorial:
git add .git commit -m "Initial setup"
Documenting changes
As with a single package, you can document changes with either changesets or conventional commits.
Changesets
knope document-change
Knope will ask which packages the change impacts:
? Which packages does this change affect? [x] pizza [ ] toppings> [x] calzone[↑↓ to move, space to select one, → to all, ← to none, type to filter]
Use the arrow keys and space bar to select pizza
and calzone
, then press enter.
Next, select patch
as the change type for each:
> Which packages does this change affect? pizza, calzone> What type of change is this for pizza? patch? What type of change is this for calzone? major minor> patch[↑↓ to move, enter to select, type to filter]
Finally, summarize the change:
> Which packages does this change affect? pizza, calzone> What type of change is this for pizza? patch> What type of change is this for calzone? patch? What is a short summary of this change? The cheese is now distributed more evenly[This will be used as a header in the changelog]
This will create a change file that looks like this:
---pizza: patchcalzone: patch---
# The cheese is now distributed more evenly
It includes the name of each package that the change impacts, the type of change for each of those packages, and the summary. At this point, you could add as much Markdown as you want to the bottom of the file to describe the change more fully.
Knope can show you a preview of the upcoming release:
knope release --dry-run
Would delete: .changeset/the_cheese_is_now_distributed_more_evenly.mdWould add the following to pizza/Cargo.toml: 3.14.16Would add the following to pizza/CHANGELOG.md:## 3.14.16 (2023-11-11)
### Fixes
- The cheese is now distributed more evenly
Would add files to git: pizza/Cargo.toml pizza/CHANGELOG.md .changeset/the_cheese_is_now_distributed_more_evenly.mdWould add the following to calzone/Cargo.toml: 0.14.3Would add the following to calzone/CHANGELOG.md:## 0.14.3 (2023-11-11)
### Fixes
- The cheese is now distributed more evenly
Would add files to git: calzone/Cargo.toml calzone/CHANGELOG.md .changeset/the_cheese_is_now_distributed_more_evenly.mdWould run git commit -m "chore: prepare release"Would run git pushWould create a release on GitHub with name pizza 3.14.16 (2023-11-11) and tag pizza/v3.14.16 and body:## Fixes
- The cheese is now distributed more evenlyWould create a release on GitHub with name calzone 0.14.3 (2023-11-11) and tag calzone/v0.14.3 and body:## Fixes
- The cheese is now distributed more evenly
Knope updates the versions and changelogs of each package independently.
Because there are no changes to toppings
, nothing will happen to it.
Conventional commits
Changesets work great for monorepos by default, but conventional commits require a bit more care. A basic conventional commit will apply to all packages:
rm .changeset/the_cheese_is_now_distributed_more_evenly.md # Revert changesetgit commit --allow-empty -m "fix: The cheese is now distributed more evenly" # create basic conventional commitknope release --dry-run # See what Knope would do with it
Would add the following to pizza/Cargo.toml: 3.14.16Would add the following to pizza/CHANGELOG.md:## 3.14.16 (2023-11-11)
### Fixes
- The cheese is now distributed more evenly
Would add files to git: pizza/Cargo.toml pizza/CHANGELOG.mdWould add the following to toppings/Cargo.toml: 1.209.1Would add the following to toppings/CHANGELOG.md:## 1.209.1 (2023-11-11)
### Fixes
- The cheese is now distributed more evenly
Would add files to git: toppings/Cargo.toml toppings/CHANGELOG.mdWould add the following to calzone/Cargo.toml: 0.14.3Would add the following to calzone/CHANGELOG.md:## 0.14.3 (2023-11-11)
### Fixes
- The cheese is now distributed more evenly
Would add files to git: calzone/Cargo.toml calzone/CHANGELOG.mdWould run git commit -m "chore: prepare release"Would run git pushWould create a release on GitHub with name pizza 3.14.16 (2023-11-11) and tag pizza/v3.14.16 and body:## Fixes
- The cheese is now distributed more evenlyWould create a release on GitHub with name toppings 1.209.1 (2023-11-11) and tag toppings/v1.209.1 and body:## Fixes
- The cheese is now distributed more evenlyWould create a release on GitHub with name calzone 0.14.3 (2023-11-11) and tag calzone/v0.14.3 and body:## Fixes
- The cheese is now distributed more evenly
You can limit commits to specific packages using scopes:
[packages.pizza]versioned_files = ["pizza/Cargo.toml"]changelog = "pizza/CHANGELOG.md"scopes = ["pizza"]
[packages.toppings]versioned_files = ["toppings/Cargo.toml"]changelog = "toppings/CHANGELOG.md"
[packages.calzone]versioned_files = ["calzone/Cargo.toml"]changelog = "calzone/CHANGELOG.md"scopes = ["calzone"]
Now, conventional commits which have the pizza
scope will only affect the pizza
package,
and calzone
commits will only affect the calzone
package.
Commits without scopes (like the one you just created) will still affect all packages,
you can verify that with knope release --dry-run
again.
It’s possible to recreate the changeset results using two commits:
But the point of conventional commits is to document the changes made within the commit, so one change should be in one commit, not two. It’s better to have a new scope that impacts both packages:
[packages.pizza]versioned_files = ["pizza/Cargo.toml"]changelog = "pizza/CHANGELOG.md"scopes = ["pizza", "pizza-and-calzone"]
[packages.toppings]versioned_files = ["toppings/Cargo.toml"]changelog = "toppings/CHANGELOG.md"
[packages.calzone]versioned_files = ["calzone/Cargo.toml"]changelog = "calzone/CHANGELOG.md"scopes = ["calzone", "pizza-and-calzone"]
Now a single commit can impact both pizza
and calzone
, without impacting toppings
:
git reset HEAD~ # undo the unscoped commitgit commit --allow-empty -m "fix(pizza-and-calzone): The cheese is now distributed more evenly"
knope release --dry-run
Would add the following to pizza/Cargo.toml: 3.14.16Would add the following to pizza/CHANGELOG.md:## 3.14.16 (2023-11-11)
### Fixes
- The cheese is now distributed more evenly
Would add files to git: pizza/Cargo.toml pizza/CHANGELOG.mdWould add the following to calzone/Cargo.toml: 0.14.3Would add the following to calzone/CHANGELOG.md:## 0.14.3 (2023-11-11)
### Fixes
- The cheese is now distributed more evenly
Would add files to git: calzone/Cargo.toml calzone/CHANGELOG.mdWould run git commit -m "chore: prepare release"Would run git pushWould create a release on GitHub with name pizza 3.14.16 (2023-11-11) and tag pizza/v3.14.16 and body:## Fixes
- The cheese is now distributed more evenlyWould create a release on GitHub with name calzone 0.14.3 (2023-11-11) and tag calzone/v0.14.3 and body:## Fixes
- The cheese is now distributed more evenly
This is the same result as the changeset, but with a single commit message instead.
Time to try it out for real:
knope release
If you don’t have a GitHub token set, Knope will prompt you to create one and paste it into the terminal. Once you do, you’ll see some output from Git. If there are no errors, your releases should exist!
Open your repo in GitHub (you can use gh repo view --web
), and click on “Releases” on the side.
You should see something like this:


Knope creates one release on GitHub per package so that it’s easy for consumers to see what’s changed in only the packages they care about!
Wrapping up
In this tutorial, you:
- Configured Knope for a monorepo
- Documented changes using both changesets and conventional commits
- Created GitHub releases for each package