TFS workfold /unmap "Multiple workspaces exist with the name XYZ" - tfs

I am trying to understand how to solve the following situation.
I have a TFS 2012 server with three collections, say;
- http://tfs2012:8080/tfs/DefaultCollection/
- http://tfs2012:8080/tfs/CollectionOne/
- http://tfs2012:8080/tfs/CollectionTwo/
In CollectionOne and CollectionTwo I have a workspace of the same name, lets call it "TestWorkspace".
When I run a map command for that workspace on CollectionOne it works perfectly (can get, delete, update, etc). The issue comes when I try to unmap the workspace as I am done using it (think build machine), the following call fails.
tf.exe workfold /unmap /workspace:TestWorkspace E:\Temp
It fails with;
Multiple workspaces exist with the name TestWorkspace.
Please specify the Team Foundation Server or qualify the name with the owner.
Therefore I try the following;
tf.exe workfold /unmap /workspace:TestWorkspace E:\Temp /collection:http://tfs2012:8080/tfs/CollectionOne/
Which fails with the following;
The option collection is not allowed.
Also specifying the owner of the workpsace doesn't help as they are owned by the same user.
How do I unmap a workspace which exists in two or more collections?

This has been reported as a bug here: https://connect.microsoft.com/VisualStudio/feedback/details/574162/tf-workfold-unmap-not-accepting-collection-option
See here for a workaround: http://wiert.me/2012/08/29/vs2010-workfold-command-allows-moving-a-local-working-folder-for-a-workspace-but-not-unmapping-it-when-you-have-multiple-workspaces-with-the-same-name/

This is indeed an annoying defect. Here's a simple workaround I've used successfully.
# Rename existing workspace to something unique
tf workspace /collection:http://yourserver:8080/tfs/DefaultCollection /newname:TEMPORARY /noprompt DEVBOX-SGY
# Unmap based on new (unique) name
tf workfold /unmap /workspace:TEMPORARY C:\Code\Tools
# Rename workspace back to original name to avoid side-effects
tf workspace /newname:DEVBOXSGY /noprompt TEMPORARY
Personally I was not able to use the workaround mentioned by sparkplug, because I needed something automation friendly.

Related

Include branch name in post build event on Team Build

I would like to perform the following steps in the TFS build process:
do post build event that will copy some files from my compiled projects to another predefined directory, I'd like that directory path to include the branch name.
I'd like to be able to refer to the branch name inside my xaml workflow template as well.
The first one is rather simple. When you're using the new TFS 2013 build server and process template, you can simply add a post-build powershell script in the Build Definition Configuration, check in the script and run it during the build.
The second one is dependent on whether you're using TFVC or Git, in the first case, use the VersionControlServer class to query the BranchObjects, then check which one is the root for your working folder. Be aware though, that in TFVC multiple branches can be referenced in one workspace, so there may be multiple answers to this query, depending on which file you use the find the branchroot. A custom CodeActivity would do the trick, similar to this check in a custom checkin policy.
The code will be similar to:
IBuildDetail buildDetail = context.GetExtension<IBuildDetail>();
var workspace = buildDetail.BuildDefinition.Workspace;
var versionControlServer = buildDetail.BuildServer.TeamProjectCollection.GetService<VersionControlServer>();
var branches = versionControlServer.QueryRootBranchObjects(RecursionType.Full);
var referencedBranches = listOfFilePaths.GroupBy(
file =>
branches.SingleOrDefault(
branch => file.ServerItem.StartsWith(branch.Properties.RootItem.Item)
)
).Where(group => group.Key != null);
To get a list of all items in yo workspace, you can use Workspace.GetItems.
In case you're using Git, you have a few options as well. The simplest is to invoke the command line:
git symbolic-ref --short HEAD
or dive into LibGit2Sharp and use it to find the branch name based on the current working folder from a custom activity.
If you want to include this in an MsBuild task, this may well be possible as well. It goes a bit far for this answer to completely outline the steps required, but it's not that hard once you know what to do.
Create a custom MsBuild task that invokes the same snippet of code above, though instead of getting access to the workspace through BuildDetail.BuildDefinition.Workspace, but through the WorkStation class:
Workstation workstation = Workstation.Current;
WorkspaceInfo info = workstation.GetLocalWorkspaceInfo(path);
TfsTeamProjectCollection collection = new TfsTeamProjectCollection(info.ServerUri);
Workspace workspace = info.GetWorkspace(collection);
VersionControlServer versionControlServer = collection.GetService<VersionControlServer>();
Once the task has been created, you can create a custom .targets file that hooks into the MsBuild process by overriding certain variables or copying data when the build is finished. You can hook into multiple Targets and define whether you need to do something before or after them.
You can either <import> these into each of your projects, or you can place it in the ImportAfter or ImportBefore folder of your MsBuild version to make it load globally. You can find the folder here:
C:\Program Files (x86)\MSBuild\{MsBuild Version}\Microsoft.Common.Targets\ImportAfter

