Validate C# project file against a template during build - continuous-integration

I know that you can create a template project to ensure that certain required settings (for ex: code analysis, treat warnings as errors, platforms, etc.) are set in a new project.
I want to enforce this as a part of the CI process i.e. in the build I want to validate the C# project files against a template (or an XML file) and cause a build failure if the project files don't conform to it. I need suggestions and ideas on how this can be achieved.
I want to try this with TFS 2010 and VS 2010.

I am writing a custom task to search for all the C# project files and compare the Xml structure of the Template project file with the Actual project file and report any difference as error.

I usually tackle this by customizing my build process to run Code Analysis/StyleCop/etc against all projects regardless of project settings.
Likewise for Treat Warnings as Errors. I just override the proejct settings at the build-level so that no matter what people do to the projects I know that everything I want to run is being run at build time.

Related

How can I make msbuild understand that a .csproj file depends on the availability of an exe built by another .csproj

I have a large VStudio solution whose .csproj files I'm porting over to the new .NET SDK format. I have integrated the github project with AppVeyor. When I work on the solution, my project is built by VStudio; AppVeyor uses msbuild to build my project.
All of the class library project files in the solution have been modified so that they specify <TargetFrameworks>netStandard2.0</TargetFrameworks>. For simplicity, let's represent the class library project files with classlib.csproj.
The solution also contains a few command-line tools, which need to be built in advance of some of the other projects, because those later projects need to run the command-line tools as a preprocessor before building themselves. These command-line projects are all specifying <TargetFrameworks>net472;netcoreapp2.0</TargetFrameworks>. Let's represent the tool project files with tool.csproj.
In order to build correctly, tool.csproj needs to be built before classlib.csproj. In the solution I've used the Build dependencies > Project dependencies command in the VStudio solution explorer to indicate this. This works fine when I'm working inside of VStudio.
However, when I push my changes to github, AppVeyor kicks off an msbuild process to build the projects. From the error spew, it's clear that the tool.csproj didn't get built in time. It seems msbuild doesn't understand the project dependency information in the .sln file.
Reading what's posted on the intertubes (e.g. https://devblogs.microsoft.com/visualstudio/incorrect-solution-build-ordering-when-using-msbuild-exe/), I attempted to add the following to classlib.csproj:
<ProjectReference Include="..\tool\tool.csproj">
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>
But when I do this I get the error:
Project '..\tool\tool.csproj' targets 'net472;netcoreapp2.0'. It cannot be referenced by a project that targets '.NETStandard,Version=v2.0'
which clearly makes sense.
Some other solutions I've read suggest editing the .sln file so that tool.csproj gets built first, and hope that building will be completed before classlib.csproj starts building. However, this is a race condition since msbuild is not aware of the dependency.
How, then, do I express that classlib.csproj depends on tool.csproj so that msbuild understands it?
EDIT
It turns out the issue was caused by an interaction between the target I'd written to start my tool and the globbing operation MSBuild does to resolve the <Compile> item collection using a pattern similar to **\*.cs. The tool generated the file after the globbing operation. Since the generated file isn't present when the globbing happens, it is missing from the <Compile> item collection, and the build failed. I mistakenly interpreted the error "foo.cs not found" as a failure to execute the tool, when in fact, it's a timing issue.
To make the build order works outside VS IDE, we need to use add reference
instead of BuildDependencies=>ProjectDependencies.
Right-click classlib project and choose add=>reference, in Project node choose the Tool Project you want like this:
Click ok to add it and save changes. After that, open the classlib.csproj you can find sentence like:
<ItemGroup>
<ProjectReference Include="..\xxx\Tools.csproj">
<Project>{6eaa430f-9793-4639-a84b-6ab767d57147}</Project>
<Name>Tools.csproj</Name>
</ProjectReference>
</ItemGroup>
This what the msbuild can understand. And I think that's what you want.
After that,you can use a single msbuild tool or Appveyor to check the
build order.
And in Appveyor, we can also disable the paralell builds(settings=>build=>msbuild options) to make sure it won't build classlib.csproj until the tools.csproj build ends.
The final build order in Appveyor will be what we defined in VS. Hope it helps.

Is it possible to change the configuration of visual studio according to the startup project?

I am having one solution with multiple projects.
I am basically creating building blocks to build more complicated projects later on. These projects are sometimes dependent on one another, thought I am trying to keep it losely coupled.
It is sometimes necessary to debug one of the projects to test whether certain functions actually behave the way they should. ( I am going to create test projects for each individual project in the future. ).
Since they are all .lib files, everytime I make a certain project the startup project to test it, I need to switch the configuration properties to create a .exe file otherwise it wont run.
Is there a way to change the configuration of your projects based on what project is the startup project? So that I can instantly run this instead of manually changing the properties everytime I take a differnt startup project.
Your plan won't work the way you want. But I suppose you could add an extra project that can load the correct lib file and launch it. Then in the debug settings of each lib project specify that debugging will launch your extra project with the path to the lib to load as an argument.
It will require a small custom project, but will make your life easier. It'll look something like this in the debug settings:

