DEV Community

Cover image for GitHub Actions for Node Modules in a Monorepo
Jessie Barnett
Jessie Barnett

Posted on • Updated on • Originally published at jessie.codes

GitHub Actions for Node Modules in a Monorepo

One of the projects I have been working on uses a monorepo, where we have multiple frontend applications with shared private dependencies. We decided all of our shared node modules would live under one top-level folder to keep things organized. When it came time to set up our CI for the project, I found that writing some custom bash scripts was the easiest way to avoid setting up a workflow per module.

This strategy might not work well for you if you have quite a few private packages; however, since we only have a handful, I determined our best bet would be to have one workflow that ran anytime any of our packages were updated. As we keep all of our these packages under a folder named private_modules, I set the workflow to target anything with a path of private_modules/** and then had it run a custom shell script that could take in a yarn script to run. We're using yarn to manage our dependencies, but this should work with npm as well.

name: Private Packages

on:
  pull_request:
    paths: 
      - "private_modules/**"

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [12.x]
    steps:
    - uses: actions/checkout@v1
    - name: Use Node.js ${{ matrix.node-version }}
      uses: actions/setup-node@v1
      with:
        node-version: ${{ matrix.node-version }}
    - name: yarn install and test
      run: |
        cd private_modules
        ./yarn_run.sh test

As you've seen, all we have to do without our workflow file is cd into the top-level directory and run our bash script. If you need to run more than one yarn command, you can either add a new step for each command or update the bash script to take multiple commands.

The bash script itself is straight forward. It will loop through all of the subdirectories within the folder, install any dependencies, and then run the yarn script specified in the arguments. This way, we could use it for all of our CI steps, whether it be linting, testing, or publishing.

#!/bin/bash

CMD=$1

dir_resolve()
{
cd "$1" 2>/dev/null || return $?
echo "`pwd -P`"
}

for dir in ./*/
do
    (
      abs_path="`dir_resolve \"$dir\"`"
      echo "Installing $abs_path"
      cd $abs_path
      yarn install
      yarn run $CMD --max-warnings=0 2>/dev/null
      if [ $? -ne "0" ]
      then
        exit 1
      fi
    ) || exit 1
done

Using this bash script has kept our workflows both easy to manage and maintain. The main thing to keep in mind is that every package will need to have the yarn command configured that you intend to pass into the bash script, or the script will fail.

Originally published on jessie.codes

Top comments (0)