These 6 essential tools will release, version, and maintain your NPM modules for you

24,170 reads

@ patrickleet Patrick Lee Scott Read my story at https://patscott.io/

Learning how to implement them for your own projects will save you a ton of time!

Managing open source projects is way too much work.

That’s why your favorite obscure library with 1 or 2 contributors has not merged your pull request.

reactions

In order to remedy this situation, a suite of automation tools can be employed to free you from the shackles of keeping dependencies up-to-date, ensuring code quality, and releasing new versions of your software.

reactions

Unfortunately, we can’t automate away all of the maintenance, but we can deal with a lot of it.

reactions

First of all, you’ll need an npm account, and a github account for these to work.

reactions

Let’s get started.

reactions

1. Automate your releases and semantic versioning with semantic-release

This first tool really solves the biggest pain point in my opinion. Releasing new versions of your software.

reactions

When using it correctly,

semantic-release

reactions

will calculate new version numbers when necessary, taking the emotional part of deciding when to bump a version number out of the equation.

It also publishes you package to npm, and tags a new release in GitHub. This generates a nicely formatted Releases page detailing the changes that make up every new version!

reactions

First, install the semantic-release-cli tool:

reactions

npm i -g semantic-release-cli

Then, use it to set up your project. Run the following in the npm module you’re working on:

reactions

➜ semantic-release-cli setup ? What is your npm registry? https: //registry.npmjs.org/ ? What is your npm username? patrickleet ? What is your npm password? [hidden] ? What is your GitHub username? patrickleet ? What is your GitHub password? [hidden] ? What is your GitHub two-factor authentication code? [hidden] ? What CI are you using? Travis CI ? Do you want a `.travis.yml` file with semantic-release setup? Yes

This will set up all necessary connections and authentication with Travis, Github, and NPM.

reactions

Here’s the new

package.json

reactions

{ "name" : "open-source-setup" , "version" : "0.0.0-development" , "description" : "" , "main" : "index.js" , "scripts" : { "test" : "echo \"Error: no test specified\" && exit 1" , }, "author" : "" , "license" : "ISC" , "repository" : { "type" : "git" , "url" : "https://github.com/patrickleet/open-source-setup.git" } }

file.

Running

semantic-release-cli

package.json

semantic-release

package.json

0.0.0-development

reactions

setup added two new scripts to ourfile.which calls the devDependency by the same name, is what calculates the version and prepares the build’sfile by replacingwith the newly calculated “semantic version”, or “semver”.

The next script

travis-deploy-once

travis-deploy-once

reactions

will run the actual release portion. However, builds can be run in multiple environments in Travis at once. We needto ensure that the actual release happens only once, when all builds have finished, instead of releasing for every tested Node version.

The

setup

repository

devDependencies

reactions

command will also add the requiredsection to your config if it is missing, and install the new required

Lastly, a “travis.yml” file was also generated with the following content:

reactions

language: node_js node_js: - node - 10 - 8 cache: npm install: - npm install - npm install -g codecov script: - npm run lint - npm run test - codecov branches: except: - '/^v\d+\.\d+\.\d+$/' jobs: include: - stage: deploy if : branch == master && !fork node_js: 'node' # pre-installed version script: - npm install -g semantic-release@^ 15 - semantic-release

2. Use commitizen with cz-convential-changelog to capture additional details about each commit

semantic-release

reactions

needs a little help to actually calculate the new version, though, given that it doesn’t actually understand what your code does, an obvious prerequisite to understanding if there are breaking changes, and thus still relies on the developer to tell it.

The way it does this is through the commit messages that have occurred between the previous release and the current release.

reactions

Consider the following examples:

reactions

git commit -m 'unhelpful' # semantic-release has no idea what you did git commit -m "feat(Customers): Add new customer API endpoints to be more human friendly, removed delete route and replaced it with deactivate BREAKING CHANGE: The old /delete url is no longer supported." # semantic-release knows you wrote a new feature. That 's a minor version bump. Also, there is a breaking change! This calls for a major bump instead!

