Is there any task to copy files from TFS to a folder? - tfs

Scenario: I need as part of my deploy scripts I have a task that copy files from a source to a origin.
Now I have to change the source. Instead of being a normal folder it has to be a location in my TFS.
Is there any task to do it? I can't find any.
I am trying to get the files manually from TFS using something similar to:
<PropertyGroup>
<TF>"C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\tf.exe"</TF>
<TFSourceLocation>$/TFSDIR</TFSourceLocation>
<SolutionRoot>.</SolutionRoot>
<RemoteWebRoot>$(DestinationRoot)\DIR</RemoteWebRoot>
<Copy>xcopy /E /I /R /Y</Copy>
</PropertyGroup>
<Exec Command="$(TF) get $(TFSourceLocation) /force /recursive /version:T /noprompt" ContinueOnError="true" />
I don't have to compile anything. I only need to copy some files that now are stored in TFS to a folder.
Question: Is this the best approach? or exists a task that allows me to copy from TFS to a folder?

I don't understand your question completely, but if you want to download some files from TFS to a folder on the build server, the command you are using is the best option.
Only be aware that you need a workspace configured so TFS knows where to download the files to.
Another option is to use the TF VIEW command:
tf view $/myitem /console /collection:http://mytfsserver:8080/tfs/defaultcollection >c:\localfile
This will show the contents of the item to the console and prints it to c:\localfile. You then get around the workspace issue.

Related

Prevent TFS Build Definition Source Settings from triggering a build

When I create a build definition I have setup some source settings, example below:
Problem is I want it to trigger a build when someone checks into the Builds or Install folders, but the Includes folder is just some libraries and other items it needs. I don't want it to re-run when these libraries are changed. However I need to set them up here to make sure they are copied across to the Build drop server. Is there a way to copy across this Includes folder without forcing a build trigger when someone checks in to this folder?
There are 2 things to do to approach this.
First you need to get your source folders into a build centric layout, this will help to eliminate as much overlapping as possible.
If you need a particular shared folder that shouldn't trigger a build, then don't include it in the source mappings, instead add a script to download the files to your workspace as an early part of the build.
The example will need updating for your visual studio version, and you should pass the sources Directory to the script.
REM %1 represents the Sources directory
REM Compute variables
SET TfExe="%ProgramFiles(x86)%\Microsoft Visual Studio 10.0\Common7\IDE\TF.exe"
REM SET TfExe="C:\Program Files\Microsoft Visual Studio 10.0\Common7\IDE\TF.exe"
Set RefPath="$/TFS BUILDS/Shapes/Main/Includes"
Set localPath="%~1\Includes"
REM set the Drive Letter for this build
Set Localdrive=%localPath:~1,2%
%Localdrive%
cd %1
REM Map the folders
%TfExe% workfold /map %RefPath% %localPath%
REM Get the required content
%TfExe% get %RefPath%
REM Unmap the folders
%TfExe% workfold /unmap %RefPath%
There is no easy way to do this. As you've discovered, the source settings do double-duty, they define the set of files needed for the build that are downloaded and the set of files that trigger a CI.
I would argue this isn't a problem, if the Includes are used in your build, then I would want to kick off a new build when they change, to ensure that the change didn't break anything in the build process.
Use the special keyword ***_NO_CI*** in your checkin into the Includes directory.
See this post for further details.

MSBuild not copying files with PublishProfile

