There is a webproject with a batchfile that generates all files needed on the targetserver and puts them in a folder "/Deployable" .
The batch file is quite involved because the project contains a pluginsystem and all plugins need to be copied to a certain location.
When I use webdeploy to deploy to the targetserver it happens what you expect: there are some of the needed assemblies copied over, but not the files as specified in the batchfile.
My plan is now to first execute the batchfile and then use webdeploy to copy the folder "/Deployable" to the targetserver. Can this be done with webdeploy?
This is what I see in Visual Studio deploy menue:
This is the resulting publish profile
<?xml version="1.0" encoding="utf-8"?> <publishData>
<publishProfile publishUrl="http://myserver/msdeployagentservice"
deleteExistingFiles="False"
ftpAnonymousLogin="False"
ftpPassiveMode="True"
msdeploySite="mysite/"
msdeploySiteID=""
msdeployRemoteSitePhysicalPath=""
msdeployAllowUntrustedCertificate="False"
msdeploySkipExtraFilesOnServer="False"
msdeployMarkAsApp="False"
profileName="publish_to_myserver"
publishMethod="MSDeploy"
replaceMatchingFiles="True"
userName="myuser"
savePWD="True" userPWD="xxx" SelectedForPublish="True" />
</publishData>>
I think there is an ability to add third-party files into webdeploy package by modifying .csproj file, however, I have never had to use it.
Alternatively, you can easily achieve the same result by using MSDeploy's command-line client and its sync verb, by specifying your /Deployable folder as the -source argument and your target server's msdeploy service as the -dest, e.g.:
$(WebDeployToolPath)\msdeploy -verb:sync -source:dirPath='Deployable\' -dest:dirPath='$(DeployDirectoryLocalPath)',computerName=$(DeployTargetURL),userName='$(DeployUserName)',password='$(Password)',authType='Basic' -verbose -allowUntrusted
Substitutions:
$(WebDeployToolPath) - full path to folder with msdeploy executable (e.g. c:\Program Files (x86)\IIS\Microsoft Web Deploy V3\msdeploy.exe )
Deployable\ - full path to the folder you wnat to copy to the target server.
$(DeployDirectoryLocalPath) - full local path to the target folder on the target server.
$(DeployTargetURL) - web deploy service URL (e.g. https://192.168.142.55:8172/MsDeploy.axd or http://myserver/msdeployagentservice)
$(DeployUserName) - username to be used for deployment (should be admin for Win 2003)
$(Password) - user's password.
That's it - this command will synchronize Deployable\ folder with $(DeployDirectoryLocalPath) folder (i.e. make the content exactly match).
You can wrap it into an msbuild target in your .csproj file:
<PropertyGroup>
<DeployTargetURL Condition="'$(DeployTargetURL)'==''">https://192.168.142.55:8172/MsDeploy.axd</DeployTargetURL>
<DeployUserName Condition="'$(DeployUserName)'==''">tergetServer\Administrator</DeployUserName>
<Password Condition="'$(Password)'==''">AdminPassword</Password>
<WebDeployToolPath Condition="'$(WebDeployToolPath)'==''">c:\Program Files (x86)\IIS\Microsoft Web Deploy V3\msdeploy.exe</WebDeployToolPath>
<Target Name="Deploy">
<Exec Command=""$(WebDeployToolPath)"\msdeploy -verb:sync -source:dirPath='Deployable\' -dest:dirPath='$(DeployDirectoryLocalPath)',computerName=$(DeployTargetURL),userName='$(DeployUserName)',password='$(Password)',authType='Basic' -verbose -allowUntrusted " />
</Target>
And than run it from the command-line in the following way:
%windir%\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe MyProject.proj /t:Deploy*
Related
I am trying to use .NET Core + Ionide + VS Code + Fake + Paket on macOS High Sierra.
Using the project generator, I have created a Suave application called Test. Ionide seems to have generated the appropriate files. After tweaking the TargetFramework to .NET Core, I can build successfully:
$ ./build.sh
...
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:00:03.72
Finished Target: Build
---------------------------------------------------------------------
Build Time Report
---------------------------------------------------------------------
Target Duration
------ --------
Clean 00:00:00.0026904
InstallDotNetCLI 00:00:01.2292511
Restore 00:00:04.2731055
Build 00:00:07.1234434
Total: 00:00:12.7035334
---------------------------------------------------------------------
Status: Ok
---------------------------------------------------------------------
There are now some files in Test/bin, but none of them are .exe, which is what I would expect as output from fsharpc.
Where does Ionide + Fake put the output executable?
My project has OutputType executable:
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Compile Include="Test.fs" />
</ItemGroup>
<Import Project="..\.paket\Paket.Restore.targets" />
</Project>
.Net Core compiles all projects (even executable applications) to .dll not .exe that can be run with dotnet PATH_TO_DLL. In the bin folder, in the subfolder for given framework target there should be file YOUR_PROJECT_NAME.dll that can be run with dotnet CLI.
To generate an exe you need to supply a run-time identifier. You can include this in the fsproj with
<PropertyGroup>
<RuntimeIdentifiers>win10-x64</RuntimeIdentifiers>
</PropertyGroup>
but you don't need to do that. You can use VSCode's tasks.json file to set up a build task.
My suggestion is just to run the dotnet CLI:
dotnet build -c Release -r win10-x64
This will create an exe in the bin\release\netcoreapp2.0\win10-x64 folder. You can also dotnet publish if you want a self-contained directory to deploy (this can get large). The id for OSX will be something like osx-x64.
By default ionide generates an fsproj file that is targetting net461, and you might also need Fake 5 for dotnetcore. I also suggest you use paket in magic-mode, and commit the .exe to github (if you use git).
During my build process I'm trying to copy a folder to the artifacts folder (\myserver\d$\TFBuild-Agent01\66\a).
So I put this in the .csproj file:
<Target Name="BeforeBuild">
<Exec
Command="xcopy.exe Databases "$(Build.ArtifactStagingDirectory)\Databases" /i /e /y /d" />
</Target>
This gets me
Error MSB4184: The expression """.ArtifactStagingDirectory" cannot be evaluated. Method 'System.String.ArtifactStagingDirectory' not found*
Everything I can find online says that $(Build.ArtifactStagingDirectory) is the way to do it. But it doesn't work.
Building with Visual Studio 2015 on TFS 2015
This doesn't work either:
<Exec
Command="xcopy.exe Databases "$($Env:BUILD_ARTIFACTSTAGINGDIRECTORY)\Databases" /i /e /y /d" />
The expression "$Env:BUILD_ARTIFACTSTAGINGDIRECTORY" cannot be evaluated.*
This doesn't error, but it looks like %BUILD_ARTIFACTSTAGINGDIRECTORY% gets replaced as an empty string:
<Exec Command="xcopy.exe Databases "%BUILD_ARTIFACTSTAGINGDIRECTORY%\Databases" /i /e /y /d" />
You have been mixing ways to access the build variables that the agent allows you. The syntax using $(some.variable) is interpreted by the agent itself. MSBuild has a similar looking syntax - $(PropertyName) - which does something different - it gives access to msbuild properties and does not allow for dots (.) in it's name, since you can use the dot to call functions on the value (e.g. $(OutputPath.Substring(3))).
When you want to reference build variables from MSBuild, you need to reference the environment variable that the agent sets. This is possible because MSBuild makes all environment variables accessible as global properties using its property syntax. The environment variable for Build.ArtifactStagingDirectory is BUILD_ARTIFACTSTAGINGDIRECTORY so you can use it in MSBuild using $(BUILD_ARTIFACTSTAGINGDIRECTORY).
I have been using it successfully in this script to default a property when run as part of a TFS/VSTS build (PublishBaseDir is a custom property used later):
<PropertyGroup>
<!-- Default artifact staging directory when built via VSTS / TFS agent -->
<PublishBaseDir Condition="'$(PublishBaseDir)' == '' and '$(BUILD_ARTIFACTSTAGINGDIRECTORY)' != '' ">$(BUILD_ARTIFACTSTAGINGDIRECTORY)</PublishBaseDir>
<!-- If not built on a known agent, use a "publish" subdir next to this file -->
<PublishBaseDir Condition="'$(PublishBaseDir)' == ''">$(MSBuildThisFileDirectory)publish\</PublishBaseDir>
<!-- Normalize directory if set manually or through ENV var -->
<PublishBaseDir Condition="!HasTrailingSlash('$(PublishBaseDir)')">$(PublishBaseDir)\</PublishBaseDir>
</PropertyGroup>
OK, I guess that because I'm using Visual Studio to build my solution, I can't access $(Build.StagingDirectory) from the .csproj. However, it's being passed on the command line to the "Visual Studio Build" build step as a property:
/p:OutDir="$(Build.StagingDirectory)"
So that can be accessed by doing
<Exec Command="xcopy.exe Databases "$(OutDir)\Databases" /i /e /y /d" />
How does one get the full physical path of the .sln file when scripting in MSBuild?
I'm trying to force nuget to download packages using:
<Target Name="BeforeCompileConfiguration">
<Exec Command=""$(ToolsHome)NuGet\NuGet.exe" restore "$(SolutionRoot)\KK\MyProject.sln"" />
</Target>
KK is the name of the folder that the .sln file is under. I'd like to replace
$(SolutionRoot)\KK\MyProject.sln
with a single $() build property.
$(SolutionPath)
should do your job!
By the way it's equivalent to:
$(SolutionDir)$(SolutionFileName)
I have two license files that I would like to include in my \bin directory both when I build and publish.
Both files are in the App_Data directory (their initial location doesn't matter, they just need to end up in the \bin) and have the following properties set:
Build Action = Content
Copy to Output Directory = Copy Always
They are in not the \bin when I build or publish.
What is wrong with my setup: the settings, the folders, the files, something else...?
UPDATE
I moved the files out of the App_Data directory and placed them in the project root and now they are copied to the \bin on build.
I've done this in a few projects by expanding my .csproject file slightly. The following code should be put directly beneath the Project node in your WebProject.csproj.
The AfterBuild target simply copies a set of files ("unreferenced DLLs" in this case) to the bin-folder when building normally from Visual Studio. The CustomCollectFiles basically do the same thing when deploying.
<PropertyGroup>
<UnreferencedDlls>..\lib\Unreferenced\**\*.dll</UnreferencedDlls>
</PropertyGroup>
<PropertyGroup>
<CopyAllFilesToSingleFolderForPackageDependsOn>
CustomCollectFiles;
$(CopyAllFilesToSingleFolderForPackageDependsOn);
</CopyAllFilesToSingleFolderForPackageDependsOn>
</PropertyGroup>
<Target Name="AfterBuild">
<Message Text="Copying unreferenced DLLs to bin" Importance="High" />
<CreateItem Include="$(UnreferencedDlls)">
<Output TaskParameter="Include" ItemName="_UnReferencedDLLs" />
</CreateItem>
<Copy SourceFiles="#(_UnReferencedDLLs)" DestinationFolder="bin\%(RecursiveDir)" SkipUnchangedFiles="true" />
</Target>
<Target Name="CustomCollectFiles">
<Message Text="Publishing unreferenced DLLs" Importance="High" />
<ItemGroup>
<_CustomFiles Include="$(UnreferencedDlls)" />
<FilesForPackagingFromProject Include="%(_CustomFiles.Identity)">
<DestinationRelativePath>bin\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
</FilesForPackagingFromProject>
</ItemGroup>
</Target>
The part you need to modify is basically the UnreferencedDlls node to match your folder structure. The **\*.dll part simply means "every DLL file at any level beneath here".
If you're using Visual Studio:
Show your file properties (Click on your file or Right-click on it then choose Properties)
At the Copy to Output Directory property choose Copy always or Copy if newer.
At build time, the file is going to be copied at the bin directory: Debug or Release...
not necessarily a direct answer, but I highly suggest not using the baked in "publish" mechanism, but rather wire up a build script (probably in powershell) that will do everything you need. It's really easy to hook into MSBuild as well as nUnit and also copy files and move them around.
POWERSHELL (rough) example.
# Get Directory Location
$invocation = (Get-Variable MyInvocation).Value
$directorypath = Split-Path $invocation.MyCommand.Path
# Build the application using MSBuild
cmd /c C:\Windows\Microsoft.NET\Framework\$v4_net_version\msbuild.exe "$directorypath\MyProject.sln" /p:Configuration=Release
# Run the tests using nUnit
cmd /c $directorypath\build\nunit\nunit-console.exe $solutionPath\MyProject.Tests\bin\debug\MyProject.Tests.dll
# Copy the license to the appropriate directory
Copy-Item -LiteralPath "$directorypath\mylicensefile.txt" "$directorypath\bin\release" -Force
# NOTE: You are going to have to adjust this to match your solution and projects.
In this post on Microsoft Connect the answer is much simpler:
Referenced assemblies in Unit Test are not copied in TestResults/Out
So what I did was the following:
[TestClass]
[DeploymentItem("Some.dll")]
public class SomeTests
{
...
}
It works fine for me.
Hope it help.
As part of an automated build, I clear out a directory, and copy the latest versions of the source files to this directory. First, I set up the list of files I wish to copy:
<CreateItem
Include="\\BuildServer\Build_Temp\SomeRootDirectory\**\*">
<Output
TaskParameter ="Include"
ItemName ="FilesToCopy"/>
</CreateItem>
And let my system know where my QA server is located at:
<CreateProperty
Value="\\QAWebServer\Websites\MySite">
<Output
TaskParameter="Value"
PropertyName ="MyDropLocation"/>
</CreateProperty>
I then remove and recreate my directory on the destination server to wipe out all files (this is a scorched earth build to make sure we're not accidentally leaving files not part of source control in our web directory).
<RemoveDir Directories="\\QAWebServer\Websites\MySite" />
<MakeDir Directories="\\QAWebServer\Websites\MySite" />
Finally, I execute a copy task:
<Copy
SourceFiles="#(FilesToCopy)"
DestinationFiles="#(FilesToCopy->'$(MyDropLocation)\%(RecursiveDir)%(Filename)%(Extension)')"
OverwriteReadOnlyFiles="True"/>
I then get the resulting error as it attempts to copy files. Interestingly, some make it and some don't (in this case, it looks like almost exclusively ones in the root of the directory I just created above):
C:\Build_Temp\QABuild\BuildType\TFSBuild.proj(690,3): error MSB3021: Unable to copy file "\\BuildServer\Build_Temp\SomeRootDirectory\Import.swf" to "\\QAWebServer\Websites\MySite\Import.swf". Access to the path '\\QAWebServer\Websites\MySite\Import.swf' is denied.
C:\Build_Temp\QABuild\BuildType\TFSBuild.proj(690,3): error MSB3021: Unable to copy file "\\BuildServer\Build_Temp\SomeRootDirectory\Incomplete.swf" to "\\QAWebServer\Websites\MySite\Incomplete.swf". Access to the path '\\QAWebServer\Websites\MySite\Incomplete.swf' is denied.
C:\Build_Temp\QABuild\BuildType\TFSBuild.proj(690,3): error MSB3021: Unable to copy file "\\BuildServer\Build_Temp\SomeRootDirectory\Index.html" to "\\QAWebServer\Websites\MySite\Index.html". Access to the path '\\QAWebServer\Websites\MySite\Index.html' is denied.
I've verified access rights to the filesystem (Everyone has access to create/modify/etc.), and there are no issues adding the files to the subdirectory structure on \QAWebServer\Websites\MySite, just (primarilly) to the root.
We finally had to fix this by switching over to an XCopy task.
<Exec Command="xcopy /E /R /Y \\buildMachine\Build_Temp\BuildSource
\\QAWebServer\Websites\MySite"/>