The problem with this is now you’re expecting people to know and/or care about your rules about how you should write commit messages.

reactions

Don’t worry, there’s a module for that!

reactions

It’s called commitizen, and when a user runs it, it prompts the user with a wizard to create their commit message. It asks a series of questions to do so.

reactions

First, to install:

reactions

npm i --save-dev commitizen cz-conventional-changelog

commitizen

cz-conventional-changelog

reactions

is the tool that provides the wizard, andis a plugin that describes the desired commit format.

In package.json make the following changes:

reactions

// package.json { //... scripts: { "commit" : "git-cz" , // ... }, //... "config" : { "commitizen" : { "path" : "./node_modules/cz-conventional-changelog" } } }

Now instead of commiting with git

commit -m ""

npm run commit

reactions

➜ npm run commit > open-source-setup@ 0.0 .0 -development commit /Users/patrickscott/dev/patrickleet/open-source-setup > git-cz /Users/patrickscott/dev/patrickleet/open-source-setup /Users/patrickscott/dev/patrickleet/open-source-setup cz-cli@ 2.9 .6 , cz-conventional-changelog@ 2.1 .0 Line 1 will be cropped at 100 characters. All other lines will be wrapped after 100 characters. ? Select the type of change that you 're committing: chore: Other changes that don' t modify src or test files ? What is the scope of this change (e.g. component or file name)? (press enter to skip) release ? Write a short, imperative tense description of the change: added commitizen and cz-conventional-changelog ? Provide a longer description of the change: (press enter to skip) These dependencies allow users to commit in the desired format by using npm run commit instead of git commit -m ? Are there any breaking changes? No ? Does this change affect any open issues? No [master 7 a98de5] chore(release): added commitizen and cz-conventional-changelog 3 files changed, 5989 insertions(+) create mode 100644 .gitignore create mode 100644 package-lock.json

, we can use

Our nicely formatted commit message

reactions

PRO TIP: You’ll still get Pull Requests that don’t follow these rules – in those cases, select “Squash and Merge” instead of the default “Create Merge Commit”. You’ll be able to enter a new commit message that will trigger a new release.

3. Run Automated Tests that generate Code Coverage reports

Releasing just anything isn’t a great practice. This article isn’t about testing, but, if you aren’t running automated tests as part of your release process, you’re doing it wrong.

reactions

I really like

jest

reactions

for this. As such, I will add the minimal set up for jest.

Whatever you use, it’s important that you are generating coverage reports! Jest does this out of the box by simply using the

--coverage flag

reactions

. I also find it’s mocking functionality to be really simple to use.

To set up jest and report coverage, make the following changes:

reactions

npm i --save-dev jest mkdir __tests__ touch jest.config

Many people like putting their jest config in their package.json. I think it’s cluttered enough as is, so I usually use the following

jest.config

reactions

{ "testEnvironment" : "node" , "modulePaths" : [ "src" , "/node_modules/" ], "coverageThreshold" : { "global" : { "branches" : 100 , "functions" : 100 , "lines" : 100 , "statements" : 100 } }, "collectCoverageFrom" : [ "src/**/*.js" ] }

And in package.json :

reactions

"scripts" : { "commit" : "git-cz" , "test" : "jest --config jest.json --coverage" , "semantic-release" : "semantic-release" , "travis-deploy-once" : "travis-deploy-once" },

My test repository has 0 files, and 0 tests, so to fix that quickly, I created two files in this commit. Given it’s a bit of a long article already, and it’s out of scope, feel free to check those files out there.

reactions

You’ll also want to add

coverage

.gitignore

reactions

to yourfile.

Here’s the new output of running

npm run test

reactions

A new folder

coverage

open ./coverage/lcov-report/index.html

reactions

4. Maintain coverage standards with Codecov

is also generate with the results. Check it out by running

With the jest setup, the project is now outputting a coverage folder. This is pretty much the only requirement to set up codecov when you’re project is open-source and running on Travis.

reactions

