Dev agility is all about getting your code into production as fast as possible and turning the time you invested into product value. The faster you can securely and reliably get your code into the hands of your users, the better.
One part of this is packaging up code into containers, ready to be deployed on servers. Containers are great at defining the exact environment to run code in and automating the creation of them means you can get code live faster.
Automating this process means less time manually running tests and building containers. To do this you can hook into the git flow you're already using.
The workflow is as follows:
- structure commits to describe changes to the application
- semantically version the app based on those commits
- [not covered] automatically build container images based on those versions
There are a couple of npm packages to help with this.
- yorkie lets you define scripts that run on when you interact with git
- @commitlint/cli is a utility for linting commit messages
- standard-version analyses commits to automatically version your app and generate changelogs
This workflow uses semantic versioning to denote the changes to the application. From this you can see the relation between different versions and work out what changes are safe to be deployed.
There are three parts to a semantic version
major.minor.patch. If the application is a major change, e.g. 1.2.3 to 2.0.0, you know there is some extra work needed to migrate a deployment. If there is a minor or patch change, e.g. going from 2.0.0 to 2.0.1 or 2.1.0 you know it's safe to deploy the new version as it (should) only contain backwards compatable changes.
More about Semantic versioning →
Conventional commits are a standard format for commit messages that describe the type of changes made. It also forces commits towards atomic single-concern commits, i.e. only working on one bug/change/feature at a time.
fix: stop user from dropping users table is a backwards-compatible fix and generates a semver patch
feat: add new fancy buttons is a backwards-compatible enhancement and triggers a semver minor version
BREAKING CHANGE: redesign login form is a breaking change and triggers a major semver change
You can also supply a commit body and/or footer to add more info to your commit. Here's a full example:
BREAKING CHANGE: redesign login form
We reviewed user feedback and moved all the buttons around
to make the login flow as easy as possible
I find the footer works nicely with github's fix/resolves syntax
More info on conventional commits →
The final piece of the puzzle is standard version, it is a command that parses git commits to work out whats changed since the last version. Because the commits are "conventional" it can work out what the next semantic version of the app should be and it can accurately generate a changelog from commit messages.
For example, if you'd commited three
fix:-es and a one
feat: it would increase the semver's minor part. It'll then go away and generate a changelog with those commit messages and run the npm version command to increament that minor version. It creates a commit for those changes and tags it with the new version.
When you push up a tag you then have a pipeline of your choice to build a container image.
git add somefile.txt
git commit -m "feat: add that really cool thing you wanted"
npm run release
Or a more complex example:
git checkout -b feature-branch
git commit -m "fix: add check for divide by zero"
git checkout master
git merge feature-branch
npm run release
git push --follow-tags origin master
Most of these can be done inside your favourite IDE
Start by adding these dependencies
npm install --save-dev \
Then add this to your package.json:
"commit-msg": "commitlint -e $HUSKY_GIT_PARAMS"
First it sets up commit lint to ensure your commits meet the conventional commits standard. This means you can't commit unless you
Second it sets up a git hook to run commitlint on
commit-msg, which means your commit will fail if it doens't meet the standard.
Next add this script to your package.json.
Now you can perform a release with npm run. Like this:
npm run release
- Write commit messages that are conventional commits
npm run release to version releases and generate changelogs
- Next setup a CI/CD to generate a docker image based on git tags