Invoke remote MSBuild script inside a MSBuild script with cygwin sshd - msbuild

I'm trying to do some MSBuild automation for deploy and backup. I tried several different remote execution platforms (Powershell/WMI, PsExec and Cygwin) and had some troubles with all of them.
With Powershell and PsExec, I think the problem is some security baselines used on the machines. I don't have full control of the machines and domain.
The most stable scenario I found is with cygwin/openssh. But when I'm running plink inside MSBuild and trying to invoke MSBuild remotely, msbuild hangs without telling me the error. If I run directly plink from prompt, everything works fine.
The MSBuild script follows:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Plink>"c:\Program Files (x86)\PuTTY\plink.exe"</Plink>
<UserName></UserName>
<Password></Password>
<HostName>localhost</HostName>
<RemoteCommand2>/cygdrive/c/SandBox/remotemsbuild/echoalotoffiles.bat</RemoteCommand2>
</PropertyGroup>
<Target Name="Build">
<Exec Command="$(Plink) -l $(UserName) -pw $(Password) -batch $(HostName) $(RemoteCommand2)" />
</Target>
<Target Name="EchoALotOfFiles">
<ItemGroup>
<SandBoxFiles Include="$(MSBuildProjectDirectory)\..\**\*.*" />
</ItemGroup>
<Message Text="#(SandBoxFiles)" />
</Target>
</Project>
When I run the first target, Build, I have the issue (MSBuild hanging)
Microsoft (R) Build Engine version 4.0.30319.17929
[Microsoft .NET Framework, version 4.0.30319.17929]
Copyright (C) Microsoft Corporation. All rights reserved.
Build started 02/11/2013 12:01:45.
Project "C:\SandBox\remotemsbuild\remotemsbuild.build" on node 1 (EchoALotOfF
iles target(s)).
EchoALotOfFiles:
If I run just plink from command line, everything works fine.
Any guesses?

Related

MSBuild ClickOnce app: FTP Upload files after build

I am using MS build to publish my ClickOnce app, in Visual Studio 2017 developer command line to a remote ftp site.
How do I initiate the FTP file upload that starts in Visual Studio after build? This is my command line, which builds the project:
msbuild /target:publish -property:Configuration=Release /p:PlatformTarget=x86 "%USERPROFILE%\VSProjects\IIC\IIC.UI.vbproj"
There are 2 problems with command line Click Once deployment: (1) Auto Incrementing option from the publish property page of a project is not honored from the command line, and (2) the subject of the question, starting the FTP upload to the remote site.
Solution (with Visual Studio 2017 Developer Command Prompt v15.7.3)
Download community ms build tasks from here: https://github.com/loresoft/msbuildtasks
Unload the project and open with notepad++ or your editor of choice and import the community ms build tasks. Follow the instructions on their github page.
Add file ProjectName.version.txt with just one line with the version information of your project. For example:
1.2.78.1341
The numbers correspond to {Major}.{Minor}.{Build}.{ApplicationRevision}
Add the following target to the bottom of the project, which uses the Version and FileUpdate community tasks:
<Target Name="beforePublishCmd">
<Message Text="revision before: 3.0.0.$(ApplicationRevision)"/>
<Version VersionFile="ProjectName.version.txt" BuildType="Automatic" Major="3" Minor="0" Build="0" RevisionType="Increment">
<Output TaskParameter="Major" PropertyName="Major" />
<Output TaskParameter="Minor" PropertyName="Minor" />
<Output TaskParameter="Build" PropertyName="Build" />
<Output TaskParameter="Revision" PropertyName="ApplicationRevision" />
</Version>
<Message Text="revision after: 3.0.0.$(ApplicationRevision)"/>
<FileUpdate Files="ProjectName.vbproj"
Regex="<ApplicationRevision>(\d+)"
ReplacementText="<ApplicationRevision>$(ApplicationRevision)" />
</Target>
Call the above target from the command line BEFORE calling the publish target, like so:
msbuild /target:beforePublishCmd -property:Configuration=Release /p:PlatformTarget=x86 "%USERPROFILE%\VSProjects\ProjectName.vbproj"
Add an "afterPublish" target, which uses the FtpUploadDirectoryContent community task. This target is automatically called after the publish target finishes.
<Target Name="afterPublish">
<PropertyGroup>
<CurrentDate>$([System.DateTime]::Now.ToString(yyyy MMM dd HH:mm:ss))</CurrentDate>
</PropertyGroup>
<FtpUploadDirectoryContent
ServerHost="projectname.org"
Username="*****"
Password="*****"
LocalDirectory=".\bin\Release\app.publish"
RemoteDirectory="/"
Recursive="true"
/>
<Exec Command="C:\Progra~1\TortoiseSVN\bin\svn commit ..\ --non-interactive --message "Release 3.0.0.$(Revision) on $(CurrentDate): $(commitMessage)""/>
</Target>
Finally, call the publish target from the command line:
msbuild /target:publish -property:Configuration=Release /p:PlatformTarget=x86 "%USERPROFILE%\VSProjects\ProjectName.vbproj"
MSBuild ClickOnce app: Upload files after build
You can add a copy task into your project file to upload files after build:
To accomplish this, unload your project. Then at the very end of the </project>, just before the end-tag, place below scripts:
<ItemGroup>
<UploadFiles Include="ThePathOfYourUploadFiles\*.*"/>
</ItemGroup>
<Target Name="AfterBuild">
<Copy
SourceFiles="#(UploadFiles)"
DestinationFolder="PathWhereYouWantTouploadYourUploadFiles"
/>
</Target>
With this target, Visual Studio/MSBuild will upload the files after build.
Hope this helps.

