I'm writing a script that will run a build only if there is a change in source code. I need to know whether there is a change since the build last ran. This used to work because the folder would not be deleted, so it was easy to determine whether there was a change, but now everything is deleted everytime the build is run. I thought about using the TFS TF history command to query the last changeset or the last two changesets, but have had issues parsing just the changeset number from the output. I also considered using the changeset command. Is there any command-line parameter that I can use to answer the question, has there been a change since either a date, or a changeset number?
To the latest changeset number without local workspace, please use this command:
tf history /collection:"http://server:8080/tfs/Collection" "$/Project" /recursive /stopafter:1 /noprompt /login:domain\user,password
excerpt from my batch file to build.
set _aPath="f:\TFS\a"
set _TFPath="c:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE"
...
pushd %_aPath%
%_TFPath%\TF.exe history . /r /noprompt /stopafter:1 /Version:W > temp
FOR /f "tokens=1" %%a in ('findstr /R "^[0-9][0-9]*" temp') do set _BuildVersion=10.3.0.%%a
del temp
popd
uses a temp file, but works well.
As Andrew mentioned, TFS has continuous integration functionality built-in. However, yes, it's easy to query the changesets since a certain point, be it a date or a changeset. You want to look at the history between that changeset and latest:
tf history <folder> /version:C<changeset>~T /noprompt /recursive
If the only line output is the changeset you queried for, then obviously there have been no changes since that checkin. Otherwise, you will see the additional changesets, one per line.
There is an adaptor that can integrate BuildForge and Microsoft Team Foundation Server. Here is the url if you are interested...http://www-304.ibm.com/partnerworld/gsd/solutiondetails.do?&solution=46360&lc=en
The Automatra TFS Adaptor for Rational Build Forge provides Continuous Integration (CI) and reporting capabilities.
The TFS Adaptor further enables CI capabilities at both the TFS Source (Change Set) and WorkItem levels. Out of the box reporting delivers clear Bill of Materials (BOM) reports that can be delivered to downstream consumer of your builds.
Finally, as you must be aware, the strength of Build Forge is its capability to bridge build with deployment (and beyond). Obviously, with these Continuous Integration capabilities you can then move forward with the continuous delivery capability I believe you wish to achieve.
My PowerShell script that is called GetVcsRevision.ps1 and located in subfolder of VCS Root:
param (
[string]$PathToTF='C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE\TF.exe'
,[Parameter(Mandatory=$true)][string]$Login
,[Parameter(Mandatory=$true)][string]$Password
)
$result = &$PathToTF #("history","/stopafter:1","/recursive","..\*","/login:""$Login"",""$Password""") 2>&1 3>&1
if ($result.GetType().Name -eq "Object[]")
{
<# $result format is:
Changeset User Date Comment
--------- ----------------- ---------- ----------------------------------------
26038 user 24.06.2014 Sample commit comment
$result[2] is:
26038 user 24.06.2014 Sample commit comment
$result[2].Split(" ")[0] is:
26038
#>
$result[2].Split(" ")[0]
}
else
{
"0"
}
It is sending last changeset number to out pipe. If something goes wrong, then this number is 0.
You can make a function from this script and call it in you build script.
My one-line command:
for /f "usebackq tokens=*" %%a in (`tf history . /recursive /noprompt /stopafter:1 /version:T ^| powershell -Command "$input | ? { $_ -imatch '^(\d+)\s+' } | %% { $matches[0].Trim() } | Select-Object -First 1"`) do set TIP_CHANGESET=%%a
after execution TIP_CHANGESET env. variable contains tip changeset
Related
I used tf.exe to get a particular version of a source tree like:
$ tf get $/[PATH]/[SUBPATH] /r /version:C1234
Now I want to check the last checkin, but only up to the version as checked out. I tried:
$ tf history . /r /noprompt /stopafter:1 /version:1~W
However, this prints the tip of the source tree as in source control.
Changeset User
--------- ----------------
1555 domain\[USER]
Is there a command option to only show the history of the tree as it is checked out (excluding any changes that may exist on the server, but are not checked out locally), i.e. for the example above, the output should be
Changeset User
--------- ----------------
1234 domain\[USER]
Thanks
Turns out that the command above works after I re-get the workspace but also undid all local changes. In my previous attempt I had kept two local edits (answered "Keep Local Version" to the conflict resolution prompt). Looks like this caused the history command to return the latest server version.
Is it possible, through the command line (e.g. tf.exe) to check if there are new changes within a specific directory?
My hope is to have a script that will automatically merge certain folders if they have changes.
Have you checked Tf Command-Line Utility Commands on MSDN? Probably "Folderdiff Command" is what you want. Example
C:>tf folderdiff $/serverFolder F:\localFolder /recursive /noprompt
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
Can we switch between branches in TFS
what i want is i downloaded a working copy and now I want to switch to different branch without downloading everything, because for large projects it will take lot of time since developers spend lot of time downloading
Is it possible, if not any workaround ??
You can switch branches from the command-line client (only downloading the differences) by changing your workspace mappings and using the /remap flag to the get command:
tf workfold /map $/Branch1 C:\Work
tf get C:\Work /version:T /recursive
tf workfold /unmap $/Branch1
tf workfold /map $/Branch2 C:\Work
tf get C:\Work /remap /version:T /recursive
In TFS branches are "physically" present in the Source Control, they're like "special folders". So you can totally choose what branch you get locally by targeting the right folder for your get.
If you have for instance:
Projects [folder]
ProjectA [folder]
Dev [Branch]
V1 [Branch]
ProjectB [folder]
Dev [Branch]
V1 [Branch]
and you want to get at the "Projects" level with only the content of "Dev", you can create mapping in your Workspace definition to cloack the V1 branches of ProjectA and B.
Just for supplementing the knowledge base - my colleague Isak Savo created useful batch for such purpose. You need to do some editing inside the script (at the top) to point to the correct source code location and appropriate branches. The core is basically the same as in Edward Thomson answer, but with some interactive logic added. I made some minor changes (directory context switching for tf commands, quotes for arguments - needed if there are spaces in directories) and shared it below:
#echo off
rem Command to switch the current source tree to a new branch.
rem It's best to not have any pending changes.
set DEVBRANCH=$/dir/src1
set RELEASEBRANCH=$/dir/src2
set SOURCEDIR=c:\sources directory\src
if exist "%SOURCEDIR%" goto ASK
echo Source code directory (%SOURCEDIR%) not found, please edit this script to point to the correct directory
pause
exit
:ASK:
set TARGET=
echo Available branches are:
echo Dev: %DEVBRANCH%
echo Release: %RELEASEBRANCH%
set /P ANSWER=Specify target branch? [Dev, Release]
cls
if /I "%ANSWER%"=="Release" set TARGET=%RELEASEBRANCH%
if /I "%ANSWER%"=="Dev" set TARGET=%DEVBRANCH%
if /I "%ANSWER%"=="quit" goto END
if [%TARGET%] NEQ [] goto SWITCH
echo "%ANSWER%" unknown, please answer Dev or Release. Specify quit to cancel
GOTO ASK
:SWITCH
rem Navigate to the mapping source folder to avoid "Unable to determine the workspace..." error while invoking tf commands.
echo Changing directory context
pushd %SOURCEDIR%
echo Switching to branch %TARGET%
echo - Creating new mapping...
tf workfold /map "%TARGET%" "%SOURCEDIR%"
echo - Get latest version...
tf get "%SOURCEDIR%" /remap /version:T /recursive
popd
goto END
:END
Save it e.g. to switch_branch.cmd and execute from any directory from your machine.
Team Explorer Everywhere has a "Switch to branch" command, which is probably what you're looking for.
Visual Studio, on the other hand, doesn't have the same command...
You can switch between multiple branches, as long as you are using same workspace and the working directory contains the branches.
How do I figure out what changeset I currently have in my local workspace?
Sure, I can pick one file and view its history. However, if that file was not recently updated, its changeset is probably older than the more recently updated files in the same solution.
One possible mistake that we may make is that we view the history on the solution file, however the solution file rarely changes unless you're adding a new project / making solution-level changes.
In the end to figure out the changeset I need to remember what were the latest files changed and view their history.
Is there a better way to do this?
Your answer is on a MSDN blog by Buck Hodges: How to determine the latest changeset in your workspace
from the root (top) of your workspace, in cmd perform:
tf history . /r /noprompt /stopafter:1 /version:W
Run a Visual Studio CMD (in my case, for VS2015 is called: "Developer Command Promp for VS2015") and then get into your project folder and execute the following command:
tf history . /r /noprompt /stopafter:1 /version:W
The common answer to use tf.exe history . /r directly does work, but it can be horribly slow. In our case it takes 10-15 seconds.
I now use a two stage check, first checking the revision of some arbitrary files (I'm using the files in the root folder).
With powershell:
$tfexepath = "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer\tf.exe"
$localpath = "C:\some\tfs\directory"
$result = & $tfexepath history $localpath /noprompt /stopafter:1 /version:W
"$result" -match "\d+" | out-null
$id = $matches[0]
Then search from the root using the /r flag, but limit the search to start from the revision found above:
$result2 = & $tfexepath history $localpath /r /noprompt /stopafter:1 /version:$id~W
"$result2" -match "\d+" | out-null
$id2 = $matches[0]
#result:
Write-Host $id2
For our code base, this brings down the total time from 10-15 to 1.4-1.5 seconds.
As far as I understand there are no drawbacks or limitations, but I suppose it could be slower in a tiny repository. - I'd be glad to know.
If you want to use PowerShell (see also; equivalent to answer of #kroonwijk):
enable tfs snapin (once, if not already)
add-pssnapin Microsoft.TeamFoundation.PowerShell
use tfs cmdlet to get current changeset id
Get-TfsItemHistory <PATH_TO_PROJECT> -Recurse -Stopafter 1 -Version W
If you really have no idea what version you have you should use one of the other suggested methods. If you are just not sure if you have a specific version or you are uncertain between a few change sets and you prefer working from the VS TFS GUI you can fallow this steps:
Pick the change set you want to be certain about and do a compare:
If you have no difference:
or, if the only files that are different are files that you have pending changes in:
That means you are up to date with the version in question.
** If you are not sure if file that has a pending change is actually also not up to date you can check that file version with properties: