<p>How it should look like:</p>

<ol>
<li>Commit changes in some microservice and push it to VCS origin repo</li>
<li>CI system sees new commit</li>
<li>CI starts build and tests</li>
<li>If everything's good, it pushes image to docker registry with tags</li>
</ol>

<p>So, the answer is: CI should know, what service has changes.</p>

CC BY-SA 4.0
2018-09-16T13:31:39.950Z
Hi @chupasaurus, how CI would know? I would have to make different build scripts for different branches?
Renato Pereira
CC BY-SA 4.0
2018-09-16T14:02:29.503Z
@renatogbp CI should have triggers for commits.
chupasaurus
CC BY-SA 4.0
2018-09-16T14:12:30.057Z
I know it has triggers, but it will be based on the default job. My solution file includes 4 microservices. If I add a new commit, the job will build the whole solution and publish all 4 images again, even though I had changed only one microservice
Renato Pereira
CC BY-SA 4.0
2018-09-16T14:16:34.353Z
Microservices should be independent to each other so you could separate build/deploy pipelines for each one.
chupasaurus
CC BY-SA 4.0
2018-09-16T14:21:13.347Z
Hmm, so that means I should have a VCS origin repo for each microservice? And also one repo for the gateway?
Renato Pereira
CC BY-SA 4.0
2018-09-16T15:02:46.463Z
It's a most common way. There are companies which use monorepo, but one have to add the script in the build pipeline to detect which projects are changed.
Dunno what you're calling the "gateway".
chupasaurus
CC BY-SA 4.0
2018-09-16T16:22:59.727Z
We have a gateway that does the routing between the clients and the microservices. We use Ocelot with the BFF (backend-for-frontend) approach
Renato Pereira
CC BY-SA 4.0
2018-09-16T19:44:22.350Z
You should add a service discovery to cover up the configuration steps. With quick lurking through Ocelot docs, Consul is well supported.
chupasaurus
CC BY-SA 4.0
2019-01-02T19:42:10.783Z
One repo per deployable is best and is most widely supported by build tools. Historically source control systems at big companies with “enterprise” (aka broken) processes to get access to the code, or that needed a sysadmin to create a new repo, forced monster (aka mono) repos. Anyone that doesn’t face those historic pains shouldn’t be using a monster repo. The disadvantages of a monster repo are performance, git tags of releases applying to the whole repo not the one service release, having to make custom code to deploy only one service, noisier git log, a noisier issue tracker, ...
simbo1905
CC BY-SA 4.0
2018-09-16T13:26:16.157Z
2018-09-16T13:26:16.157Z
chupasaurus
<p>@chupasaurus gave an answer based on a multi-repo solution. </p>

<p>Based on this <a href="https://stackoverflow.com/a/45507614/3223737">answer</a>, I came up with the following jenkins pipeline approach. I've decided to build and test the whole solution, but you can use the same approach from "Push Image" stage to build and test only the changed services.</p>

