Continuous Integration and Deployment with Codeship
Continuous integration (CI) is one of those topics that might sound scary and complicated, and of course there are a gazillion aspects of it that could occupy you for years, but getting started doesn’t have to be a major undertaking.
The idea of CI is very coupled to using a code repository (usually git) as well as the idea that testing and building on every committed change and releasing often will help you identify problems early.
Quick introduction to git/CI-based workflows
A common setup with git and CI is to have a branch calleddevelop
, which will automatically test/build any changes and deploy to a develop/staging environment (which is only for internal preview/testing), and a branch calledmaster
, which will do the same for the production environment.
Each new feature is developed in its own branch. When that’s done, you make a request to merge it todevelop
, writing a short description of what functionality your changes adds or what problems they solve. Someone will then read your description, check your code changes, and decide if this can safely be merged into thedevelop
branch and that it is up to the project’s standards.
Of course, if you are the only person working on a project, you are going to have to fill both these roles. I still think doing pull requests (sometimes called merge requests) is worth doing anyway; they give a very nice high-level overview of the changes that are made to a codebase over time.
When starting a project on my own, I often commit directly to the
master
ordevelop
branch until I have some kind of working proof of concept. Then, when it’s time to start making incremental improvements to the project, I switch to creating a new branch for every feature and making pull requests to myself.
To deploy to production, you then merge thedevelop
branch intomaster
. How often this should happen is up for (much) debate.
Some say that every change todevelop
should kick off a series of automated tests on the staging environment, which should be as identical to the production environment as possible, and automatically deploy to production if they succeed. This idea is called continuous deployment.
Some think that continuous deployment is not always practical and that it is enough to automatically verify that every change to the staging environment could be deployed to production. This idea is called continuous delivery.
How does CI/CD apply to an NPM package?
These are the goals I defined for thehuman-date-range
module:
- Make sure that every commit is tested with Jest and built with Rollup to verify that everything works.
- Make sure that every commit to the project’s
master
branch also publishes successful builds to NPM.
This matches the workflow described above, where “deploy” has simply been translated to “publish a new version to NPM.” There is no “develop environment” here since there is only one NPM. To keep things simple, only commits tomaster
will result in a deploy.
There are ways to have different release “channels.” You can publish a dev version with
npm publish --tag dev
, and anyone who doesnpm install human-date-range
will still get the old stable version. People who like to live dangerously can runnpm install human-date-range@dev
to get your develop version.
!Sign up for a free Codeship Account hbspt.cta.load(1169977, ‘964db6a6-69da-4366-afea-b129019aff07’, {});
Publishing a New Version to NPM
Publishing new versions is done by changing theversion
inpackage.json
and then runningnpm publish
again. This can be done by runningnpm version
, which has the advantage that it can “bump” your current version by one; eithernpm version patch
to bump the last number (1.0.X), ornpm version minor
to bump the middle number (1.X.0), ornpm version major
to bump the first number (X.0.0).
When run in a project with git, it will also create a version-tagged commit for you with the version change. So if you fix a bug in your module, the correct way to make a new release would be to run:
npm version patch
npm publish
Your module is well prepared for CI since testing, building, and publishing are all configured already.
The idea here is to let you control when to publish which version by letting you manually bump the appropriate version number and push all changes fromdevelop
tomaster
when you feel ready to publish a new version.
Because CI will also test and build every commit todevelop
when it’s time to release, you can feel confident about the tests passing inmaster
as well. That’s the theory, so let’s go ahead and set this up.