You might want to setup a ci for your monorepo. In this article we will see how to use CircleCI inside a mono-repository. This post assumes that you already have knowledge about monorepo and continuous integration process with CircleCI.
We will use the version 2.0 of the CircleCI API. In this version they allow you to trigger a workflow from an API call. Now you are able to have different workflows between each project inside your monorepo. The main idea here is to trigger workflows based on boolean parameters that you enable or not.
In this article we will not focus on what we exactly do inside our ci and best practices inside circleci. We will only focus on the way we are triggering workflows. You can take a look at the final result on github here.
In your file .circleci/config.yml you can define parameters. They are just variables that you can access inside this file. When you trigger CircleCI for this project you can change the value of these parameters.
```yamlversion: 2.1
parameters: # By default we enable the main workflow trigger: type: boolean default: true
# Add a boolean parameter on each package. core: type: boolean default: false
components: type: boolean default: false```
- We specify the
triggerparameter totrue. It will be the boolean that triggers or not the main workflow. - We've also added one parameter per package (
coreandcomponents), by default set tofalse.
Now we've defined parameters. Based on the value of these variables we can enable or not workflows inside our continuous integration process.
Let's look at the workflow configuration part of .circleci/config.yml. We have three different workflows:
ciwhich is the main workflow. It will install dependencies of packages and have the responsibility to trigger other workflows.coredefines the workflow of thecorepackage.componentsdefines the workflow of thecomponentspackage.
```yamlworkflows: version: 2
# The main workflow will trigger other workflow based on your changes trigger: when: << pipeline.parameters.trigger >> jobs:
- trigger-workflows
- new_version: requires:
- trigger-workflows filters: branches: only:
- master
# Workflows defined for each package. core: when: << pipeline.parameters.core >> jobs:
- lint: package_name: core
components: when: << pipeline.parameters.components >> jobs:
- test: package_name: components
- lint: package_name: components```
You can notice that we have a condition to trigger each of them with the when condition. The condition needs to match with the parameter variable defined previously. This is why we have when: << pipeline.parameters.components >> to trigger the components workflow.
In this part we will look at how we trigger different workflows on the monorepo. Here is the job trigger-workflows:
```yamljobs: trigger-workflows: executor: node steps:
- run: name: Trigger workflows command: node ./circleci.js```
trigger-workflows only runs a javascript file which takes care of triggering workflows. Here is circleci.js:
```javascriptconst fetch = require('node-fetch');const { exec } = require('child_process');
const modules = ['core', 'components'];
exec('npx lerna changed --all', (error, stdout) => { modules.forEach(name => { if (!stdout.includes(name)) return;
const params = { parameters: { [name]: true, trigger: false, }, branch: process.env.CIRCLE_BRANCH, };
fetch( https://circleci.com/api/v2/project/github/${process.env.CIRCLE_PROJECT_USERNAME}/${process.env.CIRCLE_PROJECT_REPONAME}/pipeline, { body: JSON.stringify(params), headers: { Authorization: `Basic ${Buffer.from( process.env.CIRCLE_TOKEN ).toString('base64')}`, 'Content-Type': 'application/json', }, method: 'POST', } ) .then(console.log); });});```
In this file:
- We execute the command
npx lerna changed --allto see packages that have changed. - We take the output of that command to see which package changed.
- For each package that changed, we trigger the CircleCI API and tell it to execute the workflow that corresponds to the name of our package. We also set
triggertofalseso the base CI will not be executed.
A few notes:
CIRCLE_TOKENis your personal token that allows you to trigger workflows.CIRCLE_PROJECT_USERNAMEandCIRCLE_PROJECT_REPONAMEare injected by CircleCI so we do not have to care about it.
That's it! You see how to create different workflows and trigger them into your mono-repository. I've added a simple example on github here. The goal of this example is to focus on the way we trigger workflows for a monorepo and not what we are doing inside the workflows. Once you see how to make a workflow for a monorepo you can easily adapt that to your continuous integration needs.
