Releasing multiple packages
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
gitCLI 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 initThis 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 ChangelogCommit 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-changeKnope 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 evenlyIt 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-runWould 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 evenlyKnope 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 itWould 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 evenlyYou 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-runWould 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 evenlyThis is the same result as the changeset, but with a single commit message instead.
Time to try it out for real:
knope releaseIf 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