-2

We have a large repo that contains many C# projects but we would only like to build the projects where a change was committed. So if a Change was committed to Project A, then it will only build Project A and not all the projects in the solution.

Is this possible using Jenkins?

Thanks in advance.

Ryan Blake
  • 79
  • 7

2 Answers2

0

Yes, it is possible. But, you'll have to configure all the projects as separate jobs in Jenkins.

Vighnesh Pai
  • 1,795
  • 1
  • 14
  • 38
0

We did exactly this in a solution with over 165 projects grouped into 30 individual services and web applications. However instead of building a specific project with msbuild we created individual solutions based on the respective service and web application domain. The result were solutions like JenkinsBuild_Project1.sln and JenkinsBuild_Project2.sln.

https://stackoverflow.com/a/19534376/3850405

The code below can be modified to use msbuild instead with minor changes.

Jenkinsfile:

#!groovy
import groovy.json.*
pipeline {
    agent {
        node {
            label 'msbuild'
        }
    }

    environment {
        OCTOPUS_PUBLISH_KEY = credentials('OctoPackPublishApiKey')
        //Global variable where we save what to build
        BUILD_LIST =''
    }

    stages {
        stage('What to build?') {
            steps {
                script {

                    GIT_DIFF = bat (
                        script: 'git diff --name-status HEAD..HEAD~1',
                        returnStdout: true
                    ).trim()
                    echo "From batscript: ${GIT_DIFF}"
                    //Environment variable values must either be single quoted, double quoted, or function calls and therefore a json string is used to save the array
                    //https://stackoverflow.com/a/53745878/3850405
                    BUILD_LIST = new JsonBuilder(whatToBuild("${GIT_DIFF}")).toPrettyString()
                    echo BUILD_LIST
                }
            }
        }
        stage('Prepare') {
            steps {
                script {
                    def buildList = new JsonSlurper().parseText(BUILD_LIST)
                    for (i = 0; i < buildList.size(); i++){
                        bat "C:\\Program\\NuGet\\nuget_4.4.1.exe restore Source\\${buildList[i]}\\${buildList[i]}.sln"
                    }
                }
            }
        }
        stage('Build') {
            steps {
                script {
                    def buildList = new JsonSlurper().parseText(BUILD_LIST)
                    for (i = 0; i < buildList.size(); i++){
                        bat "\"${tool 'Build Tools 2019'}\" /t:Clean;Build /p:Configuration=JenkinsBuild JenkinsBuild\\JenkinsBuild_${buildList[i]}.sln"
                    }
                }
            }
        }
        stage('Publish') {
            when {
                anyOf { 
                    branch 'master';
                }
            }
            steps {
                script {
                    def buildList = new JsonSlurper().parseText(BUILD_LIST)
                    for (i = 0; i < buildList.size(); i++){
                        bat """\"${tool 'Build Tools 2019'}\" ^
                        /t:Build ^
                        /p:Configuration=JenkinsBuild ^
                        /p:RunOctoPack=true ^
                        /p:OctoPackEnforceAddingFiles=true ^
                        /p:AllowedReferenceRelatedFileExtensions=none ^
                        /p:OctoPackNuGetProperties=env=${env.BRANCH_NAME};change=${env.CHANGE_ID} ^
                        /p:OctoPackPackageVersion=2.1.${BUILD_NUMBER}-${env.BRANCH_NAME}1 ^
                        /p:OctoPackPublishPackageToHttp=https://OurOctopusServer:1337/nuget/packages ^
                        /p:OctoPackPublishApiKey=${env.OCTOPUS_PUBLISH_KEY} ^
                        JenkinsBuild\\JenkinsBuild_${buildList[i]}.sln"""
                        }
                }
            }
        }
    }
    post {
        always {
            //Clean and notify
        }
    }
}

Groovy script that takes a file list from git command git diff --name-status HEAD..HEAD~1 and filters out unique project values like Project1 and Project2 from paths like below.

/Source/Project1/Project1.Data/Properties/AssemblyInfo.cs /Source/Project2/Project2.Clients.WinService/Services/Project2.Designer.cs

whatToBuild.groovy:

#!/usr/bin/env groovy

def call(String fileList) {
    println "Printing filelist in whatToBuild()"
    println fileList
    def lines = fileList.tokenize('\n')
    println lines
    def list = []
    lines.eachWithIndex{ value, key -> 
        println "Printing value"
        println value
        if (value.contains("Source")) {
        def result = value =~ /Source\/([A-Z]*)\//
        println "Printing result"
        println result[0][1]
        list.add(result[0][1])
        }
    }
    def listUnique = list as Set
    println listUnique
    return listUnique
}
Ogglas
  • 62,132
  • 37
  • 328
  • 418