When a Build is not a Build

In my experience, the best way to learn a new software system is to see how it is built. That path lead me to some warnings housekeeping, which lead me to a weird issue with Azure DevOps.


In starting my new role, I have been trying to get a lay of the land. That includes cloning repositories, configuring authentication, and getting local builds running. As I was doing that, I noticed some build warnings.

Now, I will be the first to admit, in the physical world, I am not a “neat freak.” But, in my little digital world, I appreciate a world of builds free of warnings, unit tests where appropriate, and a well-organized distribution system.

So with that, I spent a little time fixing the build warnings or entering new technical debt tickets for them to be addressed at a later date. I also spent some time digging into the build process to start making these more apparent to the teams.

Where are the Warnings?

In digging through our builds, I noticed that none of them listed the warnings that I was seeing locally. I found that odd, so I started looking at my local build to see what was wrong.

And I did, in fact, find some issues with my local environment. After some troubleshooting, I literally deleted everything (Nuget caches and all my bin/obj folders), and it did get rid of some of the warnings.

However, there were still general warnings that the compiler was showing that I was not seeing in the build pipeline. I noticed that we were using the publish command of the DotNetCoreCli@2 task to effectively build and publish the projects, creating build artifacts. Looking at the logs for those publish tasks, I saw the warnings I expected. But Azure DevOps was not picking them up in the pipeline.

Some Google searches led me to this issue. As it turns out, it is a known problem that warnings output using the publish command do not get picked up by Azure DevOps. So what do we do?

Build it!

While publish does not output the warnings correctly, the build command for the same task does. So, instead of one step to build and publish, we have to separate:

- task: DotNetCoreCLI@2
  displayName: 'Build Project'
    command: 'build'
    publishWebProjects: false
    projects: '${{ parameters.project }}'
    ${{ if eq(parameters.forceRestore, true) }}:
      arguments: '-c ${{ parameters.configuration }}'
    ${{ else }}:
      arguments: '-c ${{ parameters.configuration }} --no-restore' 

- task: DotNetCoreCLI@2

  displayName: 'Publish Project'
    command: 'publish'
    publishWebProjects: false
    nobuild: true
    projects: '${{ parameters.project }}'
    arguments: '-c ${{ parameters.configuration }} --output ${{ parameters.outputDir }} --no-build --no-restore' 
    zipAfterPublish: '${{ parameters.zipAfterPublish }}'
    modifyOutputPath: '${{ parameters.modifyOutputPath }}'

Notice in the build task, I have a parameter to optionally pass --no-restore to the build, and in the publish I am passing in --no-build and --no-restore. Since these steps are running on the same build agent, we can do a build and then a publish with a --no-build parameter to prevent a double build scenario. Our pipeline also performs package restores separately, so most of the time, a restore is not necessary on the build. For the times that it is required, we can pass in the forceRestore parameter to configure that project.

With this change, all the warnings that were not showing in the pipeline are now showing. Now it is time for me to get at fixing those warnings!