How to manage Monorepos within a Jenkinsfile in CloudBees CI

Issue

  • How to manage Monorepos within a Jenkinsfile in CloudBees CI? When you have a repository consisting of multiple components, how can you set up a Pipeline that tests each of them separately whenever there has been a change in the code?

Environment

Resolution

The main idea behind it is using built-in conditions for different modules from a monorepo when { changeset “**path/to/module-example/.” }

For instance, imagine that your monorepo consists of three modules: frontend, backend/web and backend/api

. (monorepo-example)
├── backend
│   ├── api
│   └── web
├── frontend
└── Jenkinsfile

A valid Jenkinsfile would be similiar to:

pipeline {
    agent none
    stages {
        stage('Build Frontend') {
            agent { docker { image 'my-node-agent' } }
            when {
                changeset "**/frontend/*.*"
                beforeAgent true
            }
            steps {
                dir('frontend') {
                  sh 'npm install'
                  sh '...'
                }
            }
        }
        stage('Build Web') {
            agent { docker { image 'my-maven-agent' } }
            when {
                changeset "**/backend/web/*.*"
                beforeAgent true
            }
            steps {
               dir ('backend/web') {
                sh 'mvn -B -DskipTests clean package'
                sh '...'
               }
            }
        }
        stage('Build REST API') {
            agent { docker { image 'my-golang-agent' } }
            when {
                changeset "**/backend/api/*.*"
                beforeAgent true
            }
            steps {
               dir ('backend/api') {
                 sh 'go build'
                 sh '...'
               }
            }
        }
    }
}

Alternatively, you could replace this section:

...
    stage('Build Frontend') {
        agent { docker { image 'my-node-agent' } }
        when {
            changeset "**/frontend/*.*"
            beforeAgent true
        }
        steps {
            dir('frontend') {
                sh 'npm install'
                sh '...'
            }
        }
    }
...

by loading a Jenkinsfile per module which is stored in your Shared Library. Refer to Share a standard Pipeline across multiple projects with Shared Libraries.

@Library("shared-libs@main") _
...

    stage('Build Frontend') {
        when {
            changeset "**/frontend/*.*"
            beforeAgent true
        }
        steps {
            frontEndPipeline {
                agent = 'my-node-agent'
                serverPort = '8080'
                developmentServer = 'dev-myproject.mycompany.com'
                stagingServer = 'staging-myproject.mycompany.com'
                productionServer = 'production-myproject.mycompany.com'
            }
        }
    }
...

Whenever the changelog of any of the modules is not empty, i.e.: recent changes have been pushed to the component, the job build will execute the stage defined for it. Please note that if the pipeline is run right after its definition, the build will not trigger any of the tasks defined, as the changelog will be empty. A warning message like this will appear:

Warning, empty changelog. Probably because this is the first build.

Similarly, if the pipeline is executed without recent changes made to the monorepo, all stages in the job will be skipped with the following message:

Warning, empty changelog. Have you run checkout?

In case you get the warning above after actually having made changes to the module, check that the pipeline source is correctly configured and that the updates were committed to the same branch that is used in the job definition.

Have more questions?

0 Comments

Please sign in to leave a comment.