Target with AfterTargets="Publish" executes in unpublishable project - msbuild

I have a project in my solution that I wanna publish separately from the rest of the solution. So the way to skip it is by setting the IsPublishable property to false, which works like a charm. It seems though that no matter the publishable status of the project, targets set to run after the publish target (AfterTargets="Publish") are still executed when I try to publish the entire solution.
Is this intended? Is there any way to prevent this? I am using VS 2022 preview.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<LangVersion>9.0</LangVersion>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<BaseOutputPath>..\Build</BaseOutputPath>
<IsPublishable>false</IsPublishable>
</PropertyGroup>
<ItemGroup>
<SomeFiles Include="$(SolutionDir)SomeFiles\**\*.txt" />
</ItemGroup>
<Target Name="CopyCustomContentBuild" AfterTargets="AfterBuild">
<Copy SourceFiles="#(SomeFiles)" DestinationFolder="$(TargetDir)SomeFiles" />
<Message Text="Files copied successfully." Importance="high" />
</Target>
<Target Name="CopyCustomContentPublish" AfterTargets="Publish">
<Copy SourceFiles="#(SomeFiles)" DestinationFolder="$(PublishDir)SomeFiles" />
<Message Text="Files copied successfully to publish dir." Importance="high" />
</Target>
</Project>

That is the intended behaviour. When you set IsPublishable to false MsBuild still logs when a Publish target is supposed to run and continues onto your AfterTargets="Publish" target.
You'll have to set a condition on your actions inside the target to make sure they do not get executed when IsPublishable is false.
<Target Name="CopyCustomContentPublish" AfterTargets="Publish">
<Copy SourceFiles="#(SomeFiles)" DestinationFolder="$(PublishDir)SomeFiles" Condition=" '$(IsPublishable)' == 'true' " />
<Message Text="Files copied successfully to publish dir." Importance="high" Condition=" '$(IsPublishable)' == 'true' " />
</Target>

Related

Current build number not being considered during tfsbuild

Something is not right. i am trying to build and deploy thru the below code snippet, but it so happens that the current build doesnt get deployed, whereas if i give a build number older than a current build, that gets deployed. I am puzzled what is wrong ... Can you please help me ...
I am not sure why the current buildnumber is not being considered ...
<PropertyGroup>
<deployappsvr>\\vdev\$(HostedFolder);\\vdev2\$(HostedFolder)</deployappsvr>
<prjbin>Release\_PublishedWebsites\RE.Service</prjbin>
</PropertyGroup>
<Target Name ="AfterEndToEndIteration" Condition=" '$(IsDesktopBuild)'!='true' ">
<!-- Starting deployment to servers -->
<Message Text="Starting deployment to servers" />
<CallTarget Targets="DeployBatching" />
<Message Text="finished deploying to servers" />
<!-- Unmap TFS mapping -->
<Exec Command="tf workfold /unmap $(tfsmap) /workspace:$(WorkspaceName) /collection:http://tfsapp:8080/tfs"/>
</Target>
<ItemGroup>
<SrcToCopy Include="$(DropLocation)\$(BuildNumber)\$(prjbin)\**\*"/>
<DestToCopy Include="$(deployappsvr)"/>
</ItemGroup>
<Target Name="DeployBatching" Outputs="%(DestToCopy.FullPath)">
<PropertyGroup>
<DestToCopy>%(DestToCopy.FullPath)</DestToCopy>
</PropertyGroup>
<RemoveDir Directories="#(DestToCopy)"/>
<MakeDir Directories="#(DestToCopy)"/>
<Message Text="111 #(SrcToCopy) 222 $(prjbin) 333 "/>
<Message Text="444 Copying source files #(SrcToCopy->'$(DestToCopy)\%(RecursiveDir)\%(Filename)%(Extension)') "/>
<Copy
SourceFiles="#(SrcToCopy)"
DestinationFiles="#(SrcToCopy->'$(DestToCopy)\%(RecursiveDir)\%(Filename)%(Extension)')"/>
<Message Text="Finished Copying source files"/>
<Exec Command="powershell Invoke-Command -computername vdev -scriptblock {md c:\buildtestfolder} > c:\power\pwrcmd.log 2>&1"/>
</Target>
I tired deploying from the build server i.e deploying build artifacts from the server copy instead of dropzone, that seem to be working but deploying from dropzone doesn't seem to be working still.