By setting up codecov, you’ll get a nice shiny badge on your README, advertising your well-tested code, as well as automated comments on all Pull Requests detailing how changes affect coverage.

reactions

I’ve already included the required changes in the .travis.yml file above so you’re all set here if you’re following along.

reactions

Also head on over to CodeCov and create an account by logging in with GitHub and granting appropriate permissions.

reactions

5. Ensure consistent code formatting, and avoid simple mistakes by Linting your code

While we’re ensuring code quality, we’ll also want to make sure all code passes a linting test before we allow it to be deployed.

reactions

It’s up to you what standard you prefer! Some like airbnb, others prefer “standard”.

reactions

Pick what works for you and your team, but please, pick something!

reactions

I’m gonna go with the standard named

standardjs

reactions

which, despite it’s name, is not a standard. But I still dig it.

Let’s install

eslint

reactions

npm i -- save - dev eslint

and run the setup.

Running

npx eslint --init

reactions

➜ npx eslint --init ? How would you like to configure ESLint? Use a popular style guide ? Which style guide do you want to follow? Standard ? What format do you want your config file to be in ? JSON

will start a wizard to install and configure the correct dependencies for your selections.

As a result, a very simple config,

.eslintrc.json

reactions

{ "extends" : "standard" }

was generated.

To perform the lint, we need to add some scripts to

package.json

reactions

"scripts" : { "commit" : "git-cz" , "lint" : "eslint src __tests__" , "lint:fix" : "eslint --fix src __tests__" , "test" : "jest --config jest.json --coverage" , "semantic-release" : "semantic-release" , "travis-deploy-once" : "travis-deploy-once" },

The command is simple, it takes in a list of folders to lint using the settings in

.eslintrc.json

--fix

reactions

. I like to create the second command withto autofix problems when I’m running it locally.

Here’s an example of the difference

reactions

➜ npm run lint > open-source-setup@ 0.0 .0 -development lint /Users/patrickscott/dev/patrickleet/open-source-setup > eslint src __tests__ /Users/patrickscott/dev/patrickleet/open-source-setup/src/index.js 1 : 44 error Newline required at end of file but not found eol-last /Users/patrickscott/dev/patrickleet/open-source-setup/__tests__/index.js 3 : 1 error 'describe' is not defined no-undef 4 : 3 error 'it' is not defined no-undef 6 : 5 error 'expect' is not defined no-undef 8 : 3 error Newline required at end of file but not found eol-last ✖ 5 problems ( 5 errors, 0 warnings) 2 errors, 0 warnings potentially fixable with the `--fix` option. ➜ npm run lint:fix > open-source-setup@ 0.0 .0 -development lint:fix /Users/patrickscott/dev/patrickleet/open-source-setup > eslint --fix src __tests__ /Users/patrickscott/dev/patrickleet/open-source-setup/__tests__/index.js 3 : 1 error 'describe' is not defined no-undef 4 : 3 error 'it' is not defined no-undef 6 : 5 error 'expect' is not defined no-undef ✖ 3 problems ( 3 errors, 0 warnings)

The first time, it only told us what was wrong. When including the fix flag, 2 of the 5 errors could automatically be fixed.

reactions

The remaining three errors are due to the way jest works, which is, assuming these global variables will be defined by the test runner.

reactions

We can fix this by telling

eslint

.eslintrc.json

reactions

{ "extends" : "standard" , "globals" : { "describe" : true , "it" : true , "expect" : true } }

that these are not issues by modifying

Now running

npm run lint

reactions

exits with no errors.

I’ve already added this in the first

.travis.yml

reactions

file as well.

With that, I’m pushing my code! But we aren’t quite done yet. The next tool, however, expects us to be at the point before it can be set up.

reactions

Here is the result of the build, and a release of the package was created on Github as well as published to NPM.

reactions

I encourage you to go through the job lob on Travis and read the output to see how semantic-release calculated it’s release.

reactions

Before we continue, let’s take a second and make our README pretty (or at all). To be legit, we clearly need all the badges.

reactions

