The creation of software usually takes place across multiple iterations, and our code changes often. Because of that, we need a way to describe this process with the use of versions.
There are quite a few ways to do that. Recently the most widely adopted approach seems to be semantic versioning. It involves a sequence of three digits separated with dots.
- Major version
Increasing the major version number means that we introduced a breaking change. Our users might probably need to alter their code to adapt to it - Minor version
Bumping the minor version number indicates that we introduce a feature that adds functionality in a backward-compatible way - Patch version
If our new release increases just the patch version number means introducing a backward-compatible bug fix
If you want to know more about how to deal with Semantic Versioning in your package.json file, check out Keeping your dependencies in order when using NPM
When our codebase evolves, it might be challenging to track all of the changes accurately. Fortunately, we have tools that help us do just that.
Using Conventional Commits
The Standard Version utility can figure out a proper release version and generate a changelog file for us. To do that, we need to follow a Conventional Commits specification.
The Conventional Commits provides a way for us to mark our changes as new features or fixes. Therefore, Standard Version can infer the version based on that and generate a changelog.
The “fix” type indicates that this commit removes a bug in the codebase. Creating a release with such a commit results in bumping the patch version
1 |
fix: prevent the application from crashing |
Creating a “feat” commit means introducing a new feature. Therefore, it increases the minor version.
1 |
feat: add the possibility to filter posts |
A commit marked as a breaking change results in increasing the major version. We can create it either by appending the ! sign, or adding the information in the footer.
1 |
fix!: change the way that the posts are filtered to deal with a bug |
1 2 3 |
feat: add pagination to the posts endpoint BREAKING CHANGE: now the result might not contain all posts |
We can use many different types of commits, such as:
- test – when modifying existing tests, or adding new ones
- refactor – changing the code in a way that does not fix a bug nor adds features
- docs – modifying the documentation
- chore – routine tasks such as updating dependencies
- build – affecting the way the application builds
We can make any of the above commits more precise by adding a scope.
1 |
feat(Users): add a way for the users to upload avatars |
Even without the benefits such as generating the changelog and dealing with the semantic versioning, using the above convention make our commits more explicit and meaningful.
Introducing Standard Version
Thanks to using the Conventional Commits, we can now start using the Standard Version.
1 |
npm install --save-dev standard-version |
Now, we need to add it to our scripts in package.json.
1 2 3 |
"scripts": { "release": "standard-version" } |
When we create the first release, we might want to pass some additional parameters.
1 |
npm run release -- --first-release |
✖ skip version bump on first release
✔ created CHANGELOG.md
✔ outputting changes to CHANGELOG.md
✔ committing CHANGELOG.md
✔ tagging release v1.0.0
ℹ Rungit push --follow-tags origin master
to publish
A few important things are happening above. The most noticeable is the fact that we now have a CHANGELOG file. Since my initial commit was a chore, it does not mention any features.
CHANGELOG.md
1 2 3 4 5 |
# Changelog All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. ## 1.0.0 (2020-08-16) |
Because we’ve used the --first-release flag, our version in the package.json hasn’t changed.
The thing we need to look deeper now are the Git tags.
Working with Tags
In this part of the Getting geeky with Git series, we learn that both branches and tags refer to a specific commit. With tagging, we can point to a specific point in the repository’s history. A common use-case for tags is versioning.
When we run npm run release, Standard Version creates a new tag for us. We can list all of our tags with git tag -n:
v1.0.0 chore(release): 1.0.0
We can also see here that Standard Version automatically committed all of the changes to the changelog.
The Standard Version suggests that we now run git push --follow-tags origin master. This pushes all of our changes along with the tags.
When Standard Version runs, it figures out the changelog and the version by comparing the changes with the latest tag version on your local repository. If you don’t have the latest tags fetched, you might run into unexpected results when generating the changelog. I’ve bumped into this issue in the past.
To make sure that you have all of the tags fetched, you can run git fetch --all --tags.
Making further changes
Now let’s make some additional changes, and let’s see how the Standard Version works.
fix: prevent the application from crashing
1 |
npm run release |
Doing the above adds the following to the changelog:
CHANGELOG.md
1 2 3 4 5 6 7 8 |
### 1.0.1 (2020-08-16) ### Bug Fixes * prevent the application from crashing ([e275252](https://github.com/mwanago/versioned-repo/commit/e275252e298326b34ab5866a6ab00464a498f0bf)) (...) |
Above, we can see that the patch version is bumped because we only committed a bug fix. Now, let’s add a feature.
feat: add the possibility to filter posts
chore(gitignore): add node_modules
1 |
npm run release |
CHANGELOG.md
1 2 3 4 5 6 7 8 |
## [1.1.0](https://github.com/mwanago/versioned-repo/compare/v1.0.1...v1.1.0) (2020-08-16) ### Features * add the possibility to filter posts ([5f34a96](https://github.com/mwanago/versioned-repo/commit/5f34a967fe103abb9abe88aa09b152a8213dd8fd) (...) |
We can notice that only relevant information is added, and the chore gets omitted. Now, let’s add some breaking changes.
feat(Posts): add pagination to the posts endpoint
BREAKING CHANGE: now the result might not contain all postsfix(Posts)!: change the way that the posts are filtered to deal with a bug
1 |
npm run release |
CHANGELOG.md
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
## [2.0.0](https://github.com/mwanago/versioned-repo/compare/v1.1.0...v2.0.0) (2020-08-16) ### ⚠ BREAKING CHANGES * **Posts:** change the way that the posts are filtered to deal with a bug * now the result might not contain all posts ### Features * add pagination to the posts endpoint ([4368c20](https://github.com/mwanago/versioned-repo/commit/4368c2029f0e587ff85fe2a6b112704ec0552638)) ### Bug Fixes * **Posts:** change the way that the posts are filtered to deal with a bug ([f8016a1](https://github.com/mwanago/versioned-repo/commit/f8016a1f2e4e72c0005ca1ffc3b84667e4100264)) (...) |
This time Standard Version bumps the major number because of breaking changes.
We can also view all of our tags on GitHub, for example.
Summary
In this article, we’ve learned how to use Standard Version to generate a changelog and deal with the versioning. To do so, we’ve learned about the Conventional Commits. We’ve also briefly got to know what purpose tags serve in Git. All of that can help us to make our repository cleaner and let the Standard Version library do the heavy lifting.