How to publish additional files using msbuild file and TeamCity?

I'm using a msbuild file, TeamCity and Web Deploy to deploy my siteand everything works just fine, for the files included in the Visual Studio csproj file. In addition to these files I want to publish a couple of more files such as license files etc depending on environment.
This is my build file DeployToTest.proj:
<Project DefaultTargets="Deploy" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
<ItemGroup>
<LicenseSourceFiles Include="License.config"/>
<RobotSourceFile Include="robots.txt" />
</ItemGroup>
<Target Name="Build">
<Message Text="Starting build" />
<MSBuild Projects="..\..\WebApp.sln" Properties="Configuration=Test" ContinueOnError="false" />
<Message Text="##teamcity[buildNumber '$(FullVersion)']"/>
<Message Text="Build successful" />
</Target>
<Target Name="Deploy" DependsOnTargets="Build">
<Copy SourceFiles="#(LicenseSourceFiles)" DestinationFolder="..\..\wwroot"></Copy>
<Copy SourceFiles="#(RobotSourceFile)" DestinationFolder="..\..\wwwroot"></Copy>
<Message Text="Started deploying to test" />
<Exec Command="C:\Windows\Microsoft.NET\Framework64\v4.0.30319\msbuild.exe ..\..\wwwroot\WebApp.csproj /property:Configuration=Test /t:MsDeployPublish /p:MsDeployServiceUrl=99.99.99.99;DeployIisAppPath=MySite;username=user;password=pass;allowuntrustedcertificate=true" />
<Message Text="Finished deploying to test" />
</Target>
</Project>
As you can see I tried to copy the license.config and robots.txt without any luck.
This .proj file is selected as the 'Build file path' in TeamCity.
Any suggestions on how I can accomplish this?
To solve this problem it may be worth executing the build script with the verbosity set to the 'detailed' or 'diagnostic' level. That should tell you exactly why the copy step fails.
However one of the most likely problems could be the fact that the script is using relative file paths, which depend on the working directory being set to the correct value. For build scripts I prefer use absolute paths to prevent any file path problems.
To get the absolute path you can use the MSBuildProjectDirectory property. The value of this property points to the path of the directory containing the currently executing MsBuild script. With that you can change your MsBuild script like this:
<Project DefaultTargets="Deploy" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
<PropertyGroup>
<BaseDir>$(MSBuildProjectDirectory)</BaseDir>
</PropertyGroup>
<ItemGroup>
<LicenseSourceFiles Include="$(BaseDir)\License.config"/>
<RobotSourceFile Include="$(BaseDir)\robots.txt" />
</ItemGroup>
<Target Name="Build">
<Message Text="Starting build" />
<MSBuild Projects="$(BaseDir)\..\..\WebApp.sln" Properties="Configuration=Test" ContinueOnError="false" />
<Message Text="##teamcity[buildNumber '$(FullVersion)']"/>
<Message Text="Build successful" />
</Target>
<Target Name="Deploy" DependsOnTargets="Build">
<Copy SourceFiles="#(LicenseSourceFiles)" DestinationFolder="$(BaseDir)\..\..\wwroot"></Copy>
<Copy SourceFiles="#(RobotSourceFile)" DestinationFolder="$(BaseDir)\..\..\wwwroot"></Copy>
<Message Text="Started deploying to test" />
<Exec Command="C:\Windows\Microsoft.NET\Framework64\v4.0.30319\msbuild.exe ..\..\wwwroot\WebApp.csproj /property:Configuration=Test /t:MsDeployPublish /p:MsDeployServiceUrl=99.99.99.99;DeployIisAppPath=MySite;username=user;password=pass;allowuntrustedcertificate=true" />
<Message Text="Finished deploying to test" />
</Target>
</Project>
Now this should fix the problem if there is indeed a problem with the relative file paths.
Solution was to change settings for the web project in Visual Studio. Under Package/Publish Web i set 'Items to deploy' to 'All files in this project folder'. I then added a filter to remove all .cs files and other unwanted files.

