Change management
In a typical monorepo, we want to build up changes for publishable Workspaces over time while we work on features and major changes. Because we are using a monorepo with source dependencies, we should not need to publish often, because our local Workspace’s are benefitting from code changes immediately.
We still may have certain modules that we publish to a public or private registry. Developer workflows will have a few additional steps.
One of the few opinionated pieces of oneRepo is in how publishable modules log & track changes, update versions, and publish to their registry. All of this is handled by the change
command set.
Getting started
Section titled Getting startedUnlike other change entry systems, oneRepo compiles change entry files into a .changes
folder within each workspace. These files use incremental IDs to help developers review potential order of changes as well as a unique string to prevent collisions across branches. By default, the change entries will be named with a hash of their contents:
Directorymodules
Directoryburritos
Directory.changes
- 001-978af1g.md
- 002-3ah36g1.md
- package.json
Directorytacos
Directory.changes
- 001-978af1g.md
- package.json
Funny filenames
Section titled Funny filenamesIf you prefer something a little more fun, add the human-id package to your Root Workspace and set changes.filenames
to 'human'
in your Root configuration file.
-
Add the
human-id
dependencyUse the
dependencies
command to make things easy. -
Update the config
Use the
dependencies
command to make things easy. -
Enjoy your funny filenames.
Directorymodules
Directoryburritos
Directory.changes
- 001-late-lions-accept.md
- 002-pretty-jars-dig.md
- package.json
Directorytacos
Directory.changes
- 001-swift-seals-walk.md
- package.json
Workflow
Section titled WorkflowCode changes
Section titled Code changes-
Modify code and add change files
For each Workspaces that publishes a module, whenever we commit notable changes that should appear in a changelog, we add change entry files using
one change add
command. This command will help us create individual changelog entries in the form of Markdown formatted files with YAML frontmatter. The files are stored away in each related Workspace until needed later. -
Commit files
Add change entries will create Markdown files with the change entry content in each appropriate Workspace. You will see these files in
<workspace>/.changes/*.md
. It is important to track and commit these files to the repository, as we will use them later on down the line when we’re ready to publish a new version. -
Pull request & merge” noTermina
Create a pull request with your commits to review. Since change entry files are tracked, you can always edit them later if there’s a mistake or you would like to add more information for the change.
Once ready, merge your pull request to your main branch and move on.
Version & publish
Section titled Version & publishEventually, we will need to publish one or more Workspaces to our registry for use in another repository. To do this, we follow another short workflow:
-
Update versions
First, we increment the version automatically using the command
one change version
. This command will prompt for the Workspace or Workspaces that we would like to publish and automatically ensure that any dependencies with changes are also incremented appropriately.This extra increment is necessary to ensure that each Workspace is published with the latest changes. Without this step, it would be possible that critical features would end up missing and causing errors in your published modules.
-
Verify new versions
Next, you will be asked to verify new versions. This step will list new versions for dependencies of the Workspace(s) that you requested to version that also have changes in them.
You cannot version and publish the requested Workspaces without including these Workspaces as well.
-
Pull request & merge” noTermina
The change entries related to the versioned Workspaces will be removed and their contents recreated into each Workspace’s
CHANGELOG.md
file.Add and commit all changes, then create a pull request with your commits to review.
Once ready, merge your pull request to your main branch.
-
Publish
Your updated versions are now ready to publish. Either automate this step in your CI pipline after pull requests are merged or run the command manually.
Commands
Section titled Commandsone change
Section titled one changeAliases: one changes
, one changesets
Manage changes and changesets for publishable Workspaces.
one change add
Section titled one change addAliases: one change
Add changesets for modified Workspaces.
This command will prompt for appropriate Workspace(s), prompt for the release type, and request a descriptive change entry. Once all information has been entered, a change entry file will be created in the appropriate Workspace(s). Be sure to commit these files – they will be used later when you are ready to version and publish Workspaces to the registry for use outside of the Monorepo.
Option | Type | Description |
---|---|---|
--add | boolean , default: true | Add the modified package.json files to the git stage for committing. |
--affected | boolean | Select all affected Workspaces. If no other inputs are chosen, this will default to true . |
--all, -a | boolean | Run across all Workspaces |
--type | "major" , "minor" , "patch" | Provide a semantic version bump type. If not given, a prompt will guide you through selecting the appropriate type. |
--workspaces, -w | array | List of Workspace names to run against |
Advanced options
Option | Type | Description |
---|---|---|
--filenames | "hash" , "human" , default: "hash" | Filename generation strategy for change files. If 'human' , ensure you have the human-id package installed. |
--from-ref | string | Git ref to start looking for affected files or Workspaces |
--prompts | "guided" , "semver" , default: "guided" | Change the prompt question & answer style when adding change entries. |
--staged | boolean | Use files on the git stage to calculate affected files or Workspaces. When unset or --no-staged , changes will be calculated from the entire branch, since its fork point. |
--through-ref | string | Git ref to start looking for affected files or Workspaces |
one change migrate
Section titled one change migrateMigrate from Changesets to oneRepo changes.
Advanced options
Option | Type | Description |
---|---|---|
--filenames | "hash" , "human" , default: "hash" | Filename generation strategy for change files. If 'human' , ensure you have the human-id package installed. |
one change publish
Section titled one change publishAliases: one change release
Publish all Workspaces with versions not available in the registry.
This command is safe to run any time. By default, only Workspaces that have previously gone through the one change version
process will end up being published. Use --all
for all Workspaces or --workspaces <workspace-name>
to specify individual Workspaces to try publishing.
For each Workspace, the registry will be queried first to ensure the current version in the Workspace does not yet exist in the registry. If a version does exist, the Workspace will be skipped.
The pre-publish
and post-publish
task lifecycles will be run during this command for each Workspace published. These Task lifecycles are roughly equivalent to the prepack
and postpack
provided by npm, Yarn, and pnpm.
Option | Type | Description |
---|---|---|
--all, -a | boolean | Run across all Workspaces |
--otp | boolean | Set to true if your publishes require an OTP for NPM. |
--skip-auth | boolean | Skip auth checks. This may be necessary for some internal registries using PATs or tokens. |
--workspaces, -w | array | List of Workspace names to run against |
Advanced options
Option | Type | Description |
---|---|---|
--affected | boolean | Select all affected Workspaces. If no other inputs are chosen, this will default to true . |
--allow-dirty | boolean | Bypass checks to ensure there are no un-committed changes. |
--from-ref | string | Git ref to start looking for affected files or Workspaces |
--staged | boolean | Use files on the git stage to calculate affected files or Workspaces. When unset or --no-staged , changes will be calculated from the entire branch, since its fork point. |
--through-ref | string | Git ref to start looking for affected files or Workspaces |
Publish the api
Workspace and its dependencies, if necessary.
Attempt to publish all non-private Workspaces.
one change show
Section titled one change showPreview the next versions and changelogs for Workspaces.
Option | Type | Description |
---|---|---|
--all, -a | boolean | Run across all Workspaces |
--format | "json" , "plain" , default: "plain" | Choose how the results will be returned. |
--workspaces, -w | array | List of Workspace names to run against |
one change snapshot
Section titled one change snapshotAliases: one change snap
Publish a snapshot pre-release.
Periodically you may want to publish a snapshot release – something that needs testing from the registry, but should not update the current version nor be made widely available. For these cases, use --snapshot
and versions will be published in the format 0.0.0-{tag}-{hash}
, where {hash}
is a short version of the current git sha. By appending a prerelease to version 0.0.0
, discoverability is greatly reduced.
Option | Type | Description |
---|---|---|
--all, -a | boolean | Run across all Workspaces |
--allow-dirty | boolean | Bypass checks to ensure there are no un-committed changes. |
--otp | boolean | Prompt for one-time password before publishing to the registry |
--reset | boolean , default: true | Reset package.json changes before exiting. Use --no-reset to disable. |
--tag | string , default: "prerelease" | Distribution tag to apply when publishing the pre-release. |
--workspaces, -w | array | List of Workspace names to run against |
one change verify
Section titled one change verifyAliases: one change required
Ensure there are change entries for every modified public Workspace.
Add this to your pre-commit or pre-merge task lifecycles to ensure that changes to public & publishabled Workspaces are always accompanied with change entries.
one change version
Section titled one change versionUpdate version numbers for publishable Workspaces
Option | Type | Description |
---|---|---|
--all, -a | boolean | Run across all Workspaces |
--allow-dirty | boolean | Bypass checks to ensure there are no un-committed changes. |
--prerelease, --pre, --pre-release | string | Create a pre-release using the specified identifier. |
--workspaces, -w | array | List of Workspace names to run against |
Create a prerelease for the next version the form of 1.2.3-alpha.0
.
Can I edit change files?
Yes. This is one of the main benefits of the approach we use. All change files are tracked in your git repository until they’re ready to be consumed by a the change version
command. Until then, it’s safe to add, edit, or delete change files as needed.
Got a typo? Want to add more context? No problem! Just modify the appropriate change files, commit them, and move on.
Versioning deleted my change files. Is that okay?
This is expected! Change files are temporary placeholders that inform the change version
command how to pick the appropriate next version. Once they are consumed, they get compiled back to each Workspace’s CHANGELOG.md
file.
Can I edit my changelog after it’s written?
Because change entries are written in isolation, it can be really helpful to edit your CHANGELOG.md
file after versioning and before publishing to add context and make instructions flow better. You can safely modify your CHANGELOG.md
files any time.
Why is the
oneRepo does its best to limit the number of dependencies it requires, especially those of significant weight. We really like human-id, but it is a large dataset and English-only, so it has been made optional.human-id
package not used by default?
Alternatives
Section titled AlternativesChangesets
Section titled ChangesetsoneRepo changes are inspired by 🦋 Changesets. While they provide a lot of the same functionality, there are various issues conflicting with oneRepo:
- Changelogs are written to private packages (Issue #313)
- Building and applying release plans is cumbersome with changesets when not using the
@changesets/cli
package directly. The oneRepo Graph does a fantastic job of handling Workspace linking and versioning. - Source Dependencies are one of the main reasons oneRepo was created, as other monorepo tooling doesn’t enforce or help with setting up and managing correct linking. Keeping changesets as a plugin makes this too optional and confusing to explain and implement.
- It’s easy to forget to write changesets, which can prevent versioning & publishing. Changesets do not also take into account git changes in Workspaces and dependent Workspaces.
- Changesets is haphazardly documented and difficult to onboard large teams. Many potentially helpful docs were stubbed in and forgotten for many years (example: Problems publishing in monorepos)
Conventional commits
Section titled Conventional commitsConventional Commits is a standard specification for writing effective change entries via git commit messages. The commits are then parsed in order to determine version release type, breaking changes, and compiling changelogs.
While Conventional Commits is a wonderfully sound approach for single module repositories, it quickly degrades in Monorepos when developers work across a number of Workspaces or have changes that are less deserving of mention in changelogs.
There is also little room for error with Conventional Commits, because changelog entries are set in stone once commits are written – unless you allow rewriting history, which you likely do not.