Different preprocessor directives within one solution configuration

In one of our projects, we adapt parts of our software to specific customer requirements (logos and about boxes, for example). Each of the customers gets its own release which does not include specifics of another customer. Currently this is implemented with preprocessor directives and separate build configurations for each of the customers. However as the number of projects in solution is increasing, it is getting hard to maintain these configuration (and it is getting messy, too). In essence, all configurations are "Release" builds named "Release X", "Release Y", "Release Z". They are all the same, except one preprocessor directive for distinguishing between customer builds (for example, to use proper application icon). Furthermore, the configurations must be the same, to provide consistency across builds.
For the build on build server I can create a MSBuild script, set the "DefineConstants" property and build the solution in "Release" configuration.
What about doing the same in Visual Studio? I want the developers to be still able to run builds for specific customers locally (for debugging / testing purposes), but I really want to get rid of configurations for specific customer. Because if I change something in release build, it is not propagated directly to customer specific builds and I have to do it again for every one of them.
Any ideas how to simplify these builds?
I don't fully understand all of the things you are needing to separate by customer but I have a similar challenge and here is how I solved it:
1) If there absolutely positively have to be code differences then you can use preprocessor directives to separate the code.
2) You can run a build helper in a Pre-Build Event that writes a header file with customer specific definitions.
3) Use WiX/heat.exe to assemble any customer specific build artifacts like graphics and such.
Let me explain, what I did to achieve my goals. I use preprocessor directives to separate the code. The trick is where they are defined. Under VS I load them from configuration file, on automated builds (TFS) they are set in build script.
Now I only have two project configurations, Debug and Release. Everything else (customer specific builds, code analysis build, etc) is controlled by preprocessor directives. For the server build I have separate .proj file which sets the appropriate constants and builds the .sln file. Each .csproj includes additional build script (via Include statement) in which I first override project properties to ensure all projects have the same settings (i.e. for Debug builds I set DebugSymbols=true).
In this script I also load the preprocessor directives from the file before the compilation of source is started.

Visual Studio 2010: How can I build a project and not its dependencies?

I want to be able to build a web project and not its dependencies since I know that I have not modified any of the dependencies since the last build. I am looking to cut down the build time if possible. Is there a way to do this?
You could have a solution by
check the setting in Tools >> Options >> Projects and Solutions >>
Build and Run setting : Only build startup projects and dependencies on Run.
OR
If you want to go for sophistication then :
build >> Configuration Manager
from the "Active solution configuration:" dropdown select ""
give a name to your configuration and keep checked the "Create new project configurations" checkbox.
and then choose that config that you want and set the build or not check boxes.
To accomplish this in something I am working on, I created my own solution, added the projects I needed (including the projects I never wanted compiled), and then in the Configuration Manager turned off the check boxes for building the projects I didn't want to build, just as arora described above.
I've also made a copy of an existing solution (that had 16 components in it), saved it under new name (foo.sln -> foo.mine.sln), and then disabled the build of all the other sub-projects except the one(s) I am working on, that way I know for sure that I got the correct build settings.
It's not the simplest solution, but it works well for me, and takes less than 2 minutes to set up and is easy to understand. I normally add the new solution to the version control ignore list so that it never gets checked in.
Rather than project references you can just add the references to the dlls directly (the Add Reference dialog has tabs for these types, choose browse rather than project and remove the other projects from your solution). I typically create a full lib and web project solution for major development. Then just a solution for the website project for fixes where I don't need updated libs/dlls.
Although it is nice to have them autocompile if they have changed during heavy development. If they haven't changed it just refreshes them and recopies them to the bin folder.
Well one way would be to remove project references. Instead stick to dll references. You could use a post build script for dependent projects that copy the updated dll to the web project whenever they change.

Best practice to integrate custom build tasks in Visual Studio 2008 Project/Solution

To increase the automated part of our build/release process, I would like to integrate some custom tasks in our visual studio projects. What's the best way to organize such solutions? The main problem is: If I add the project implementing the tasks to the solution, the tasks are cached by the visual studio instance. So a rebuild does not work, because the output assemblies of the task project cannot be overwritten.
I can put the task in a separate solution. Seems to be the best (only?) option, but I don't like to maintain two solutions. This makes continous integration more complicated.
Any hints? How do you manage solutions having project specific custom build tasks?
If the custom build tasks refer to some documents included in the solution, then you can make a custom build rules document, refer it in your solution and specify the custom build name for each document in the properties (this will spare you on writing command, dependencies and everything for each document, if the rule is specified correctly using the macros like $(InputPath), etc.)
If the custom build tasks refer to some operations that are not related to documents in solution, you can have them specified as commands in the post build event of the project in the solution that needs it. Another alternative can be to add a new, dummy project in the solution that will have only this post build event, dependent on all the other projects (so the post build tasks will be called only after all the other projects were built).

Resources