What happened to BeforeBuild and other targets in VS2012?

I'm trying to get some pre-build steps to work in a C++ project in Visual Studio 2012 but they do not get invoked (while I'm pretty sure the same techniques were OK in Visual Studio 2010). Command line builds behave exactly the same.
This is the end of the project file; the file was generated using Visual Studio and then I just added the last couple of lines:
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<Target Name="BeforeBuild">
<Message Text="### BeforeBuild ###" />
</Target>
<Target Name="BeforeCompile">
<Message Text="### BeforeCompile ###" />
</Target>
<Target Name="AfterBuild">
<Message Text="### AfterBuild ###" />
</Target>
and here's the output:
Project "d:\temp\temp.vcxproj" on node 1 (default targets).
InitializeBuildStatus:
Creating "Debug\temp.unsuccessfulbuild" because "AlwaysCreate" was specified.
AfterBuild:
AfterBuild
FinalizeBuildStatus:
Deleting file "Debug\temp.unsuccessfulbuild".
Touching "Debug\temp.lastbuildstate".
So only AfterBuild is considered and the others are ignored.
Looking into this I found this PropertyGroup in Microsoft.BuildSteps.targets:
<BuildDependsOn>
_PrepareForBuild;
$(BuildSteps);
AfterBuild;
FinalizeBuildStatus;
</BuildDependsOn>
Shouldn't this also have BeforeBuild and the BuildEvent targets? Or is something wrong with my MSBuild install causing it to use this BuildSteps.targets file instead of something else?
Solution
As Alexey points out, using Before/AfterTarget provides a usable workaround. You just have to take care of which targets to use, but this is easy by looking at the BuildSteps file. This seems to work fine for now:
<Target Name="BeforeBuild" BeforeTargets="PrepareForBuild">
<Message Text="### BeforeBuild ###" />
</Target>
<Target Name="BeforeCompile" BeforeTargets="BuildCompile">
<Message Text="### BeforeCompile ###" />
</Target>
<Target Name="AfterBuild" AfterTargets="Build">
<Message Text="### AfterBuild ###" />
</Target>
I have same msbuild targets as you described, so I think your msbuild installation is fine.
Looks like they decide to make some cleanup to targets and dependencies ( not sure if this issue related to VS version, VS just using same targets, provided by msbuild). BeforeBuild and other targets still exists in Microsoft.common.targets. I suppose it just reserved for .NET projects (I never played with C++ ones, so I don't know, how to build a pipeline there).
Anyway whether it works or not on previous versions, your problem can be solved much easier - just use new attributes BeforeTargets\AfterTargets for MSBuild 4.0 and hook your targets directly on whatever you want:
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<Target Name="BeforeBuild" BeforeTargets="Build">
<Message Text="### BeforeBuild ###" Importance="high" />
</Target>
<Target Name="BeforeCompile" BeforeTargets="Compile">
<Message Text="### BeforeCompile ###" Importance="high" />
</Target>
<Target Name="AfterBuild" AfterTargets="Build">
<Message Text="### AfterBuild ###" Importance="high" />
</Target>

Msbuild compile website without placing the site in IIS

I am trying to create a msbuild script that will compile and place a test app into a folder on my desktop. I do not want this app published to IIS. I have followed several blgos and looked through hashimi's book but I still cannot figure this out. Below is my script. Thank you very much!
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="Clean">
<ItemGroup>
<BinFiles Include="bin\*.*" />
</ItemGroup>
<Delete Files="#(BinFiles)" />
</Target>
<Target Name="Compile" DependsOnTargets="Clean">
<MSBuild Projects="test.vbproj"/>
</Target>
<Target Name="Publish" DependsOnTargets="Compile">
<RemoveDir Directories="$(OutputFolder)"
ContinueOnError="true"/>
<MSBuild Projects="test.vbproj"
targets="ResolveReferences;_CopyWebApplication"
Properties="WebProjectOutputdir=$(OutputFolder; OutDir=$WebProjectOutputDir)\"/>
</Target>
</Target>
</Project>
Your script is a bit awkward (you redefined the clean target to do the same as the the basic clean target).
I'm pretty sure your problem comes from the CopyWebApplication which does lots of stuff according to the properties set in your project file and pass by command line.
Can you try the following script :
<Project DefaultTargets="Compile" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="Compile">
<MSBuild
Projects="test.vbproj"
Targets="Clean;Build"
Properties="OutputPath=C:\tmp"/>
</Target>
</Project>
if your test project is a website then the build target should create it on the folder specified in the OutputPath/OutDir property

MSBuild: Add additional files to compile without altering the project file

After looking around I can't find a simple answer to this problem.
I am trying to create an MSBuild file to allow me to easily use SpecFlow and NUnit within Visual Studio 2010 express.
The file below is not complete this is just a proof of concept and it needs to be made more generic.
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<BuildDependsOn>
BuildSolution;
SpecFlow;
BuildProject;
NUnit;
</BuildDependsOn>
</PropertyGroup>
<PropertyGroup>
<Solution>C:\Users\Craig\Documents\My Dropbox\Cells\Cells.sln</Solution>
<CSProject>C:\Users\Craig\Documents\My Dropbox\Cells\Configuration\Configuration.csproj</CSProject>
<DLL>C:\Users\Craig\Documents\My Dropbox\Cells\Configuration\bin\Debug\Configuration.dll</DLL>
<CSFile>C:\Users\Craig\Documents\My Dropbox\Cells\Configuration\SpecFlowFeature1.feature.cs</CSFile>
</PropertyGroup>
<Target Name="Build" DependsOnTargets="$(BuildDependsOn)">
<Message Text="Build Started" Importance="high" />
<Message Text="Build Ended" Importance="high" />
</Target>
<Target Name="BuildSolution">
<Message Text="BuildSolution Started" Importance="high" />
<MSBuild Projects="$(Solution)" Properties="Configuration=Debug" />
<Message Text="BuildSolution Ended" Importance="high" />
</Target>
<Target Name="SpecFlow">
<Message Text="SpecFlow Started" Importance="high" />
<Exec Command='SpecFlow generateall "$(CSProject)"' />
<Message Text="SpecFlow Ended" Importance="high" />
</Target>
<Target Name="BuildProject">
<Message Text="BuildProject Started" Importance="high" />
<MSBuild Projects="$(CSProject)" Properties="Configuration=Debug" />
<Message Text="BuildProject Ended" Importance="high" />
</Target>
<Target Name="NUnit">
<Message Text="NUnit Started" Importance="high" />
<Exec Command='NUnit /run "$(DLL)"' />
<Message Text="NUnit Ended" Importance="high" />
</Target>
</Project>
The SpecFlow Task looks in the .csproj file and creates a SpecFlowFeature1.feature.cs.
I need to include this file when building the .csproj so that NUnit can use it.
I know I could modify (either directly or on a copy) the .csproj file to include the generated file but I'd prefer to avoid this.
My question is: Is there a way to use the MSBuild Task to build the project file and tell it to include an additional file to include in the build?
Thank you.
I found no way of doing it without editing the project file.
So I made an MSBuild file to:
Copy the project files
Run the copies through SpecFlow
Add the new .cs files to the copied projects
Compile the projects
Debug Run each of the compiled DLLs through NUnit
Clean up - Delete the copied projects
I've blogged about how to use it here:
http://learntdd.wordpress.com/2010/06/10/using-specflow-and-nunit-on-visual-studio-2010-express/
(It's version 1, I'd like to improve the script)
I couldn't think of any way to achieve without any modification to the .csproj file.
The approach I'd suggest would look like this.
In your .csproj you Import a container target file
...
<Import Project="SpecFlow.target" />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
...
just above the CSharp.targets.
Specflow.targets would look like this
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Compile Include="#(Compile)" />
</ItemGroup>
</Project>
so it doesn't harm while building the project from VS.
You could then use the Output of your SpecFlow Exec and add it to the SpecFlow.targets file
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Compile Include="#(Compile)" />
<Compile Include="SpecFlowFeature1.feature.cs" />
</ItemGroup>
</Project>
...
and clean SpecFlow.targets after building your .csproj.