MSBuild RE: Enforcing the Build Agent in a Team Build
This is a post that responds to a post by Michael Ruminer at Enforcing the Build Agent in a Team Build. I hope I correctly understand his situation. Here is my summary of it.
- You have a specified value for the property BuildAgentName
- You create various MSBuild scripts that will hook into a TeamBuild
- You want to specify in each MSBuild script the names of the build agents that are allowed to run the build
- If the current value for BuildAgentName is not in the list above, fail the build otherwise allow it to continue
My solution to this problem is to create a property, AllowedBuildAgents, which will contain a semi-colon separated list of the allowed build agent names. Then this is converted into an item, AllowedBuildAgentsItem, so batching can be preformed over it. If you are not familiar with MSBuild batching you can see my previous postings at:
The main objective here is to create an item that contains all the allowed names, AllowedBuildAgentsItem, and batch over them. If the value for BuildAgentName is equal to any value in that item then we want to allow the build. I create a property BuildAgentAllowed which defaults to false, and if that condition is true then I set BuildAgentAllowed to true. So I created a target DetermineIfAuthorizedBuildAgent that depends will throw an error if BuildAgentAllowed is false. Also this target depends on the target that will actually populate that value, which is the GetBuildAgentAllowed target. The build script is placed below. I added a few elements that were for demo only. Those are; value for BuildAgentName and BeforeEndToEndIteration target. See comments in the file (which can be downloaded at the end of this post).
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="2.0"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
DefaultTargets="BeforeEndToEndIteration">
<!--
Assume that this value has been set already.
I'm declaring it here for this demonstration.
-->
<PropertyGroup>
<BuildAgentName>Sayed_001</BuildAgentName>
</PropertyGroup>
<PropertyGroup>
<BeforeEndToEndIterationDependsOn>
$(BeforeEndToEndIterationDependsOn);
DetermineIfAuthorizedBuildAgent;
</BeforeEndToEndIterationDependsOn>
</PropertyGroup>
<!--
Define this here as a property so it can be passed
via Properties from various callers.
-->
<PropertyGroup>
<AllowedBuildAgents>Sayed_001;Sayed_003;Sayed_005</AllowedBuildAgents>
</PropertyGroup>
<!--
Convert the property into an item so we can batch over it.
-->
<ItemGroup>
<AllowedBuildAgentsItem Include="$(AllowedBuildAgents)"/>
</ItemGroup>
<!--
Specify this value to false. If allowed it will be set to true.
-->
<PropertyGroup>
<BuildAgentAllowed>false</BuildAgentAllowed>
</PropertyGroup>
<Target Name="PrintInfo">
<Message Text="AllowedBuildAgentsItem: @(AllowedBuildAgentsItem,'%0a%0d')"/>
</Target>
<!-- Executing this target will make the GetBuildAgentAllowed target execute first -->
<Target Name="DetermineIfAuthorizedBuildAgent"
DependsOnTargets="GetBuildAgentAllowed">
<Message Text="BuildAgentAllowed: $(BuildAgentAllowed)"/>
<Error Text="This build can only be run on one of the following build agents: @(AllowedBuildAgentsItem)"
Condition="'$(BuildAgentAllowed)'=='false'" />
</Target>
<!--
This target will be executed for each value in the AllowedBuildAgentsItem.
If the BuildAgentName is equal to any value in AllowedBuildAgentsItem then the
property BuildAgentAllowed will be set to true.
-->
<Target Name="GetBuildAgentAllowed" Outputs="%(AllowedBuildAgentsItem.Identity)">
<Message Text="GetBuildAgentAllowed %25(AllowedBuildAgentsItem.Identity): %(AllowedBuildAgentsItem.Identity)"/>
<CreateProperty Value="true" Condition="'$(BuildAgentName)'=='%(AllowedBuildAgentsItem.Identity)'">
<Output PropertyName="BuildAgentAllowed" TaskParameter="Value"/>
</CreateProperty>
</Target>
<!--
This target is really executed by TeamBuild but I will
put it here for demonstration. If this target executes then the build
was allowed otherwise an error will be shown.
-->
<Target Name="BeforeEndToEndIteration" DependsOnTargets="$(BeforeEndToEndIterationDependsOn)">
<Message Text="EndToEndIteration starting"/>
</Target>
</Project>
The only reason that I have defined the allowed build agents in a property (AllowedBuildAgents) is because I want to allow external sources to specify it. You can specify properties through the command line or when using the MSBuild Task. Then the script converts this to an item. If I execute this project I would expect it to succeed because the defined value for BuildAgentName is contained in the list of AllowedBuildAgents. The results of executing this project are shown below.
Now we can change the value for BuildAgentName, by using the command msbuild.exe BuildAgent01.proj /p:BuildAgentName=Sayed_010. We would expect the build to fail. The results of this are below.
So the build failed as expected so we are good. Any questions?
Sayed Ibrahim Hashimi