How to use MSBuild to build multiple platforms

I am using Visual Studio online build with an MSBuild task. I currently have the following MSBuild Arguments fed to my task:
/p:Configuration=Release;AppxBundle=Always;AppxBundlePlatforms="x86|x64|ARM";AppxPackageDir="$(Build.BinariesDirectory)\AppxPackages\\";UapAppxPackageBuildMode=StoreUpload
This creates my application in x86, x64 and ARM. It creates Release version of the libraries in x86 BUT creates Debug version of my libraries in x64 and ARM.
When my .appxupload package is creates it fails Windows Certification tests because my libraries are built in debug.
How can I make MSBuild build for all 3 configurations. My guess is because I haven't provided a /platform configuration. How do I provide this configuration for 3 platforms?
I have tried platform="x86|x64|ARM" but it returned an error
For a standard project file there's no way to do this in a single command. Either use multiple commands to build the project for each platform/configuration combination needed, or use a 'master' build file which does the same for you, something like:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="FullRebuild">
<Target>
<ItemGroup>
<Configurations Include="Debug;Release"/>
<Platforms Include="x86;x64;ARM"/>
<ConfigAndPlatform Include="#(Configurations)">
<Platform>%(Platforms.Identity)</Platform>
</ConfigAndPlatform>
</ItemGroup>
<MSBuild Projects="myproject.sln" Targets="Build"
Properties="Configuration=%(ConfigAndPlatform.Identity);Platform=%(ConfigAndPlatform.Platform)"/>
</Target>
</Project>

Why is MSBuild trying to run the projects it's building?

