How to work with tfs files from code? - tfs

I have a desktop application to modify some xml files that are under source control. The program should be able to get the files, modify them and make a checkin. I already know how to do all that with tf; however, I don't know how to run the developer command prompt for visual studio using code. Also, the program will be installed in computers that doesn't have visual studio; therefore, they won't have the tf command anywhere. Taking into account all that, what would be the best way to run the following commands?
mkdir C:\Temp\PROGRAM
cd C:\Temp\PROGRAM && tf workspace /new /noprompt PROGRAM /collection:"http://myserver:8080/tfs/mycollection"
cd C:\Temp\PROGRAM && tf workfold /map $/my/server/route/to/map C:\Temp\PROGRAM
cd C:\Temp\PROGRAM && tf get
I know that there are some libraries to work with tfvc, but I haven't used them and don't seem as clear as running the commands. Any solution that manage to do the same as the commands above will be welcomed.
Create workspace
Map a folder from the server to a local folder
Download (checkout) all files in that folder (doesn't need to be recursive)
If possible to include in the solution:
Make checkin of files changed
EDIT
The code that I finally used is this
static void Load(string local, string server, Uri urlCollection)
{
Directory.CreateDirectory(local);
Workspace workspace = GetWorkspace(urlCollection, "MyWorkspaceName");
workspace.Map(server, local);
workspace.Get();
}
static Workspace GetWorkspace(Uri urlCollection, string name)
{
VersionControlServer vcs = new TfsTeamProjectCollection(urlCollection)
.GetService<VersionControlServer>();
try
{ return vcs.GetWorkspace(name, vcs.AuthorizedUser))}
catch(Exception)
{ return vcs.CreateWorkspace(name, vcs.AuthorizedUser)); }
}

According to your description, you want to pull down files from TFS server and then check in changed files programmatically.
You could use TFS client API to achieve this. Suggest you go through Buck Hodges's blog which shows how to create a workspace, pend changes, check in those changes.
Please refer Team Foundation Version Control client API example for TFS 2010 and newer
As for how to get files from TFS, there are also multiple samples in web portal, suggest you use the VersionControlServer.GetItem Method
Examples of usage:
// Get the latest Item for local path "C:\projects\myfiles.cs"
Item item1 = versionControlServer.GetItem("C:\projects\myfiles.cs");
// Get ItemId = 12345 for changesetId = 54321
Item item2 = versionControlServer.GetItem(12345,54321);
// Get the latest Item for server path "$/ProjectName/myfile.cs"
Item item1 = versionControlServer.GetItem("$/ProjectName/myfile.cs", VersionSpec.Latest);
You could also select a history version of source code to pull down, for the entire code, please refer below tutorials: Team Foundation Server API: Programmatically Downloading Files From
Source Control
Another way is using powershell script to handle this, please take a look here: Download files from TFS server with PowerShell

You can install on the computers the Team Explorer Everywhere, it gives you the ability to use TFS command line (the "tf" commands) without Visual Studio.

Related

TFS tf branch command error: no appropriate mapping exists for

I'm trying to use tf branch, but get this error:
no appropriate mapping exists for $/main_folder/folderB/folder1
below is my command:
tf branch $/main_folder/folderA/folder1/file.sql $/main_folder/folderB/folder1
Any ideas why?
The branch command copies an item or set of items, including metadata and version control history, from one location to another in the Team Foundation version control server and in the local workspace.
According to above error info, you also need to map your $/main_folder/folderB/folder1 path to your local workspace. Then try to perform the command again.
More detail tutorial about how to use this command please refer this official tutorial: Branch Command
A sample full command in cmd with using tf.exe branch command for your reference:
tf branch $/ScrumProject/TestCaseProject $/ScrumProject/Test /w:WPATRICK-W10

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.

Jenkins Build Fails when trying to using MSBuild Extensions - Unable to determine the source control server