Head to Travis first and get your badge like by clicking the badge near the top of the page for the build. A popup will open with different embed codes. You’ll want markdown for the Readme file.

reactions

I think they look nice right under the heading, so go ahead in paste it there or at the top.

reactions

Next, head on over to Codecov. Navigate to your project, and grab the markdown badge showing your repositories code coverage percentage.

reactions

It can be found in the Settings | Badge section.

reactions

Also apparently they have a GitHub app now which is even better that I should install.

reactions

Here’s my README.md file:

reactions

# open source setup [![Build Status](https: //travis-ci.org/patrickleet/open-source-setup.svg?branch=master)](https://travis-ci.org/patrickleet/open-source-setup) [![codecov](https: //codecov.io/gh/patrickleet/open-source-setup/branch/master/graph/badge.svg)](https://codecov.io/gh/patrickleet/open-source-setup) An example repository showing how I set up my open-source npm modules.

6. Keep your dependencies up to date with GreenKeeper

The first thing to become outdated in your application is your dependencies.

reactions

That’s ok.

reactions

Progress, new features, and security fixes and being pushed every day all around the world.

reactions

Problem is keeping up with them.

reactions

For this, I use GreenKeeper.io.

reactions

GreenKeeper will watch any registry you tell it to by reading it’s package.json file, and any time a new version of one of your package’s dependencies is updated, it will create a new Pull Request, using

cz-conventional-changelog

reactions

styled commit messages!

This means all you need to do at this point, is press merge if the travis CI build for the Pull Request passed. Which if you’re paying attention, is awesome, because this will trigger a new release using

semantic-release!

reactions

There are two steps to setting up GreenKeeper.

reactions

Follow the installation instructions over at https://greenkeeper.io/docs.html#installation. This is going to instruct you to install the GreenKeeper “GitHub App” and then grant GreenKeeper access to your repositories. For each selected repository, an intial Pull Request will be submitted that you can merge to finish enabling GreenKeeper for that repo.Once you merge that PR, you’ll find you need to complete an additional setup step to enable keeping the lock files up to date.

reactions

You’ll only need to install the GitHub App the first time, though, as future repositories you create will ask if you want to enable it.

reactions

I already had the Greenkeeper GitHub App installed

reactions

It can take a while for the initial Pull Request from GreenKeeper to come in for a new repository.

reactions

Because I’ve done this before, and I know what comes next, there are some updates to the

.travis.yml

reactions

file that we are going to have to make.

Once you’ve merged the PR, greenkeeper will let you know about a dependency that will need to be installed and configured in order for it to be able to keep

package-lock.json

reactions

up to date.

Let’s go ahead and get it done with, and maybe Greenkeeper PR will come in the mean time.

reactions

In travis.yml add the following sections:

reactions

before_install: - npm install -g npm@latest - npm install -g greenkeeper-lockfile@ 1 before_script: greenkeeper-lockfile-update after_script: greenkeeper-lockfile-upload

If for some reason your initial PR still hasn’t come, and it’s been more than 30 minutes, this likely means something went wrong (according to their docs) and troubleshooting steps are available here.

reactions

Once it comes, merge it! The first PR will upgrade ALL of your dependencies to give it an up-to-date baseline, as well as insert the GreenKeeper badge into the README. If this is required, GreenKeeper will let you know.

reactions

Here’s the PR for the project I’ve been working on in this tutorial.

https://github.com/patrickleet/open-source-setup/pull/1

reactions

Conclusion

reactions

This is a really solid baseline for maintaining your open source projects with minimal efforts.

reactions

I hope you’ve found it useful!

reactions

Interested in hearing MY DevOps Journey, WITHOUT useless AWS Certifications? Read it now on HackerNoon.

Please follow me, leave some claps, and check out some of my other articles.

reactions

PRO TIP: Did you know that you are allowed to give up to 50 claps to every article you enjoy? Medium uses this information to pay authors for their most useful content! Pretty cool!

You can do this by clicking/tapping, and then holding the clap button.

Tags