Publish ClickOnce from the command line - visual-studio

Is there a way to have Visual Studio 2008 execute the "Publish Now" button from the command line?
I've seen posts that suggest to use msbuild /target:publish to call it. That is OK, but MSBuild doesn't increment the revision number. I'm hoping for something like:
devenv mysolution.sln /publish

To increment build numbers, I am using MSBuild Extension pack inside my .csproj file as follows:
<Target Name="BeforeBuild" Condition=" '$(Configuration)|$(Platform)' == 'Release-VersionIncrement|AnyCPU' ">
<CallTarget Targets="CleanAppBinFolder" />
<MSBuild.ExtensionPack.VisualStudio.TfsSource TaskAction="Checkout" ItemCol="#(AssemblyInfoFiles)" WorkingDirectory="C:\inetpub\wwwroot\MySolution" ContinueOnError="true" />
<!-- Microsoft's task that goes over assembly files and increments revision number. -->
<MSBuild.ExtensionPack.Framework.AssemblyInfo Condition="'$(Optimize)'=='True' " AssemblyInfoFiles="#(AssemblyInfoFiles)" AssemblyRevisionType="AutoIncrement" AssemblyFileRevisionType="AutoIncrement">
<Output TaskParameter="MaxAssemblyVersion" PropertyName="MaxAssemblyVersion" />
</MSBuild.ExtensionPack.Framework.AssemblyInfo>
<Message Text="----current version---: '$(MaxAssemblyVersion)'" />
</Target>
This way, anytime the configuration is set to Release-VersionIncrement, the version number is changed. When this is done, I can use the following MSBuild command to publish it:
msbuild c:\projects\MyProject.csproj
/t:ResolveReferences;_CopyWebApplication
/p:Configuration=Release;BuildingProject=true;WebProjectOutputDir=c:\inetpub\wwwroot\OutputProject\MyProjectOutput;OutDir=c:\inetpub\wwwroot\OutputProject\MyProjectOutput
Note that this is for an ASP.NET 3.5 web application.

Related

How to see MsBuild output in Visual Studio in real time

