When using the Web Deployment Project MSBuild uses the folder '.TempBuildDir' when performing the build. Is it possible to specify an alternative folder?
In C:\Program Files\MSBuild\Microsoft\WebDeployment\v9.0 or v10.0 directory is the Microsoft.WebDeployment.targets file where the TempBuildDir property is defined in the _PrepareForBuild target.
Since they use the CreateProperty task to set TempBuildDir it is always set to the hard-coded value even if the property already exists. This could be to eliminate the problem of someone using TempBuildDir property for something else and messing up the build.
You would have to change the Microsoft.WebDeployment.targets file to use a different temp directory.
WARNING: The following is changing a file you don't have control over so use are your own risk.
If you were to change the following lines in the _PrepareForBuild target from
<CreateProperty Value=".\TempBuildDir\">
<Output TaskParameter="Value" PropertyName="TempBuildDir" />
</CreateProperty>
to
<CreateProperty Value="$(MySpecialWebTempBuildDir)" Condition=" '$(MySpecialWebTempBuildDir)' != '' ">
<Output TaskParameter="Value" PropertyName="TempBuildDir" />
</CreateProperty>
<CreateProperty Value=".\TempBuildDir\" Condition=" '$(MySpecialWebTempBuildDir)' == '' ">
<Output TaskParameter="Value" PropertyName="TempBuildDir" />
</CreateProperty>
Then set the MySpecialWebTempBuildDir property in your project file and it should override it. If you don't set MySpecialWebTempBuildDir then it will use TempBuildDir as before.
If you install an update to the web deployment package your changes will get overwritten.
Another solution is to uncomment and override the "BeforeBuild" target of the web deployment project as follows:
<Target Name="BeforeBuild">
<CreateProperty Value=".\TempBuildDirDebug\" Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<Output TaskParameter="Value" PropertyName="TempBuildDir" />
</CreateProperty>
<CreateProperty Value=".\TempBuildDirRelease\" Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<Output TaskParameter="Value" PropertyName="TempBuildDir" />
</CreateProperty>
Related
I am trying to create a project file that performs few custom steps (specifically, it "wraps" existing Angular CLI project).
Here is my best attempt (myproject.csproj):
<Project ToolsVersion="Current" DefaultTargets="Build">
<PropertyGroup>
<ProjectGuid>{...some-guid...}</ProjectGuid>
<!-- do not include files by default -->
<EnableDefaultItems>false</EnableDefaultItems>
<!-- this removes 'Publish...' menu in VS -->
<OutputType>Library</OutputType>
<!-- output directory name -->
<AngularProject>MyWebFiles</AngularProject>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<PlatformTarget>x64</PlatformTarget>
<OutputPath>bin\Debug\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<PlatformTarget>x64</PlatformTarget>
<OutputPath>bin\Release\</OutputPath>
</PropertyGroup>
<ItemGroup>
<AngularFile Include="**" Exclude="node_modules\**" />
</ItemGroup>
<Target Name="Build" Inputs="#(AngularFile)" Outputs="$(OutputPath)$(AngularProject)\index.html">
<Exec Command="ng build --no-progress --output-path $(OutputPath)$(AngularProject)\" Condition="'$(Configuration)'=='Debug'" />
<Exec Command="ng build --no-progress --output-path $(OutputPath)$(AngularProject)\ --prod" Condition="'$(Configuration)'=='Release'" />
</Target>
<Target Name="Clean">
<RemoveDir Directories="$(OutputPath)$(AngularProject)\" />
</Target>
<Target Name="Rebuild" DependsOnTargets="Clean;Build" />
</Project>
Everything works fine, I can add this project to VS2019 solution, compile, etc. But it has problems:
Fast up-to-date check doesn't work. Related logging produces this:
Build started...
1>Project 'myproject' is not up to date. Error (0x8000FFFF).
I've tried specifying fast up-to-date files manually (via UpToDateCheckInput, etc), but it didn't work (presumably because it relies on additional definitions pulled in when you specify Sdk attribute of Project tag).
VS configuration manager has empty 'Platform' combo box. I'd like to be able to have x64 in it:
it is rather obvious that PlatformTarget is getting ignored by VS.
Opening project in VS results in creation of obj\x64\Debug\TempPE\ directory (if current Configuration is Debug). Nothing ever gets generated in it -- would be nice to avoid it being created.
Is it possible to fix these 3 problems? I suspect relates subsystems expect certain values/properties to be generated, I've tried digging in .props/.targets that come with VS in attempt to locate them, but quickly got lost.
Here is how to do it:
<Project Sdk="Microsoft.Build.NoTargets/3.2.14">
<ItemGroup>
<PackageReference Include="Microsoft.Build.NoTargets" Version="3.2.14" />
</ItemGroup>
<PropertyGroup>
<!-- Any target framework you want as long as its compatible with your referenced NuGet packages -->
<TargetFramework>net462</TargetFramework>
<Platforms>x64</Platforms>
<!-- Do not add TargetFramework to OutputPath -->
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<!-- Do not expect pdb files to be generated (this is for fast up-to-date check) -->
<DebugType>None</DebugType>
<!-- Do not include files by default -->
<EnableDefaultItems>false</EnableDefaultItems>
<!-- Output subdir name -->
<AngularProject>MyWebFiles</AngularProject>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<OutputPath>..\..\Bin\Debug\</OutputPath>
<BuildCommand>ng build --no-progress --output-path $(OutputPath)$(AngularProject)\</BuildCommand>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<OutputPath>..\..\Bin\Release\</OutputPath>
<BuildCommand>ng build --no-progress --output-path $(OutputPath)$(AngularProject)\ --prod</BuildCommand>
</PropertyGroup>
<ItemGroup>
<None Include="**" Exclude="node_modules\**;$(BaseIntermediateOutputPath)\**;$(MSBuildProjectFile)" />
<!-- This deals with fast up-to-date checks -->
<UpToDateCheckBuilt Original="package-lock.json" Include="node_modules/.build" />
<UpToDateCheckInput Include="#(None);$(MSBuildProjectFile)" Set="AngularFiles" />
<UpToDateCheckOutput Include="$(OutputPath)$(AngularProject)\index.html" Set="AngularFiles" />
</ItemGroup>
<Target Name="InitModules" Inputs="package-lock.json" Outputs="node_modules/.build">
<Exec Command="npm ci --no-progress --no-color" YieldDuringToolExecution="true" />
<Exec Command="cd . > node_modules/.build" />
</Target>
<Target Name="BuildAngular" BeforeTargets="AfterBuild" Inputs="#(None);$(MSBuildProjectFile)" Outputs="$(OutputPath)$(AngularProject)\index.html" DependsOnTargets="InitModules">
<Exec Command="$(BuildCommand)" YieldDuringToolExecution="true" />
</Target>
<Target Name="CleanAngular" BeforeTargets="AfterClean">
<RemoveDir Directories="$(OutputPath)$(AngularProject)\" />
</Target>
</Project>
Notes:
it will still generate additional local directory (obj), but it can be moved away by overriding IntermediateOutputPath
I've recently started using GitVersion to version my assemblies, and I love it!
I like to generate a .msi file that reflects the version of the product being built. Hitherto, I was using this in my .wixproj file:
<!-- [TPL] name the output file to include the version from theLocalServer assembly -->
<Target Name="BeforeBuild">
<GetAssemblyIdentity AssemblyFiles="$(SolutionDir)BuildOutput\$(Configuration)\TA.DigitalDomeworks.Server.exe">
<Output TaskParameter="Assemblies" ItemName="AssemblyVersions" />
</GetAssemblyIdentity>
<CreateProperty Value="$(OutputName).%(AssemblyVersions.Version)">
<Output TaskParameter="Value" PropertyName="TargetName" />
</CreateProperty>
<CreateProperty Value="$(TargetName)$(TargetExt)">
<Output TaskParameter="Value" PropertyName="TargetFileName" />
</CreateProperty>
<CreateProperty Value="$(TargetDir)$(TargetFileName)">
<Output TaskParameter="Value" PropertyName="TargetPath" />
</CreateProperty>
</Target>
This produces an output file with a name like:
TA.DigitalDomeworks.Installer.7.1.0.3.msi
I found this solution from this answer, which references this blog post. The 7.1.0.3 comes from the assembly version of the main assembly in the build, which in turn is being versioned by GitVersion during its own build.
However, what I'd really like is to use the FullSemVer property, which can be seen here:
C:\Users\Tim\source\repos\TA.DigitalDomeworks [release/7.1 ↑1 +0 ~1 -0 !]> gitversion
{
"Major":7,
"Minor":1,
"Patch":0,
"PreReleaseTag":"beta.3",
"PreReleaseTagWithDash":"-beta.3",
"PreReleaseLabel":"beta",
"PreReleaseNumber":3,
"BuildMetaData":"",
"BuildMetaDataPadded":"",
"FullBuildMetaData":"Branch.release/7.1.Sha.77fa2c96ed9b0f5ab162d07052ef094e8ccfc8c5",
"MajorMinorPatch":"7.1.0",
"SemVer":"7.1.0-beta.3",
"LegacySemVer":"7.1.0-beta3",
"LegacySemVerPadded":"7.1.0-beta0003",
"AssemblySemVer":"7.1.0.3",
"FullSemVer":"7.1.0-beta.3",
"InformationalVersion":"7.1.0-beta.3+Branch.release/7.1.Sha.77fa2c96ed9b0f5ab162d07052ef094e8ccfc8c5",
"BranchName":"release/7.1",
"Sha":"77fa2c96ed9b0f5ab162d07052ef094e8ccfc8c5",
"NuGetVersionV2":"7.1.0-beta0003",
"NuGetVersion":"7.1.0-beta0003",
"CommitsSinceVersionSource":3,
"CommitsSinceVersionSourcePadded":"0003",
"CommitDate":"2018-09-10"
}
So the final filename I'd like to see is:
TA.DigitalDomeworks.Installer-7.1.0-Beta.3.msi
In the GitVersion documentation, it say that I need to make sure the GitVersion.GetVersion build task has executed, after which I should be able to obtain the full SemVer from a build property called $(GitVersion_FullSemVer).
However, I'm not sure how to achieve that in a WiX project, since installing the GitVersionTask NuGet package doesn't seem to do anything (in C# projects, everything just magically works). If I could get to the point where I can execute the GitVersion.GetVersion task, then I think I can see my way clear to getting the output name I want.
Has anyone got this working? Or can anyone offer any advice on how to approach this?
I figured it out. I was on the right lines to start with. There's no need to manually execute GitVersion.GetVersion, this is handled correctly by MSBuild once the GitVersionTask NuGet package is installed in the WiX project. The reason it wasn't working is because I was trying to use GitVersion's properties before they had been set.
So, first thing is to create a couple of properties that disable some unwanted GitVersion actions:
<PropertyGroup>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<WriteVersionInfoToBuildLog>false</WriteVersionInfoToBuildLog>
<GenerateGitVersionInformation>false</GenerateGitVersionInformation>
</PropertyGroup>
We can't simply change the OutputName property because that is set before any tasks (including GitVersion tasks) execute, so if we try to use the GitVersion properties in there, they will be empty/unset because the GitVersion targets haven't executed yet. Instead, we have to put some logic into a build target, the obvious candidate being the BeforeBuild target that is usually found at the end of the project file:
<Target Name="BeforeBuild" AfterTargets="GetVersion">
<CreateProperty Value="$(OutputName).$(GitVersion_SemVer)">
<Output TaskParameter="Value" PropertyName="TargetName" />
</CreateProperty>
<CreateProperty Value="$(TargetName)$(TargetExt)">
<Output TaskParameter="Value" PropertyName="TargetFileName" />
</CreateProperty>
<CreateProperty Value="$(TargetDir)$(TargetFileName)">
<Output TaskParameter="Value" PropertyName="TargetPath" />
</CreateProperty>
</Target>
Here we use the OutputName property as a base name and augmented it with the desired GitVersion properties, to create the TargetName, TargetFileName and TargetPath properties that will be used in the rest of the build process. This works because the BeforeBuild task is guaranteed to execute before any output file is generated, so all the Target* properties will be set before then.
Let's see if this solves your problem
My approach goes thus:
Add the following to your main assembly project, not the wix project
<Target Name="WriteVersionToFile" AfterTargets="GetVersion">
<WriteLinesToFile File="$(OutputPath)version.txt" Lines="$(GitVersion_FullSemVer)" Overwrite="true" Encoding="Unicode" />
</Target>
Then replace your BeforeBuild target with this sample in your wix project
<Target Name="BeforeBuild">
<ReadLinesFromFile File="$(SolutionDir)BuildOutput\$(Configuration)\version.txt">
<Output TaskParameter="Lines" ItemName="Version" />
</ReadLinesFromFile>
<CreateProperty Value="$(OutputName).$(Version)">
<Output TaskParameter="Value" PropertyName="TargetName" />
</CreateProperty>
<CreateProperty Value="$(TargetName)$(TargetExt)">
<Output TaskParameter="Value" PropertyName="TargetFileName" />
</CreateProperty>
<CreateProperty Value="$(TargetDir)$(TargetFileName)">
<Output TaskParameter="Value" PropertyName="TargetPath" />
</CreateProperty>
</Target>
The solution adds the GitVersion_FullSemVer property to a text file after the GetVersionTask is run. This data is then used in the wix project for versioning the msi file.
I have been trying to update the ApplicationVersion property in my csproj file.witch works fine; i have added a Target that runs an custom task to extract the AssemblyFileVersion from my assemblyinfo.cs; this works there is no doubt about that.
But then when i want to use my updated ApplicationVersion to determan where to put my newly build files, i get the default value set in the property.
<PropertyGroup>
...
<ApplicationVersion>1.0.0.0</ApplicationVersion>
...
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\media-converter-BUILD\debug\$(ApplicationVersion)\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<DocumentationFile>..\media-converter-BUILD\debug\$(ApplicationVersion)\MediaConverter.XML</DocumentationFile>
</PropertyGroup>
My Targets
<UsingTask AssemblyFile="GetAssemblyFileVersion.dll" TaskName="GetAssemblyFileVersion.GetAssemblyFileVersion" />
<Target Name="MainAfterCompile">
<CallTarget Targets="AfterCompile" />
<CallTarget Targets="VerifyParam" />
</Target>
<Target Name="AfterCompile">
<GetAssemblyFileVersion strFilePathAssemblyInfo="Properties\AssemblyInfo.cs">
<Output TaskParameter="strAssemblyFileVersion" PropertyName="ApplicationVersionModded" />
</GetAssemblyFileVersion>
<PropertyGroup>
<ApplicationVersion>$(ApplicationVersionModded)</ApplicationVersion>
</PropertyGroup>
</Target>
<Target Name="VerifyParam">
<Message Text="New $(ApplicationVersionModded)" Importance="high"/>
<Message Text="Old Updated $(ApplicationVersion)" Importance="high"/>
</Target>
the GetAssemblyFileVersion.dll i more or less stole from some post i found on the internet, just can't find it again, so i can't add a link, sorry.
My theory on why it does not work is that the transforms and parameters in PropertyGroups are rendered before both InitailTagets and DefaultTargets is run. And there for will my plan never work
but if anyone knows of a way to make it work, i will be grateful to here it
My theory on why it does not work is that the transforms and parameters in PropertyGroups are rendered before both InitailTagets and DefaultTargets is run indeed, that's how the evaluation order works: msbuild evaluates global properties in the first pass of the file, you define OutputPath, that is used by the Microsoft.Common.CurrentVersion.targets file to derive OutDir/BaseIntermediateOutputPath/.... Then in another pass your targets run and update the version number, but there isn't another pass which evaluates the global OutputPath property again.
You can however override the value of OutputPath and derived paths in a Target, and it will take effect, you just have to take care of running it early in the build so that other targets use the updated version. This does the trick:
<Target Name="GetApplicationVersion">
<GetAssemblyFileVersion strFilePathAssemblyInfo="Properties\AssemblyInfo.cs">
<Output TaskParameter="strAssemblyFileVersion" PropertyName="ApplicationVersion" />
</GetAssemblyFileVersion>
</Target>
<Target Name="SetOutputPaths" DependsOnTargets="GetApplicationVersion"
BeforeTargets="PrepareForBuild">
<PropertyGroup>
<OutputPath>bin\$(Configuration)\$(ApplicationVersion)\</OutputPath>
<OutDir>$(OutputPath)</OutDir>
</PropertyGroup>
<Message Text="Set OutDir to $(OutDir)" Importance="high" />
</Target>
Another way to deal with this is doing things the other way around: define the application version as a global msbuild property, then use it to define OutputPath and to update the number in AssemblyVersion.cs before it is compiled.
I have a property in an MSBuild project which is a semicolon-separated-list of string values. How can I test if the list constains a particular value?
In the example listing below, I want the target DeployToServer only to be executed if the property $(DCC_Define) constains 'WebDeploy'.
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<DCC_Define>WebDeploy;DEBUG</DCC_Define>
</PropertyGroup>
<Target Name="DeployToServer" Condition="$(DCC_Define) constains 'WebDeploy'">
<Message Text="Do something." />
</Target>
</Project>
I've used a bit of pseudo logic in the #Condition attribute to indicate what I mean. I am using a .NET framework version of 2.0.50727.3655; and MSBuild version of 3.4.30729.1 .
How can I achieve this? I don't have the luxury of being able to upgrade to MSBuild 4.
Well, since you can't use property function you have to get creative.
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<DCC_Define>WebDeploy;DEBUG;WebDeploy</DCC_Define>
</PropertyGroup>
<Target Name="DeployToServer">
<CreateItem Include="$(DCC_Define)">
<Output TaskParameter="Include" ItemName="DCC_Define" />
</CreateItem>
<!-- Not required since MSBuild doesn't execute targets twice -->
<!-- <CreateProperty Value="True" Condition="%(DCC_Define.Identity) == WebDeploy">
<Output TaskParameter="Value" PropertyName="WebDeploy" />
</CreateProperty> -->
<CallTarget Targets="_DeployToServer" Condition="%(DCC_Define.Identity) == WebDeploy" />
</Target>
<Target Name="_DeployToServer">
<Message Text="Do something." />
</Target>
</Project>
I currently use a web deployment project to update an existing web site through various MSBuild tasks
Taking site offline:
<Target Name="BeforeBuild" Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<CreateItem Include="..\website\App_Code\override\App_Offline.htm">
<Output TaskParameter="Include" ItemName="AppOffline" />
</CreateItem>
<Copy SourceFiles="#(AppOffline)" DestinationFiles="#(AppOffline->'\\servername\f$\web\example.com\wwwroot\%(RecursiveDir)%(Filename)%(Extension)')" />
<RemoveDir Directories="\\servername\f$\web\example.com\wwwroot\bin\" />
</Target>
Update files:
<Target Name="AfterBuild" Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<CreateItem Include=".\Release\**\*">
<Output TaskParameter="Include" ItemName="ReleaseFiles" />
</CreateItem>
<Copy SourceFiles="#(ReleaseFiles)" ContinueOnError="true" SkipUnchangedFiles="true" DestinationFiles="#(ReleaseFiles->'\\servername\f$\web\example.com\wwwroot\%(RecursiveDir)%(Filename)%(Extension)')" />
<Delete Files="\\servername\f$\web\example.com\wwwroot\App_Offline.htm" />
</Target>
However, what I also want to do is backup the existing site before overwriting anything, into a timestamped zip (or 7zip) file, e.g. if done on 3rd October 2011 at 10:35 file would be named \\servername\f$\web\example.com\backup201110031035.7z containing the contents of the wwwroot folder (before taking the site offline and deleting the bin directory)
The MSBuild Community Tasks provide support for both, zipping and getting the (formatted) current time through the Zip and Time tasks respectively.
Once the MSBuild community tasks are installed and imported to your project, you can create a backup zip file by adding the following to the beginning of your BeforeBuild target.
<ItemGroup>
<FilesToZip Include="\\servername\f$\web\example.com\wwwroot\**\*.*" />
</ItemGroup>
<Time Format="yyyyMMddhhmm">
<Output TaskParameter="FormattedTime" PropertyName="Timestamp" />
</Time>
<Zip
Files="#(FilesToZip)"
ZipFileName="\\servername\f$\web\example.com\backup$(Timestamp).zip"
WorkingDirectory="\\servername\f$\web\example.com\wwwroot" />