Best practice for automating Php project builds using Visual Studio Ultimate/Online and Git


We have an existing Php application that I'd like to integrate into my <em>very</em> simple MS Build process. Currently we are using Visual Studio 2013 Ultimate with Visual Studio Online (TFService) and Git to source control various C++, C# and this Php web applications (all in different Git repositories).

To develop our Php code inside of VS2013, we use Devsense's Php Extension (<a href="http://www.devsense.com/products/php-tools" rel="nofollow">http://www.devsense.com/products/php-tools</a>). This has been great, but doesn't natively support automated builds.

Has anyone setup automated builds for Php? The first goal would be to have the build process deliver a zip file to the cloud that can be downloaded by the web head. I want the zip file to <em>not</em> include the solution and project files, but rather to only include the files that we need on the web head.

Currently, if I create a simple out of the box "hello world" project using the Devsense template and put it in it's own Git repository on VS Online, the build breaks with the following error.

1 error(s), 0 warning(s) C:\a\src\PhpTest.sln - 1 error(s), 0 warning(s), View Log File C:\a\src\MyPhpSite\MyPhpSite.phpproj: The target "Build" does not exist in the project. C:\a\src\PhpTest.sln compiled No Test Results No Code Coverage Results



This requires editing your phpproj file and some knowledge of MSBUILD.

In order to edit your phpproj file:

<ul><li>Right-click your project ("MyPhpSite") and select "Unload Project".</li> <li>Right-click your project again and select "edit MyPhpSite.phpproj"</li> </ul>

at the end of the file, enter the following to pull in the "Build" target:

<Import Project="$(MSBuildToolsPath)\Microsoft.Common.targets" />

Since I'm not sure exactly how you plan on using the zip file, I'll assume you just want to have it available for download from Visual Studio Online.

Add an inline task for zipping the file.

<UsingTask TaskName="Zip" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll"> <ParameterGroup> <InputFileFolder ParameterType="System.String" Required="true" /> <OutputFileName ParameterType="System.String" Required="true" /> </ParameterGroup> <Task> <Reference Include="System.IO.Compression" /> <Using Namespace="System.IO.Compression" /> <Code Type="Fragment" Language="cs"> <![CDATA[ ZipFile.CreateFromDirectory(InputFolderName, OutputFileName); ]]> </Code> </Task> </UsingTask>

set the following PropertyGroup and ItemGroup

<PropertyGroup> <OutputPath>bin\</OutputPath> </PropertyGroup> <ItemGroup> <Payload Include="$(OutputPath)$(Name)" /> </ItemGroup>

Set the following targets, the last one being the one that moves the files to a single location and then zips them up.

<Target Name="CreateManifestResourceNames" /> <Target Name="CoreCompile" /> <Target Name="CopyFilesToOutputDirectory"> <MakeDir Directories="$(OutputPath)$(Name)" /> <Copy SourceFiles="@(Compile)" DestinationFiles="$(OutputPath)$(Name)\%(Identity)" /> <Copy SourceFiles="@(Content)" DestinationFiles="$(OutputPath)$(Name)\%(Identity)" /> <Zip InputFolderName="@Payload" OutputFileName="$(OutputPath)$(Name).zip/> </Target>

The Blank targets are there in order to keep MSBuild from throwing an error.

This will get you to having a successful build that ends in a zip file to download.


  • respondsToSelector - not working
  • Can I disable IE compatibility mode only for content within a ?
  • How to create a data template dependent on an XML Attribute?
  • Gforce min not supported for character in data.table
  • css calendar - td background diagonal split - two colors
  • Confirm box return value from alertify plugin and jquery
  • Multiple flexboxes with margin-right, except the last one in the row? Without JS?
  • How to get Fully qualified domain name in unix
  • How to resolve dependencies from one gradle project to another gradle project in my Eclipse workspac
  • passing parameter to DownloadStringCompletedEventHandler in C#
  • force json_encode to create strings
  • EF 4.1 DBContext AutoDetectChangesEnabled
  • Watson Conversation - Why is the ANYTHING ELSE node not chosen
  • pickle.PicklingError: args[0] from __newobj__ args has the wrong class with hadoop python
  • ImportError: cannot import name Pubnub
  • Flex items with same property values are rendering in different sizes
  • Django Haystack Rebuild Index
  • Using $compile in a directive triggers AngularJS infinite digest error
  • Django invalid literal for int() with base 10
  • How to view images from protected folder with php?
  • Ajax calls do not work in IE unless you fiddle with security settings
  • xtable package: Skipping some rows in the output
  • How to add git credentials to the build so it would be able to be used within a shell code?
  • Keep this build forever option - Jenkins
  • Display images in Django
  • C++ Partial template specialization - design simplification
  • Java: can you cast Class into a specific interface?
  • Resize panoramic image to fixed size
  • AES padding and writing the ciphertext to a disk file
  • Updating server-side rendering client-side
  • How to extract text from Word files using C#?
  • Where to put my custom functions in Wordpress?
  • How to show dropdown in excel using jrxml (jasper api)?
  • Importing jscolor library in angular 2
  • Function pointer “assignment from incompatible pointer type” only when using vararg ellipsis
  • Run Powershell script from inside other Powershell script with dynamic redirection to file
  • Windows forms listbox.selecteditem displaying “System.Data.DataRowView” instead of actual value
  • Linking SubReports Without LinkChild/LinkMaster
  • XCode 8, some methods disappeared ? ex: layoutAttributesClass() -> AnyClass
  • Observable and ngFor in Angular 2