I'm currently writing an msbuild script to build a solution I've been working on, as well as run its tests. On my development machine, this works as expected. However, when I try to run the same build script on our build server, I get several failures. I've tracked the source of the problem down to the fact that my build script appears to be trying to run the .exe file associated with my application. This line during the script execution tipped me off, since it doesn't run that command on my dev box:
MSIAuthoring:
Building MSI
"C:\Program Files (x86)\Jenkins\workspace\Test Build\BuildArtifacts\MsiBuildTool.exe" "/MBSBUILD:MsiBuildTool"
I'm fairly new to build scripting, but my understanding is that the build script shouldn't be trying to run my program unless I explicitly tell it to do so. Does anyone know what might be causing this?
For reference, here is my build script:
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="RunTests"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<BuildArtifactsDir Include="BuildArtifacts\"/>
<SolutionFile Include="MsiBuildTool.sln"/>
<NUnitConsole Include="C:\Program Files (x86)\NUnit 2.6.4\bin\nunit-console.exe"/>
<UnitTestsDll Include="BuildArtifacts\MsiBuildToolUnitTests.dll"/>
<TestResultsPath Include="BuildArtifacts\TestResults.xml"/>
</ItemGroup>
<PropertyGroup>
<Configuration Condition="'$(Configuration)' == ''">Release</Configuration>
<Platform Condition="'$(Platform)' == ''">Any CPU</Platform>
</PropertyGroup>
<Target Name="Init" DependsOnTargets="Clean">
<MakeDir Directories="#(BuildArtifactsDir)"/>
</Target>
<Target Name="Clean">
<RemoveDir Directories="#(BuildArtifactsDir)"/>
</Target>
<Target Name ="Compile" DependsOnTargets="Init">
<MSBuild Projects="#(SolutionFile)"
Targets ="Build"
Properties ="OutDir=%(BuildArtifactsDir.FullPath);Configuration=$(Configuration);Platform=$(Platform)"/>
</Target>
<Target Name="RunTests" DependsOnTargets="Compile">
<Exec Command='"#(NUnitConsole)" #(UnitTestsDll) /xml=#(TestResultsPath)'/>
</Target>
</Project>
Update:
After some digging through the output, I found that "MSIAuthoring" step was the result of the Wix# library that I'm using. As described by this thread: https://wixsharp.codeplex.com/discussions/644609#
I disabled the MSIAuthoring step by removing this line in my .csproj files:
<Import Project="..\packages\WixSharp.1.0.22.3\build\WixSharp.targets" Condition="Exists('..\packages\WixSharp.1.0.22.3\build\WixSharp.targets')" />
You're building solution file, thus MSBuild will generate msbuild-xml script first and then will build it. To find why it's being called on build machine but not on your dev machine - follow this advice and obtain generated MSBuild scripts from your dev environment and your build server. Then compare it.
Also enable diagnostic logging (/verbosity:diag in the command line) as Lex Li advised, and you'll see detailed decisions why each target being run or not - grep logs for something like "Conditions A, B, C on target BuildMSI evaluated to False" and this will show you the difference between environments.
It might be some type of post-build script on one of the projects which builds MSI only if it's being run not on dev environment - check actual build script to find where it comes from. Also check that it's really related to your build script, and it's not an extra build step in your Jenkins build configuration.

MSBuild publish web project from command line does Package instead of FileSystem

