tldr;
Working in an Nx monorepo over the last year has been really great. Sharing code between projects is really convenient. The only problem is that as you add more libraries and applications and projects, the time it takes to build or test applications grows as well. The good thing is that Nx monorepos come with a variety of commands that run on only portions of the codebase. For example, if your change only affects one library in your project, you can test just that library instead of the entire project. This is especially useful on your CI/CD server when you create pull requests. Tests can be run on the pull request branch, making sure that any new code is working and that it didn’t break any previous portions of the app. In this post, we’ll go over how to create a GitHub Action workflow to run the affected tests when a pull request is created.
The Setup
In my situation, I have an Nx monorepo with two applications in it. There are a lot of libraries included as well. Some of the libraries are shared, and some are specific to the application. What I needed was a solution for running the nx affected:test
command when a pull request was created. This would run the tests for just those projects affected by the code changes. If the tests pass, the PR can safely be merged.
I first started to implement this using Google Cloud, as that is the product we use to build and deploy our applications at my full time job. I was never able to get it to work, though, because for nx
to work it needs the git history for the repo. I tried many solutions, but could never get the git history into the cloud build instance. My only solution was to run all the tests on each PR. This worked for a while, but as the repository has grown more tests and libraries have been added. Last week, the tests started timing out and wouldn’t finish. It no longer became a viable solution. Because of that, I came to GitHub Actions to try and solve the issue.
Creating Your GitHub Action
If you’ve never tried GitHub Actions before, you’ll find the process straightforward and convenient. Before creating your action, switch to a new branch in your repo. Next, create a .github
folder in the root of your repository, with a nested workflows
folder:
mkdir .github
mkdir .github/workflows
The yaml
files that we place inside the .github/workflows
folder will be run as GitHub Actions. In this case, the next step is creating a new yaml file, which I’ll call nx-affected.yml
. This file will define the steps for the action. I won’t go into all the details of each step; that’s more suited for another article. I will provide insight on the more important steps to accomplish our goals here, though. Here’s the full contents of the yaml file, after which we’ll break it down piece by piece.
name: Nx Affected CI
on:
pull_request:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [12.x]
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Use Node.js $
uses: actions/setup-node@v1
with:
node-version: $
- run: git fetch origin main
- run: npm install
- name: Run Affected Tests
shell: bash
run: npm run affected:test -- --base=remotes/origin/main
Let’s break this down piece by piece and explain what’s going on.
name: Nx Affected CI
on:
pull_request:
branches: [main]
At the top of the workflow yaml file we give our workflow a name. After that we determine when the workflow will be run. In this case, the workflow will run when pull requests are created for merging into the main branch. Other branches can also be targeted by being added to the array.
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [12.x]
The next part of the yaml file is the meat of the workflow. The first part I’ll point out is that we determine what operating system to use for the action with the runs-on
attribute. In this case, ubuntu-latest
. Next, the strategy
and matrix
attributes allow us to determine multiple versions of node to use for running the tests. This part is optional. You can choose just one version if you’d like, or select multiples. The action will run for each version of node that you provide in the array.
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Use Node.js $
uses: actions/setup-node@v1
with:
node-version: $
- run: git fetch origin main
- run: npm install
The steps
section of our workflow file is where we will accomplish the goal of the workflow. In other words we will prepare to run the tests and run them. These first three steps checkout the git repository into the context of the workflow. fetch-depth: 0
ensures that we get the full git history, which is necessary for running the nx affected
commands. The second step determines the node version to use (using our matrix
from the strategy
section above). The third step fetches the latest information from the main branch. We need that information because Nx runs compares the current branch to the main
branch to determine what has changed. The last step I’ve included here is to run npm install
. This ensures that all necessary packages are ready for the application to be built and tested.
- name: Run Affected Tests
shell: bash
run: npm run affected:test -- --base=remotes/origin/main
This last step is where we actually run the tests. We gave the step a name
, and specified the shell
to be used while running the tests. When this step runs, we run an npm command declared in the package.json
. This will run the Nx command that runs tests against projects that have changed between the branch of the pull request and the main
branch. The tests will be run, and if they are successful the workflow will end in a success status. If any tests fail, the workflow ends with a failure status. Both of these statuses will show on the pull request page in GitHub.
Running the Action
To test the action, push your changes to the repository and create a pull request using the branch that you did this work on, with the intent to merge it into main
. When you create the pull request, the action you just created will start running. You can see it in the repository. You can get there by clicking the “Actions” tab on the repository’s main page:
Once you’ve clicked on that tab, you’ll see a table of the actions that you’ve run in this repository. If the workflow is currently running, you’ll see a yellow circle. If it was unsuccessful, it’s marked with a red x. If it was successful, you’ll see a green check mark.
Clicking on one of the rows will show you the details of that action. It will show each step that was defined in your action and the logs that are pertinent to that step. Each time you create a pull request, or push updates to an existing PR, the tests will run.
Additional Information
You can use this same step, or duplicate it, to run other Nx affected commands, such as lint
, build
, or e2e
. They can all be run in a single workflow, as separate steps, or you can have one workflow for each of them. In addition, you could use an action to build your application in a Docker image and push the image to GitHub’s package registry (or another registry like Docker Hub). Here are a couple previous articles of mine that may help you out. In addition, here’s a reference to a post on Dev.to that I used to help me get started with testing affected projects in my Nx monorepo.
Top comments (0)