<pre><code>pipeline {
agent any
environment {
    CHANGES = getChangeLog()
}
stages {
    stage('Build') {
        steps {
            bat 'dotnet clean solutionFile.sln'
            bat 'dotnet build solutionFile.sln'
        }
    }
    stage('Test') {
        steps {
            bat 'dotnet test solutionFile.sln --no-build --logger:trx;LogFileName=results.trx'
            // parse tests
        }
    }
    stage('Push Image') {
        stage('serviceA') {
            when {
                allOf {
                        expression {
                            hasChanged = powershell(returnStdout: true, script: '"$env:CHANGES" -like "*serviceA*").trim() // check if any file path contains "serviceA"
                            return  hasChanged == "True" 
                        }
                        branch 'master'
                }                        
            }
            steps {   
                // set tag or use latest by default from docker-compose      
                bat 'docker-compose build serviceA.api'
                bat 'docker-compose push registry/serviceA.api'
            }
        }
    }
    stage('Deploy Image') {
        stage('serviceA') {
            // deploy image code
        }
    }
}

def getChangeLog(){
    def changes = ""
    build = currentBuild
    while(build != null &amp;&amp; build.result != 'SUCCESS') {
        changes += "In ${build.id}:\n"
        for (changeLog in build.changeSets) {
            for(entry in changeLog.items) {
                for(file in entry.affectedFiles) {
                    changes += "${file.path}\n"
                }
            }
        }
        build = build.previousBuild
    }
    echo changes
    return changes
}
</code></pre>

<p>This code isn't fully tested, I just wanted to give a practical approach.</p>

CC BY-SA 4.0
2019-01-02T19:42:36.727Z
does the code work?
simbo1905
CC BY-SA 4.0
2018-10-03T22:04:31.603Z
2018-10-03T22:04:31.603Z
Renato Pereira
<p>I am starting to use Continuous Integration on my microservices solution (monorepo approach), and I am referencing this <a href="https://devops.stackexchange.com/a/3342/9772">post</a> for versioning approach. </p>

<p>But, let's say I make some change in one of the microservice and commit that change, but all the others are exactly the same. How the process would know that those microservices (docker images) weren't changed so don't need to increase the build number? I feel like I would end-up with many docker images with different build numbers but same content.</p>

<p>Am I misunderstanding the concept? Sorry, this whole microservices and docker thing are pretty new to me.</p>

CC BY-SA 4.0
2018-09-16T06:51:41.987Z
Hi @renatogpb, welcome to SO. The whole idea behind micro-services is that you could make changes in one of them and deploy just that, without affecting other parts of your infrastructure. Could you please go into more detail about how your CI works ? Which process are you referring to ?
vishnu narayanan
CC BY-SA 4.0
2018-09-16T12:50:16.923Z
Hi @vishnunarayanan, thanks! So I didn’t implement the actually CI yet, but I was thinking about doing: checkout repository, build de images using “docker-compose -d —build” (I would set some environment variable to replace {$TAG} of the images, and then “docker push”. So, I know what microservices I made the change, but the CI doesn’t know. That’s why I am building all the images. How can I make the CI know about which one I’ve changed?
Renato Pereira
CC BY-SA 4.0
2019-01-02T19:16:26.307Z
Mono repo is a bit of an anti-pattern. As you point out if you make a git tag to release one microservice all of the code has the same tag even if it not deployed in that state. With git it’s more natural to group a system as a organisation and have a repo per deployable (either a service or a library).
simbo1905
<docker><containers><microservices>
Automated tag versioning on unchanged docker images
Renato Pereira
# Automated tag versioning on unchanged docker images

(Asked by: username_0 on 2018-09-14)

I am starting to use Continuous Integration on my microservices solution (monorepo approach), and I am referencing this [post](https://devops.stackexchange.com/a/3342/9772) for versioning approach.

But, let's say I make some change in one of the microservice and commit that change, but all the others are exactly the same. How the process would know that those microservices (docker images) weren't changed so don't need to increase the build number? I feel like I would end-up with many docker images with different build numbers but same content.

Am I misunderstanding the concept? Sorry, this whole microservices and docker thing are pretty new to me.

**Tags:** docker, containers, microservices

> **Comments:**
> **username_1**: Hi @renatogpb, welcome to SO. The whole idea behind micro-services is that you could make changes in one of them and deploy just that, without affecting other parts of your infrastructure. Could you please go into more detail about how your CI works ? Which process are you referring to ?  
> **username_0**: Hi @vishnunarayanan, thanks! So I didn’t implement the actually CI yet, but I was thinking about doing: checkout repository, build de images using “docker-compose -d —build” (I would set some environment variable to replace {$TAG} of the images, and then “docker push”. So, I know what microservices I made the change, but the CI doesn’t know. That’s why I am building all the images. How can I make the CI know about which one I’ve changed?  
> **username_2**: Mono repo is a bit of an anti-pattern. As you point out if you make a git tag to release one microservice all of the code has the same tag even if it not deployed in that state. With git it’s more natural to group a system as a organisation and have a repo per deployable (either a service or a library).  

---

## 2 answers

### Answer by username_3 on 2018-09-16. Score: 1

How it should look like:

1. Commit changes in some microservice and push it to VCS origin repo
2. CI system sees new commit
3. CI starts build and tests
4. If everything's good, it pushes image to docker registry with tags

So, the answer is: CI should know, what service has changes.

> **Comments:**
> **username_0**: Hi @username_3, how CI would know? I would have to make different build scripts for different branches?  
> **username_3**: @renatogbp CI should have triggers for commits.  
> **username_0**: I know it has triggers, but it will be based on the default job. My solution file includes 4 microservices. If I add a new commit, the job will build the whole solution and publish all 4 images again, even though I had changed only one microservice  
> **username_3**: Microservices should be independent to each other so you could separate build/deploy pipelines for each one.  
> **username_0**: Hmm, so that means I should have a VCS origin repo for each microservice? And also one repo for the gateway?  
> **username_3**: It's a most common way. There are companies which use monorepo, but one have to add the script in the build pipeline to detect which projects are changed. Dunno what you're calling the "gateway".  
> **username_0**: We have a gateway that does the routing between the clients and the microservices. We use Ocelot with the BFF (backend-for-frontend) approach  
> **username_3**: You should add a service discovery to cover up the configuration steps. With quick lurking through Ocelot docs, Consul is well supported.  
> **username_2**: One repo per deployable is best and is most widely supported by build tools. Historically source control systems at big companies with “enterprise” (aka broken) processes to get access to the code, or that needed a sysadmin to create a new repo, forced monster (aka mono) repos. Anyone that doesn’t face those historic pains shouldn’t be using a monster repo. The disadvantages of a monster repo are performance, git tags of releases applying to the whole repo not the one service release, having to make custom code to deploy only one service, noisier git log, a noisier issue tracker, ...  

---

### Answer by username_0 on 2018-10-03. Score: 0

@username_3 gave an answer based on a multi-repo solution. 
Based on this answer, I came up with the following jenkins pipeline approach. I've decided to build and test the whole solution, but you can use the same approach from "Push Image" stage to build and test only the changed services.
pipeline {
agent any
environment {
    CHANGES = getChangeLog()
}
stages {
    stage('Build') {
        steps {
            bat 'dotnet clean solutionFile.sln'
            bat 'dotnet build solutionFile.sln'
        }
    }
    stage('Test') {
        steps {
            bat 'dotnet test solutionFile.sln --no-build --logger:trx;LogFileName=results.trx'
            // parse tests
        }
    }
    stage('Push Image') {
        stage('serviceA') {
            when {
                allOf {
                        expression {
                            hasChanged = powershell(returnStdout: true, script: '"$env:CHANGES" -like "*serviceA*").trim() // check if any file path contains "serviceA"
                            return  hasChanged == "True" 
                        }
                        branch 'master'
                }                        
            }
            steps {   
                // set tag or use latest by default from docker-compose      
                bat 'docker-compose build serviceA.api'
                bat 'docker-compose push registry/serviceA.api'
            }
        }
    }
    stage('Deploy Image') {
        stage('serviceA') {
            // deploy image code
        }
    }
}

def getChangeLog(){
    def changes = ""
    build = currentBuild
    while(build != null && build.result != 'SUCCESS') {
        changes += "In ${build.id}:\n"
        for (changeLog in build.changeSets) {
            for(entry in changeLog.items) {
                for(file in entry.affectedFiles) {
                    changes += "${file.path}\n"
                }
            }
        }
        build = build.previousBuild
    }
    echo changes
    return changes
}

This code isn't fully tested, I just wanted to give a practical approach.

> **Comments:**
> **username_2**: does the code work?  

---