I've added some additional targets to a .csproj file in order to carry out some additional tasks after the project build is completed.
Nothing appears in the Visual Studio output window until all targets have completed. I want to be able to see messages that occur as the targets are being processed.
If I use the MSBuild Task Explorer (a VS extension), I can see that the messages can be picked up by a Visual Studio window as they are generated, so am I just missing a setting somewhere?
I've also tried replacing the Exec tasks with SmartExec from the MSBuild Extensions package.
Here is a snippet from my .csproj project file:
<Target Name="PostBuildActions" AfterTargets="Build">
<!--Get the version number from the assembly info -->
<GetAssemblyIdentity AssemblyFiles="$(ProjectDir)$(OutputPath)$(TargetFileName)">
<Output TaskParameter="Assemblies" ItemName="ToolboxVersion" />
</GetAssemblyIdentity>
<CreateProperty Value="$(ProjectDir)$(OutputPath.TrimEnd('\'))">
<Output TaskParameter="Value" PropertyName="ToolboxTarget" />
</CreateProperty>
<!-- Run the Simulink Widget Generator tool -->
<CreateProperty Value=""$(SolutionDir)SimulinkWidgetGenerator\bin\$(Configuration)\SimulinkWidgetGenerator.exe" -v %(ToolboxVersion.Version) -d "$(ToolboxTarget)"">
<Output TaskParameter="Value" PropertyName="WidgetGenCommand" />
</CreateProperty>
<Message Text="Running Simulink Widget Generator:" Importance="High" />
<Message Text="$(WidgetGenCommand)" Importance="High" />
<Exec Command="$(WidgetGenCommand)" ConsoleToMSBuild="true" />
<!-- Invoke Matlab -->
<CreateProperty Value="try, PackageToolbox, catch ex, disp(getReport(ex)), exit(-1), end, exit(0);">
<Output TaskParameter="Value" PropertyName="MatlabScript" />
</CreateProperty>
<CreateProperty Value=""$(MATLAB_INSTALL_DIR)\bin\matlab.exe" -automation -wait -log -sd "$(ToolboxTarget)" -r "$(MatlabScript)"">
<Output TaskParameter="Value" PropertyName="MatlabCommand" />
</CreateProperty>
<Message Text="Invoking Matlab: " Importance="High" />
<Message Text="$(MatlabCommand)" Importance="High" />
<Exec Command="$(MatlabCommand)" ConsoleToMSBuild="true" />
In Visual Studio, you can config your MSBuild verbosity in Tools –> Options –> Projects and Solutions –> Build and Run.
From here:
Verbosity set to Quiet – shows either success or the build failure. 1 line displayed below for successful build.
Verbosity set to Minimal – shows the command line for the build. 2 lines displayed for successful rebuild.
Verbosity set to Normal. Shows the output from the MSBuild Targets. 25 lines displayed for successful rebuild.
Verbosity set to Detailed. Much more comments shown from MSBuild. 395 lines displayed for successful build.
And lastly, Verbosity set to Diagnostic, shows you everything. 1097 lines displayed for successful build.
For this issue, I recommend you use msbuild command like msbuild
xxx.csproj by developer command prompt to see the targets being processed.
So am I just missing a setting somewhere?
No, indeed you're right and for now, the output in Visual studio seems to not support for real-time display after my test.
Details to describe this situation:
As we know, there has two ways to build vs project:
1. Build in Visual Studio 2. Msbuild.exe.
Build process in VS(#1) actually calls the Msbuild tool(#2) to work.
Msbuild tool will display the target to a console window in real-time.
And in VS, the output of its build seems like a Non-real-time
log, which will display after the build process ends.If we add a Time-consuming operation like yours, it won't display until the command ends.
I've done a test for this, create a simple test.csproj, and add a script like this:
<Target Name="WaitingToDoSth" AfterTargets="Test1">
<Exec Command="$(ProjectDir)DoSth.exe"/>
</Target>
This DoSth.exe has a Thread.sleep(3000) in it. In VS, the output won't display anything until the DoSth.exe executes successfully and the entire build process ends.
When using msbuild xxx.csproj command in developer command prompt for VS2017, the display can be real-time and we can see messages that occur as the targets are being processed.
If my answer is helpful, please give a feedback. Thank you.
The key to seeing MSBuild output in realtime is to use the MSBuild project SDK. Many thanks to rainersigwald that posted this solution on GitHub:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace>_5451</RootNamespace>
</PropertyGroup>
<Target Name="LogStuffInRealTime" BeforeTargets="CoreCompile">
<Exec Command="ping 127.0.0.1" YieldDuringToolExecution="True" ConsoleToMSBuild="true" StandardOutputImportance="high">
<Output TaskParameter="ConsoleOutput" ItemName="OutputOfExec" />
</Exec>
</Target>
</Project>

ApplicationFiles folder missing when ClickOnce publish with command line

ClickOnce publish with IDE works normal.
When trying to publish via MSBuild command line
%MSBUILD% /target:publish /p:Configuration=Release;PublishDir="REMOTE_FOLDER"
only Project.exe and Setup.exe copies.
When try to %MSBUILD% /target:publish command then all necessary files copies to the build\app.publish folder
How do I publish via command line same ClickOnce settings which IDE uses
PS this question similar but not the same
How do I publish via command line same ClickOnce settings which IDE uses
Some features are done by Visual-Studio and not by the MSBuild command line. So the click-once-deployment behaves differently when it's executed from the command-line.
If you want to publish via command line same ClickOnce settings which IDE uses, you can use a custom target to achieve it. Edit your project(csproj) file (right click project node -> unload project -> edit xxx.csproj) and add the following code in it:
<PropertyGroup>
<ProjLocation>D:\Test\Projects\ClickOncePublish\ClickOncePublish</ProjLocation>
<ProjLocationReleaseDir>$(ProjLocation)\bin\Debug</ProjLocationReleaseDir>
<ProjPublishLocation>$(ProjLocationReleaseDir)\app.publish</ProjPublishLocation>
<DeploymentFolder>D:\Test\Publish\</DeploymentFolder>
</PropertyGroup>
<Target Name="Test" DependsOnTargets="Clean">
<MSBuild Projects="$(ProjLocation)\$(ProjectName).csproj"
Properties="$(DefaultBuildProperties)"
Targets="Publish"/>
<ItemGroup>
<SetupFiles Include="$(ProjPublishLocation)\*.*"/>
<UpdateFiles Include="$(ProjPublishLocation)\Application Files\**\*.*"/>
</ItemGroup>
<Copy SourceFiles="#(SetupFiles)" DestinationFolder="$(DeploymentFolder)\" />
<Copy SourceFiles="#(UpdateFiles)" DestinationFolder="$(DeploymentFolder)\Application Files\%(RecursiveDir)"/>
</Target>
<Target Name="Clean">
<Message Text="Clean project" />
<MSBuild Projects="$(ProjLocation)\$(ProjectName).csproj"
Properties="$(DefaultBuildProperties)"
Targets="Clean"/>
</Target>
Then you can build the project with the MSBuild command line:
msbuild /target:test
After execute the build command, all the expected files are publish via command line same ClickOnce settings which IDE uses.
Note: You should change the value of ProjLocation to the path of your project.

Trick to run different pre/post build events when building with MSBuild or from Visual Studio IDE

Don't ask me why, but does anyone know any trick to put in the pre/post build event command that will run different commands if the project is being built from command line with MSBuild or from inside the Visual Studio IDE?
The easiest solution would be to define build targets that are conditioned on the $(BuildingInVisualStudio) property that visual studio sets to true when buildinging.
<Target Name="SpecialPreBuild" BeforeTargets="BeforeBuild" Condition="'$(BuildingInVisualStudio)' != 'true'">
<Exec Command="some-command.exe --magic" />
<Copy SourceFiles="foo.txt" DestinationFolder="bin\$(Configuration)\bar" />
</Target>
<Target Name="SpecialPostBuild" AfterTargets="AfterBuild" Condition="'$(BuildingInVisualStudio)' != 'true'">
<Exec Command="some-other-command.exe --magic" />
</Target>
If you want to skip these targets in other IDEs / editors as well, you could introduce a custom property as well and change the Condition attributes above to
Condition="'$(PerformSpecialLogic)' == 'true'"
That way no "default" builds will execute these targets and you could build with the following arguments in your build script / CI definition:
msbuild /p:PerformSpecialLogic=true

How to set dynamic/variable ToolPath for Wix prebuild step (msbuild) using Jenkins

We have a WinXP Jenkins build machine that I'm in the process of moving over to a 64bit Win-7 machine. We are utilizing Wix to build the msi's via MSBuild..all these projects sit in TFS. We are getting the TFS changeset number in order set to current build in each project. The line in question in many of our [projectname].wixproj files looks like :
<Target Name="BeforeBuild">
<MSBuild.Community.Tasks.Tfs.TfsClient ToolPath="C:\Program Files\Microsoft Visual Studio 10.0\Common7\IDE" Command="history /stopafter:1 /version:T /format:detailed /recursive $(ProjectDir)">
<Output TaskParameter="Changeset" PropertyName="Changeset" />
</MSBuild.Community.Tasks.Tfs.TfsClient>
<Message Text="TFS ChangeSetNumber: $(Changeset)" />
<PropertyGroup>
<DefineConstants>ChangesetNumber=$(Changeset)</DefineConstants>
</PropertyGroup>
</Target>
This works fine on our 32-bit machine but fails on the new 64 bit because the toolpath for TF.EXE is now in c:\Program Files (x86)... instead of C:\program files... I'm trying to figure out a way to make this toolpath variable so we can continue to use both build machines (for now) without dedicating the wix project file to one or the other (without breaking one of the build machines, basically).
This tf.exe toolpath is configured easily in Jenkins on a per-machine basis, but this isn't propagated down into the projects themselves...unless there's a path variables I'm unaware of? Thanks.
You can calculate the root tool path in a msbuild variable.
First set the default value for windows 64 bits subfolder and then depending on an environment variable set the value for 32 bits where that variable is undefined in 32 bits machine.
<PropertyGroup>
<MyProgramFiles>C:\Program Files (x86)\</MyProgramFiles>
<MyProgramFiles Condition=" '$(CommonProgramW6432)' == '' ">C:\Program Files\</MyProgramFiles>
</PropertyGroup>
So passing that variable to your .wixproj will look something like:
<Target Name="BeforeBuild">
<PropertyGroup>
<MyProgramFiles>C:\Program Files (x86)\</MyProgramFiles>
<MyProgramFiles Condition=" '$(CommonProgramW6432)' == '' ">C:\Program Files\</MyProgramFiles>
</PropertyGroup>
<MSBuild.Community.Tasks.Tfs.TfsClient ToolPath="$(MyProgramFiles)\Microsoft Visual Studio 10.0\Common7\IDE" Command="history /stopafter:1 /version:T /format:detailed /recursive $(ProjectDir)">
<Output TaskParameter="Changeset" PropertyName="Changeset" />
</MSBuild.Community.Tasks.Tfs.TfsClient>
<Message Text="TFS ChangeSetNumber: $(Changeset)" />
<PropertyGroup>
<DefineConstants>ChangesetNumber=$(Changeset)</DefineConstants>
</PropertyGroup>
</Target>
I hope this help you.

Visual Studio Project - MSBuild Target - AfterBuild - Condition - Only When Binary File Updated

I have a long afterbuild process on my Visual Studio project file's after build target, as show below.
The issue is that it always runs the AfterBuild target when I hit build even when the actual source code has not changed and the project is not compiled.
How can I have this only run when the project has been compiled and the physical binary is written or update on the disk?
<Target Name="AfterBuild">
<Exec Command=""$(ProgramFiles)\Microsoft\ILMerge\ILMerge.exe" /copyattrs /log /target:library /targetplatform:4,C:\Windows\Microsoft.NET\Framework64\v4.0.30319 /Lib:"$(TargetDir)\" /keyfile:"$(ProjectDir)\Plugin.snk" /out:"$(TargetDir)\$(AssemblyName).merged.dll" "$(AssemblyName).dll" "PluginCommandCommon.dll" "Common.dll"" />
<Copy SourceFiles="$(TargetDir)\$(AssemblyName).merged.dll" DestinationFolder="$(ProjectDir)..\PluginPackage\bin\$(Configuration)\" />
</Target>
Option 1:
Instead of AfterBuild use AfterRebuild (one of MSBuild's many undocumented features):
<Target Name="AfterRebuild" >...</Target>
Option 2:
Hook up one of the incremental build's conditions:
<Target Name="AfterBuild" Condition=" '#(_SourceItemsToCopyToOutputDirectory)' != '' " >
UPDATE:
Using MSBuild Extension Pack's ILMerge task will allow better control, I.E check for each file existence:
<Target Name="ILMergeItems">
<ItemGroup>
<Input Include="C:\b\MSBuild.ExtensionPack.dll"/>
<Input Include="C:\b\Ionic.Zip.dll"/>
</ItemGroup>
<MSBuild.ExtensionPack.Framework.ILMerge
Condition="Exists('%(Input.FullPath)')"
InputAssemblies="#(Input)"
OutputFile="C:\a\MyNewAssembly.dll"/>
</Target>
There is a ComboBox in Properties>>Build Events>>Run the post-build event...if this is what you mean.

Resources