TF checkin ignore "no files to check in" error

Background: I am writing a batch files to create and check in some contract files (language agnostic representations of API files) whenever we check into an API project. I am checking in the files with the following command:
tf checkin /flags myContractFiles
Frequently the contract files do not change so I often get this error:
There are no remaining changes to check in.
As a result the build fails.
Question: Is there a way to avoid this particular error?
What I have tried: I am aware of the /force flag for tf checkin (as suggested here), but would rather not use it because I would prefer to only check in when there actually is a change (I do not want to pollute the branch history with changesets with no changes). I have also seen the tf diff and tf folderdiff commands, but it looks like they output their result to the command line, and I am unable to do something like this:
if tf folderdiff ... (
tf checkin ...
)
You will either have to parse the folderdiff result to do what you want or create a custom activity to detect the changes through the API.

TFS - is it possible to delete merge flag from files and send commit just like a normal changeset?

Let's say I have two branches: A and child branch B. I wanna merge one changeset from branch A to B, but with one detail: I don't want flag [merge] for files in this changeset, it must look just like I edit files manualy and don't have a link on changeset from branch A. Is it possible?
Yes, the general idea is to generate a diff on the source branch with the following command
tf.exe diff [...] /recursive /format:unified /version:[...] >> diff.patch
Replace the [...] with the actual values (branch folder and versions). The documentation is on MSDN
Then use the patch utility (from sourceforge.net) to apply it the other branch:
patch.exe -p0 < diff.patch
Then check in.

TFS Label Inconsistency

I've been working with Team Foundation Server 2012 to get a Continuous Integration build for a data warehouse project working. In doing so I noticed that the labeling and building from a label wasn't yielding the results that I was expecting. In researching the problem I was able to replicate the issue using only the command line arguments provided by Team Foundation Servers Command Line tools. That helped me to eliminate anything in the build definition that may have been affecting the build.
So this is my problem:
I have a build that is building 2 different projects in a single build. It basically has two *.SLN files associated with it. I applied a label to 2 assets, one in each project. I can then execute the command to view which assets have the label. When doing this I get the expected result. However, when I execute the command to get the assets associated with this label it only pulls 1 of the two files. I've verified that I can pull both files, by removing one of the projects. This is the setup that I have with the build definition, work space and label
TFS Paths: $/Dev/Project1
$/Dev/Project2
Workspace Mapping
Project1: C:/SourceControl/Project1
Project2: C:/SourceControl/Project2
DeploymentFolder
Project1: //DevServer/SSIS/Project1
Project2: //DevServer/SSIS/Project2
Executed Commands:
Apply Label: tf label TestLabel $/DEV/Project1/PackageA.dtsx
tf label TestLabel $/DEV/Project2/PackageA.dtsx
Review Label: tf labels /format:Detailed LTestLabel
Get From Label:
tf get /r /version:LTestLabel
After executing the tf get command I get the following results
Deployment folder: //DevServer/SSIS/Project1 contains the file PackageA.dtsx
Deployment folder: //DevServer/SSIS/Project2 contains 0 Files.
It appears that there is a filter or restriction on pulling assets in different projects with the same label. I would expect that if I apply a label to any asset in TFS, then pull the labels, it should allow me to retrieve all assets with that applied label. Has anyone heard or experienced this? Any help provided would be appreciated.
You don't specify what (local) folder you're in when you execute the get: since you don't specify a folder to get, it implies the current one, equivalent to:
tf get /recursive /version:Llabelname .
If you want to get both, specify a directory containing both, for example:
tf get /recursive /version:Llabelname $/
This, of course, assumes that both the files in your label are mapped.

tf.exe folderdiff diffing files in specific folders

I want to be able to diff all my app.config files that resides in folders called MessagingService. I have read the documentation on the tf.exe about 50 times now, and I can't understand that the syntax should be different than:
tf.exe treediff $/myproject/main $/myproject/prod /filter:"app.config;MessagingService\" /r
but this leaves no results. As far as I can understand the folder inclusion mask does not behave as expected, because the following line works fine:
tf.exe treediff $/myproject/main $/myproject/prod /filter:"app.config;!MessagingService\" /r
but of course it displays only the app.configs I'm not interested in :)
Any enlightening comments are highly appreciated.
try this one ...
tf.exe treediff $/myproject/main $/myproject/prod /filter:"app.config;*MessagingService*\" /r
I believe stars are needed after and before MessagingService word because "app.config" IS the entire filename but MessagingService word IS NOT the entire path value, it is just a part of the actual file path.

Resources