I have a Visual Studio 2013 solution with the full Orchard source code. When I use "Publish..." on the "Orchard.Web" project in Visual Studio, it correctly publishes the site to the File System destination I've configured into the .PubXml file that I used.
However, if I build this site using Jenkins, the files do not get copied to the destination. I've created a separate PubXml file that is used by Jenkins.
In my Jenkins job, I have two Build steps of interest. The first uses the src\Orchard.sln file with a command line argument of /p:Configuration=Release. This runs correctly, and builds the entire solution.
The second Build step, immediately after, uses the Build File of src\Orchard.Web\Orchard.Web.csproj and these command line arguments:
/p:DeployOnBuild=true
/p:PublishProfile="D:\workspace\Site\trunk\src\Orchard.Web\Properties\PublishProfiles\Jenkins.pubxml"
/p:VisualStudioVersion=12.0
/p:Configuration=Release
/p:Platform=AnyCPU
/v:minimal
/nologo
/p:WarningLevel=1
With this, the build and deploy seems to work - but doesn't. Here are some lines from the build output:
Copying all files to temporary location below for package/publish:
obj\Release\Package\PackageTmp.
Auto ConnectionString Transformed obj\Release\Package\PackageTmp\Shapes\Scripts\Web.config into obj\Release\CSAutoParameterize\transformed\Shapes\Scripts\Web.config.
(... about 200 more "Auto ConnectionString..." lines...)
Finished: SUCCESS
No where does it actually copy the files to the destination defined in the PUBXML file.
In contrast, in Visual Studio, the output looks similar, but transforms only 4 config files and includes lots of "Publishing folder x" lines:
(...)
Transformed Modules\SH.GoogleAnalytics\web.config using ....
Copying all files to temporary location below for package/publish:
obj\Release\Package\PackageTmp.
Publishing folder /...
Publishing folder bin...
(etc.)
(I have installed the latest Windows Azure SDK for .NET on the Jenkins server.)
I have the same trouble,that work for me:
/t:Rebuild
/p:DeployOnBuild=true
/p:PublishProfile=Jenkins_Publish
/p:Configuration=Release
do not use /p:VisualStudioVersion=xxx
This is kind of old, but I actually just set up Orchard to be able to get built via command line and MSBuild. Here is what I did:
/p:VisualStudioVersion=12.0;PublishProfile="example-profile";DeployProjA=true;FrameworkPathOverride="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\v4.5";Configuration=Release;PublishProfileRootFolder=c:\Workspace\src\Orchard.Web\Properties\PublishProfiles;Password=ExamplePass
Since you are using Orchard you want to make sure that only the Orchard.Web project gets published so do not use DeployOnBuild=true. This will attempt to deploy every web project in the solution, which is a lot for Orchard. Instead follow the guidelines here to see how to deploy only the web project: http://sedodream.com/2013/03/06/HowToPublishOneWebProjectFromASolution.aspx

How do I get tf.exe to set the Source Control Folder to something other than the root?

So I am trying to script with TFS using the tf.exe command. I've looked at the docs but I can't seem to determine how to set the server path such that I don't get the intermediate path in my local directory.
E.g. The server has a dir that I want to get called $/Some/Depth/TargetDir and I want to put it in C:\MyFolder\StoreHere such that all files in TargetDir and all directories beneath it are stored in StoreHere.
Currently, I'm using tf get $/Some/Depth/TargetDir /recursive which results in the files in TargetDir to be downloaded, but in to C:\MyFolder\Storehere\Some\Depth\TargetDir which is not what I want.
I'm using TFS 2010.
Workspace mappings control where server paths are retrieved to your local paths. In the behavior you describe, you have a workspace mapping that resolves $/Some/Depth/TargetDir to C:\MyFolder\Storehere\Some\Depth\TargetDir.
Not having seen your actual workspace mappings, it's impossible for me to know exactly why, but this could be as simple as having a workspace mapping from $/ to C:\MyFolder\Storehere.
Instead, you need to map the actual directory you're interested in: you need a mapping from $/Some/Depth/TargetDir to C:\MyFolder\Storehere.
You will need to delete the existing, incorrect mapping first.
You could set this up in the Visual Studio Edit Workspace dialog, or you could use the command-line client:
tf workfold /unmap C:\MyFolder\Storehere
tf workfold /map $/Some/Depth/TargetDir C:\MyFolder\Storehere

TFS 2010 Team Build - rename a file

As part of my TFS 2010 team build, I'm trying to copy a configuration file from a network location to the output folder where the build goes to.
Using xcopy as an invoke process task, I've successfully gotten it all working EXCEPT that I want to rename the file as part of the copy. The problem is that if you supply a different destination filename, XCOPY asks if the destination is a file or a directory e.g.
XCOPY \\networkshare\configs\live.config \\networkshare\release\server.exe.config /R /Y
results in XCOPY asking me to press F if server.exe.config is a file or D if it's a directory. XCOPY doesn't seem to have any way to suppress this behaviour. I've tried using the basic COPY commmand but Team Build just says that it doesn't recognise the COPY command.
Is there any way to easily rename a file as part of Team Build or use another command line tool to achieve this?
Cheers
Just to confirm - setting the process as CMD.EXE and starting the arguments as "/c copy" does the trick.

Can you do a TFS get without needing a workspace?