I have a web project that I am publishing from the command line, using a publish profile that does a few additional tasks (excludes some files and folders, grunt, publishing another project in turn).
One two machines (A and B), it works fine from right-click > Publish... in Visual Studio, and choosing the correct publish profile.
Historically, on both machines, it has also worked with the following command line:
msbuild MyProject.csproj /p:Configuration=Release /p:DeployOnBuild=true /p:PublishProfile=myProfile /v:n
However now, machine B is not publishing correctly.
The publish profile is configured with <WebPublishMethod>FileSystem</WebPublishMethod at the top, however from the logs, it is attempting a Package publish type instead, for no apparent reason.
Here is the full publish profile:
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<WebPublishMethod>FileSystem</WebPublishMethod>
<LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
<LastUsedPlatform>Any CPU</LastUsedPlatform>
<SiteUrlToLaunchAfterPublish />
<LaunchSiteAfterPublish>True</LaunchSiteAfterPublish>
<ExcludeApp_Data>False</ExcludeApp_Data>
<publishUrl>..\Production</publishUrl>
<DeleteExistingFiles>False</DeleteExistingFiles>
<ExcludeFoldersFromDeployment>Content;Scripts;Pages</ExcludeFoldersFromDeployment>
<ExcludeFilesFromDeployment>index-dev.html;index.html;debug.html;JSLintNet.json;Gruntfile.js;package.json;packages.config;publishall.bat;publishapi.bat</ExcludeFilesFromDeployment>
<BuildDependsOn>
$(BuildDependsOn);
RunGrunt;
PublishApi;
</BuildDependsOn>
</PropertyGroup>
<Target Name="RunGrunt">
<Message Text="Running grunt production..." />
<Exec Command="grunt production" />
</Target>
<Target Name="PublishApi">
<Message Text="Publishing API..." />
<Exec Command="publishapi" />
</Target>
</Project>
As you'd expect, because it is just doing a Package, no files ever appear in the publishUrl directory. Again, the publish profile works fine from VS2013, using right-click publish.
In the log on machine A I get this excerpt:
**ValidatePublishProfileSettings**:
Validating PublishProfile(myProfile) settings.
But in machine B it doesn't appear.
Later in the log on machine A it contains:
**WebFileSystemPublish**:
Creating directory "..\Production".
Copying obj\Release\Package\PackageTmp\cache.manifest to C:\SVN\Trunk\src\Web Sites\MyProject\..\Production\cache.manifest.
Copying obj\Release\Package\PackageTmp\Global.asax to C:\SVN\Trunk\src\Web Sites\MyProject\..\Production\Global.asax.
Copying obj\Release\Package\PackageTmp\Web.config to C:\SVN\Trunk\src\Web Sites\MyProject\..\Production\Web.config.
Copying obj\Release\Package\PackageTmp\bin\MyProject.dll to C:\SVN\Trunk\src\Web Sites\MyProject\..\Production\Blithe.Web.Collect.dll.
but later in the log on machine B, in place of the above, it contains:
**Package**:
Invoking Web Deploy to generate the package with the following settings:
$(LocalIisVersion) is 7
$(DestinationIisVersion) is 7
$(UseIis) is True
$(IisUrl) is <<<some url>>>
$(IncludeIisSettings) is False
$(_DeploymentUseIis) is False
$(DestinationUseIis) is False
The only difference I can think of between the two machines, is that I installed an update on machine B (the problem machine) for 'Windows Azure SDK for .NET (VS2013) - 2.3'. Any ideas how and why this might have broken it?
I tried adding /p:PublishProfileRootFolder="Properties\PublishProfiles" as mentioned here but this didn't work.
Adding:
/p:VisualStudioVersion=12.0
to the command worked.
Machine B had Visual Studio 2008 installed on it as well, whereas Machine A didn't. Setting the version to 12.0, or even 11.0 works. Setting it to 10.0 ignores the publish profile and just does a package install.
Surprisingly it seems to default to 10.0.
This issue did not emerge until the update to Azure SDK 2.3, which DID have some changes to Web Publish, so that may well have led to this issue.

Running a .net executable from an msbuild project in a platform independent way

I'm working on a .NET library, and I want the build script to be so generic that it can run from both the MS .NET framework, and from a mono installation on a Mac/Linux machine.
The problem here is running NUnit. I have downloaded the nunit executable and placed it in a lib folder. In order to execute it on my Mac, I have to write the following in my build script
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
...
<Target Name="Test" AfterTargets="Compile">
<Exec Command="mono lib/NUnit/nunit-console.exe $(OutputAssembly)" />
</Target>
</Project>
The thing is the "mono" part, which ties the build script to the mono framework. Is there a way I can write this build script so it will run on both on the MS .NET framework, and the Mono framework?
Now my problem here relates to NUnit. But it might as well be any other .NET executable.
You can use platform conditions, like this:
<Exec Command="foo.exe arg1 arg2" Condition=" '$(OS)' == 'Windows_NT' " />
to execute conditionally. The equivalent mono condition would be either "Unix" or "OSX" instead of "Windows_NT".
For more information have a look here:
http://www.mono-project.com/Porting_MSBuild_Projects_To_XBuild#Platform_specific_items
How about the following (tested) proposal:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ManagedExeLauncher Condition="('$(OS)' != 'Windows_NT')">mono </ManagedExeLauncher>
...
</PropertyGroup>
...
<Target Name="Test" AfterTargets="Compile">
<Exec Command="$(ManagedExeLauncher)lib/NUnit/nunit-console.exe $(OutputAssembly)" />
</Target>
</Project>