The answer I finally came up with which works well for Visual Studio 2010 and Visual Studio 2012; put this just before the end of your web application's .csproj
file:
<Project...
[...]
<!-- The following makes sure we can't accidentally publish a non-Release configuration from within Visual Studio -->
<Target Name="PreventNonReleasePublish2010" BeforeTargets="PipelinePreDeployCopyAllFilesToOneFolder" Condition="'$(BuildingInsideVisualStudio)'=='true' AND '$(VisualStudioVersion)'=='10.0'">
<Error Condition="'$(Configuration)'!='Release'" Text="When publishing from Visual Studio 2010, you must publish the Release configuration!" />
</Target>
<Target Name="PreventNonReleasePublish2012" BeforeTargets="MSDeployPublish" Condition="'$(BuildingInsideVisualStudio)'=='true' AND '$(VisualStudioVersion)'=='11.0'">
<Error Condition="'$(Configuration)'!='Release'" Text="When publishing from Visual Studio 2012, you must publish the Release configuration!" />
</Target>
</Project>
Read on to see my thinking behind this answer, but basically it revolves around the fact that Visual Studio 2010 defines the PipelinePreDeployCopyAllFilesToOneFolder
Target to hook on to, and Visual Studio 2012 defines the more "standard" MSDeployPublish
Target to hook on to.
The above code only allows deploy publishing when in a Release
configuration from within Visual Studio, but it could easily be modified to prevent all deploy publishing from within Visual Studio.
AFAIR, "Publish" from Visual Studio 2010 context menu invokes webdeploymsdeploy tool. I played with it a bit, but I didn't liked at all. If you still want to use this functionality and insert your target somewhere - you need to know the exact target and its dependency property.
Check
c:Program Files (x86)MSBuildMicrosoftVisualStudiov10.0WebMicrosoft.Web.Publishing.targets
You will find two tasks - MSDeploy and VSMSDeploy. The latter one sounds right for me. The first one is not used in this file at all. But VSMSDeploy used in three different targets,
PackageUsingManifest, TestDeployPackageToLocal and MSDeployPublish. Again the latter one sounds good ;)
<Target Name="MSDeployPublish" DependsOnTargets="$(MSDeployPublishDependsOn)">
So you just need to override one property. Put this before your target and "YourTargetName" will be called right before MSDeployPublish.
<PropertyGroup>
<MSDeployPublishDependsOn Condition="'$(MSDeployPublishDependsOn)'!=''">
$(MSDeployPublishDependsOn);
YourTargetName;
</MSDeployPublishDependsOn>
</PropertyGroup>
If you already switched to MSBuild 4.0, there is an easier way to hook your target. You just need to specify the BeforeTarget
attribute. In our case it will be like this:
<Target Name="MyTarget" BeforeTargets="MSDeployPublish">
<Error Condition="'foo'=='foo'" Text="test publish error" />
</Target>
I hope this helps. Ask if you have more questions.
PS: I didn't checked all that, because I don't have any MSDeploy-ready environments ;)
NB: I remember that I was discouraged from using MSDeploy for our own products because it was pretty counter-intuitive to properly configuring it for a continuous integration (CI) system. Maybe I wasn't very good at that, and your solution will work properly. But proceed with MSDeploy carefully.