I am trying to use Jenkins in combination with MSBuildExtensions and TFS to transform AssemblyInfo.cs
On my dev box, everything works, fine, including the connection to TFS, which returns the changeset number correctly.
When I check in a changeset, and try and build on the Jenkins server, I get an error and the build breaks on this command:
Resolve TF.exe path
TF.exe path resolved to: C:\Program Files\Microsoft Visual Studio 9.0\Common7\Tools\..\IDE\tf.exe
TF Operation: GetChangeset
Executing C:\Program Files\Microsoft Visual Studio 9.0\Common7\Tools\..\IDE\tf.exe changeset /login:myDomain\SomeUser,myPassword /latest /noprompt
C:\Program Files\Jenkins\jobs\DemoVersioning\workspace\VersioningDemo\VersioningDemo.csproj(513,3): error : Exit Code 100. Nothing Succeeded: Unable to determine the source control server.
In my msbuild script, this is the TFS command I am running on "BeforeBuild":
<TfsSource TaskAction="GetChangeset"
Login="myDomain\someUser,password">
<Output TaskParameter="Changeset" PropertyName="ChangeSet" />
</TfsSource>
I think this has something to do with the workspace being missing - but Jenkins pulls everything down fine, so shouldn't the workspace exist?
Some guidance would be appreciated as I am starting to go bald over this.
Supporting Material:
Can you do a TFS get without needing a workspace?
Solution 1:
By-pass the TFS voodoo, get Git for TFS, and run the below.
(This would be the equivalent of "svn.exe 'export'" if you know that world.
"C:\MyProgFiles\GitTF\git-tf.cmd" clone http://MyCoolteamfoundationserver:8080/tfs/ $/MySolution/
Solution 2:
Create the workspace and map it and then "get" the code.
Here is a .bat version that you would mimic:
set __MYWORKSPACENAME=CI_TEMP_WORKSPACE
set __BASEDIRECTORYFINAL=c:\ci_build_stuff\
MD %__BASEDIRECTORYFINAL%
CD %__BASEDIRECTORYFINAL%
set __tfExe=C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\TF.exe
"%__tfExe%" workspace /new %__MYWORKSPACENAME% /collection:http://my_super_cool_teamfoundationserver:8080/tfs/my_cool_projects /noprompt
"%__tfExe%" workfold /map $/MyTFSPath %__BASEDIRECTORYFINAL%\SXA
"%__tfExe%" get %__BASEDIRECTORYFINAL%\MyTFSPath\ /recursive /noprompt
set __BASEDIRECTORYFINAL=
set __MYWORKSPACENAME=
set __tfExe=
Further thoughts:
Checkout
http://msbuildextensionpack.codeplex.com/workitem/11709
That might have some built in workspace voodoo in it, that isn't there on the changeset.
Get the source code and look around, it'll tell you what's going on.
I see this one:
http://msbuildextensionpack.codeplex.com/SourceControl/latest#Solutions/Main/TFS/TeamBuild.cs
public class TeamBuild : BaseTask
{
private const string GetLatestTaskAction = "GetLatest";
private const string QueueTaskAction = "Queue";
private const string RelatedChangesetsTaskAction = "RelatedChangesets";
private const string RelatedWorkItemsTaskAction = "RelatedWorkItems";

Command line "get latest" from TFS without mapping workspaces and such

I assume that this:
tf.exe get $/project /recursive
...needs this weird workspace mapping, known TFS server and such.
Is there any way I could do this simplest thing: go connect to this TFS server using this set of credentials, get latest source code for this project and put it here? All from the command line.
Firstly, are you wanting a copy of the controlled files that are no longer under source-control (such as a SVN export) or are you still hoping to work with the files and TFS?
Option 1: No Binding at all
If you simply want a copy of the latest files and no 'binding' to TFS, you're going to have to do a little work yourself. Leaving aside credentials ([/login:username,[password]] parameter to many command line methods).
Use the TF command to get a list of the files: tf dir "$/YourSolution" /Recursive > files.txt
Process files.txt with some clever batch file (or use a scripting language):
Read lines starting with $/ and this is the directory, create the directory in your destination (remove first three characters and the last character, a colon).
Read the next lines (until blank or end of file), each of these represents a file in the directory discovered in step 3. Assuming you have the file in a variable %file% and directory %dir%, then issue the following command (for each file in that directory):
tf view "$/%DIR%/%FILE%" "/output:Your-Target-Path/%DIR%/%FILE%"
or if you're happy with the current directory as the target:
tf view "$/%DIR%/%FILE%" "/output:%DIR%/%FILE%"
Note, you need the %DIR%/%FILE% in the output part or all files will be dumped in to the same directory.
NOTE: this is likely to a be VERY high bandwidth and slow operation!
Option 2: Temporary Mapping
Create a temporary workspace: tf workspace /new /collection:<URL_TO_SERVER> /permission:Private (note, this will prompt, there is a no-prompt option but determining a name for the workspace is left as an exercise)
Make a directory for files, e.g. LOCALDIR
Create a mapping for your folders: tf workfold /map "$/SERVER_DIR" "LOCALDIR"
Go into LOCALDIR
Get the files tf get . /Recursive
At this point you should now have all of the files and if you wanted you also have a binding with TFS so you could commit changes. Alternatively, you can now copy the content elsewhere and break the mapping/workspace. Using the correct command line variants of tf workfold /unmap and tf workspace /delete will unmap your workfolder and delete the workspace.
Export any folder cleanly from TFS? Finally found a brilliant solution I think.
I am not going to completely research this for you now, but intend to replace my incredibly messy build server workspace synch script with this later, when I get the time.
Solution:
Use Microsoft's Git-TF to get the source to disk without having to set up a workspace or anything. I tried the command, and it worked wonderfully. Think it will work for TFS 2010 and 2012. From what I can understand, there will be no bindings or workspaces or anything left behind that will cause problems later. I think all you need to install is GIT and GIT-TF.
http://www.microsoft.com/en-us/download/details.aspx?id=30474
You will actually get the files into a GIT repository, which is not a problem at all. You will get a (hidden?) folder named .git inside the folder you exported, and I guess you can simply delete it to get rid of any trace of GIT.
If someone implements this, which should be easy, please confirm it works as expected.
Quick solution
Building on Ray Hayes option 2 answer, I put together an actual script that should be straight forward to use for those who just want the quick and dirty solution. You should read his aswer for more info.
To use it:
Set the four variables to your working environment
remember that your
tf.exe might not be located in the same directory that I have it in,
especially if you are reading this from the future :)
.
SET COLLECTION_URL="http://localhost:8080/tfs/<collection>"
SET SERVER_DIR="$/<REMOTE_SOLUTION_DIR>"
SET LOCAL_DIR="X:\<YourLocalDir>"
SET TF_DIR="C:\Program Files\Microsoft Visual Studio 10.0\Common7\IDE"
%TF_DIR%\tf workspace /new /collection:%COLLECTION_URL% /permission:Private /noprompt tmp_batchws
%TF_DIR%\tf workfold /map %SERVER_DIR% %LOCAL_DIR%
cd /d %LOCAL_DIR%
%TF_DIR%\tf get . /Recursive
%TF_DIR%\tf workspace /delete tmp_batchws /noprompt
i wrote the powershell for the leading answer
$base = "f:\whereyouwantthefilestogo\"
foreach($l in get-content D:\outputfromTFdir.txt)
{
if($l -match '^\$.*\:$')
{
$repopath = $l.trim(':')
write-host 'base path'
$basepath = "$base$($l.Substring(2,$l.Length -3) -replace '/','\')"
if((Test-Path $basepath) -eq $false)
{
write-host 'making directory'
New-Item -ItemType directory -Path $basepath
}
continue;
}
elseif($l -match '^\$')
{
write-host 'sub folder'
$subfolderpath = "$basepath\$($l.trim('$'))"
if((Test-Path $subfolderpath) -eq $false)
{
write-host 'making directory'
New-Item -ItemType directory -Path $subfolderpath
}
continue;
}
elseif($l -match '.*\..*')
{
write-host 'get file'
$filename = "$basepath\$l"
write-host $filename
$repofile = "$repopath/$l"
tf view "$repofile" "/output:$filename" /collection:http://tfsserver
}
else{write-host 'blank line'}
}
There is no "easy" option when it comes to TFS command lines - they almost always involve an awful lot of typing (such as not being able to simply have a default set up so you don't have to specify a collection URL on every command)
The usual way to make TFS command lines "simple" is to write batch files to hide away all the details that have to be specified every time (server URLs and recurse flags etc)
TF.exe does allow you to do almost anything, though, so it is a pretty straight-forward sequence of tf calls to create a temporary mapping, do a Get and and delete the mapping again.
http://johannblais.blogspot.com/2014/07/tfs-equivalent-of-svn-export.html
http://tfs-server:port/tfs/Collection/TeamProject/Team/_api/_versioncontrol/itemContentZipped?repositoryId=&path=url-encoded-source-control-path
tfs-server is the TFS server hostname
port is the TFS port (usually
8080)
Collection is the name of your team project collection
TeamProject is the name of your team project
Team is the name of the team
url-encoded-source-control-path is the URL encoded source
control path (for example, $/Project1/Main/Sources/Folder/SubFolder becomes %24%2FProject1%2FMain%2FSources%2FFolder%2FSubFolder

How to get certain files from TFS using PowerShell?

After we branch for release, there are certain configuration files that need to be updated. Currently, I'm getting latest version of all the source code on the specific (new) branch. This is time consuming and takes up a lot of disk space.
Is there a way to search/loop through the particular branch and only getting files that match a certain criteria?
E.g:
Loop through files under branch on the TFS server
If file name matches "foo.proj" or file name matches "foo.ini"
Get latest version of the file
The "get" part is easy using the command line interface to TF (tf get $/project/foo.proj). I'm not to sure how to loop through the server objects without getting latest version first.
Take a look at the TFS PowerShell Snapin from the TFS PowerToys (you need a custom install to select).
After loading the snapin in a 32bit PSH instance (Add-PSSnapin Microsoft.TeamFoundation.PowerShell) you can use:
Get-TFSItemProperty on a folder to get a list of items under source control.
Update-TfsWorkspace to get or update all or specific files/folders into your workspace.
Update: You can install the PSH TFS snapin for 64bit yourself having installed it for 32bit via the PowerToys (see comments) in which case this is not limited to a 32bit PSH instance.
I used this in the end:
Custom install the TFS Powershell snap in using the tftp.exe that you download.
Add the snap in:
if ( (Get-PSSnapin -Name Microsoft.TeamFoundation.PowerShell -ErrorAction SilentlyContinue) -eq $null )
{
Add-PSSnapin Microsoft.TeamFoundation.PowerShell
}
Powershell script:
param( [string] $ServerBranchLocation )
$tfs=Get-TfsServer -name http://mytfsserver:8080/tfs
$TfExePath = "${env:ProgramFiles(x86)}\Microsoft Visual Studio 10.0\Common7\IDE\TF.exe"
$matchFoo = "foofile.foo"
foreach ($item in Get-TfsChildItem $ServerBranchLocation -r -server $tfs)
{
if ($item -match $matchFoo)
{ & "$TFExePath" get $item.ServerItem /force /noprompt }
}
I couldn't find a way to get the latest version using the snap in, so I had to use the ol' trusty tf.exe.

Resources