I'm trying to change our build scripts from using SourceSafe to TFS without using MsBuild (yet).
One hiccup is that the workspace directory is renamed and archived by the scripts, which makes TFS think it doesn't need to get any files. Even with the /force flag it just gets the directories without getting the source files.
I am currently using
TF.exe get "Product/Main/Project1" /force /recursive /noprompt
To save me managing workspaces in the scripts or using intermediate directories, does anyone know of a command that can get directories and code without needing a workspace?
It's not possible to run a tf get without a workspace. The reason is that the server needs to know the mapping between the server paths and the local paths.
If you are working with a large number of files, it is not a good idea to:
Create & Delete a new workspace every time
Or, Create a new workspace (and then never delete it)
The reason for this is that every time you do a Get, the server keeps track of which files, at which versions were downloaded to which workspace. If you never clean up these workspaces, then the table that stores this information will grow over time.
Additionally, if you are creating & deleting a workspace all the time, the server has to write all these rows, then delete them when you are done. This is unnecessary.
You really should try and reuse the same workspace each time. If you do, the server is very efficient about only sending you files that have changed since you last downloaded them. Even if your build is moving from one branch to another, you can use tf get /remap which is sometimes more efficient if the branches share common files.
Although it doesn't solve your problem, it is possible to list files and download files without a workspace.
To list files:
tf dir $/Product/Main/Project1 /R
To download a file:
tf view $/Product/Main/Project1/file.cs
With a creative batch file, you can string these two together with a FOR command. However I would recommend trying to solve your workspace problem first, since that is the way that TFS was intended to be used.
A workspace is a mapping between the source repository location and the filesystem location, so no you can't get away with not using a workspace. But you can easily set up and tear down a workspace when you need to.
Here is a simple TFS task i use to get my database source files from TFS prior to doing some text substitutions and building them into a database update package. You can easily translate this to whatever syntax your current build scripts require:
<Target Name="GetDatabaseSources">
<!-- clean out the folder before doing the fresh get of the database sources -->
<Folder.CleanFolder Path="$(DatabaseBuildBaseLocation)" Force="true"/>
<!-- create a workspace for the database source of the product -->
<CallTarget Targets="CreateDatabaseSourceWorkspace" />
<!-- get the database sources for the product -->
<Get TeamFoundationServerUrl="$(TeamFoundationServerUrl)" Workspace="$(DatabaseSourceWorkspaceName)" Recursive="true" Version="$(DatabaseSourceVersion)" Force="true" />
<!-- delete the workspace -->
<Exec Command="$(Tf) workspace /delete $(DatabaseSourceWorkspaceName) /server:$(TeamFoundationServerUrl) /noprompt " ContinueOnError="true" />
</Target>
<!-- creates and maps a temporary workspace for the database source of the product -->
<Target Name="CreateDatabaseSourceWorkspace">
<Exec Command="$(Tf) workspace /delete $(DatabaseSourceWorkspaceName) /server:$(TeamFoundationServerUrl) /noprompt " ContinueOnError="true" />
<Exec Command="$(Tf) workspace /new $(DatabaseSourceWorkspaceName) /server:$(TeamFoundationServerUrl) /noprompt" />
<Exec Command="$(Tf) workfold /unmap /workspace:$(DatabaseSourceWorkspaceName) $/" />
<Exec Command="$(Tf) workfold /map /workspace:$(DatabaseSourceWorkspaceName) /server:$(TeamFoundationServerUrl) $(DatabaseSourceLocation) "$(DatabaseBuildBaseLocation)"" />
</Target>
TFS is your source repository, but you didn't explicitly mention what your build scripts were designed for. You really should migrate them to a TFS build script, then you can simplify your build, for example you won't have to worry about mapping workspaces or getting the latest source code because TFS does that for you, all you have to worry about is any custom build steps and possibly archiving your build results.
Neno Loje created a small utility that does exactly what you need. To boot it can also remove any source control bindings from the solution and project file, should you need that.
C# has the VersionControlServer library and you can use VersionControlServer.GetItems call to fetch TFS Item. If the ItemType is File then call DownloadFile to retrieve the file.
I don't know why your buildscripts delete the workspace directories everytime. But to answer your question I don't think you can get source code from TFS without a workspace. Maybe you can try to create a worspace everytime before you to a get. The command is
tf.exe workspace /new
You could do this easily with SourceSafe: get any version to any specific directory you wanted. And it was very often very convenient. There are often occasions why one would want to do this. Shame (if) TFS does not support it, it is a missing functionality, imho.

Resources