GitHub action for npm packages

 - 

Do you maintain an npm package or two? If so, and you don't...

GitHub action for npm packages

Created: 12/1/2021Updated: 12/4/2021

Do you maintain an npm package or two? If so, and you don't already have an automated CI/CD pipeline, check out this article to learn how to set one up using a GitHub action.


Quick disclaimer: This task is also totally doable via Azure Pipelines, Bitbucket Pipelines, Jenkins, and any other such product, however, this article will only cover the technical example of how to do it in GitHub.


Generally, these are the steps we're looking to automate in a good continuous integration/delivery (CI/CD) pipeline:

  • Create a fresh environment

  • Install dependencies

  • Compile source code (build it)

  • Run any linters

  • Run any automated tests (unit, integration, etc.)

  • Persist a build artifact

  • Deploy the build

You may do more or less depending on the circumstances, but you get the gist.

Now, let's get on to the fun part!

Creating the GitHub action

Create a file in the root of your project at ./.github/workflows/cd.yml. Once you've created this file, copy and past the below snippet into it:

# ./.github/workflows/cd.ymlname:CDon:push:branches:'master'pull_request:branches:'*'jobs:build:runs-on:ubuntu-lateststeps:-name:Checkoutuses:actions/checkout@v2-name:UseNode.js16.xuses:actions/setup-node@v1with:node-version:16.x-run:npmi-run:npmrunlint-run:npmruntest-once-run:npmrunbuild-uses:actions/upload-artifact@v2with:name:buildpath:./dist-name:Publishtonpmif:${{github.event_name!='pull_request'}}uses:JS-DevTools/npm-publish@v1with:token:${{secrets.NPM_TOKEN}}package:'./dist/package.json'# registry: https://npm.pkg.github.com # for private github registry

Make it your own

Next, we'll go over the steps defined in this pipeline, a few actions you'll need to take, and where you may wish to make optional adjustments.

name:CD

The first thing you'll see is the name. Not a lot to talk about there, but if you have several actions (.yml files in the workflows folder) you'll be able to find them easy via their name in the GitHub project actions page.

on:push:branches:'master'pull_request:branches:'*'

Next you'll see configuration starting with on: followed by sub-keys push and pull_request. This is the configuration that determines when this action will run. In our example it runs on all (*) pull requests and any push to the "master" branch.

You may find that you only want to run the action on pull request to a specific branch, like "develop." You'll also want to update "master" to whatever branch you want associated with publishing new versions (i.e. production) if that's not the "master" branch for your project.

jobs:build:runs-on:ubuntu-lateststeps:-name:Checkoutuses:actions/checkout@v2-name:UseNode.js16.xuses:actions/setup-node@v1with:node-version:16.x-run:npmi-run:npmrunlint-run:npmruntest-once-run:npmrunbuild

Next we see the meat of the "build" process. The above commands define the build environment (ubuntu-latest) as well as executing the following steps:

  • Checkout the source code being acted on

  • Add a specific version of node to the environment (doesn't have to be 16, but I wouldn't recommend using "latest")

  • Install dependencies (npm i)

  • Run the following package.json defined scripts:

    • lint - runs the projects linter, eslint for example

    • test-once - executes the unit test suite

    • build - compiles the source code

IMPORTANT: You'll need to define your own lint, test-once, and build commands in your project's "package.json." Not to worry though, if you forget, the build will just fail, give you some feedback and you can iterate.

-uses:actions/upload-artifact@v2with:name:buildpath:./dist

Immediately following the build steps, we have a step to archive the build artifact. This step is not necessary for us to publish to npm in the next step, however, it is a best practice, and it can be helpful to be able to download and inspect a particular artifact on a whim. Remember, rebuilding a project at the same point in source control (same hash) is not the same as re-using a persisted build artifact.

This step can be removed without affecting the rest of the pipeline.

-name:Publishtonpmif:${{github.event_name!='pull_request'}}uses:JS-DevTools/npm-publish@v1with:token:${{secrets.NPM_TOKEN}}package:'./dist/package.json'# registry: https://npm.pkg.github.com # for private github registry

Finally, we reach the "publish to npm" step. Unlike the other actions we use, this one is not prefixed with "actions", but instead, JS-DevTools [1]. That's because it's not a built-in GitHub action and the author is JS-DevTools [1]. One really cool feature of this custom action is that it detects when the version number of your package has changed and won't attempt to publish if it hasn't. Kudos to the author(s)!

Summary: Package version changed + push to master = new version of our package is published to npm.

Notice the "if: ${{ github.event_name != 'pull_request' }}" portion of this command. We don't want runs triggered by pull requests to publish new versions, just the ones triggered by pushes to master. That "if" is what keeps this step from executing on PR runs.

IMPORTANT:

The variables defined in the command under "with" need some attention.

  • If your built project's package.json isn't at "./dist/package.json", you'll want to update that line accordingly.

  • Remove the comment from the registry line if you're using a private registry (the one in the given comment is for the GitHub registry).

  • You're also going to need to add a project secret called, "NPM_TOKEN."

    • Go to your project's secrets page at https://github.com/{user or org name}/{project name}/settings/secrets/actions and add a secret called "NPM_TOKEN". The value of that token depends on the registry you're publishing to.

    • If your package is in the npm registry you can get a token by going to https://www.npmjs.com/settings/{your user name}/tokens/create, choosing the "automation" type and clicking, "Generate Token."

    • If your package is in the GitHub registry go to https://github.com/settings/tokens and create a personal access token (PAC) with the "write:packages" permission.

Conclusion

That's it! No more locally running npm login or npm publish. Now your project's contributors can just follow whatever normal workflow is in place and once changes with a version bump hit master, they'll get published.

Credits

  1. JS-DevTools