I am trying to get the local workspace to sync up with the remote workspace. The remote workspace is WindowsMain/MainProject/Subproject and the local is C:/MainProject/Subproject the problem is when I run the code shown below it says that the local workspace isn't mapped. What am I doing wrong that makes it so that the code isn't found? (localpath is C:/MainProject/Subproject
TfsTeamProjectCollection tfs = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri("http://remoteserver:8080/tfs_proj/WindowsMain"), new UICredentialsProvider());
tfs.EnsureAuthenticated();
VersionControlServer vsStore = tfs.GetService<VersionControlServer>();
Workspace workspace = vsStore.GetWorkspace(localpath);
I'm not sure what is that you want exactly,
...but this is the code I used (and I remember having trouble finding the right solution at the time):
teamProjectCollection = new TfsTeamProjectCollection(new Uri(collectionUri), new TfsClientCredentials());
teamProjectCollection.Authenticate();
versionControl = teamProjectCollection.GetService<VersionControlServer>();
(note: the credentials like this are automatically picked from what
you use in VS)
then I get all the workspaces (in your case it may be just one) - that helps to get the right matching paths for server and client (the Workstation class does the same, if that doesn't work for some reason, this does)
versionControl.QueryWorkspaces(null, null, computerName)
.SelectMany(x => x.Folders); // returns IEnumerable<WorkingFolder>
pick the workspace you need and you have both local and server path
LocalSourcePath = folder.LocalItem;
ServerPath = folder.ServerItem;
...and then I use the ServerPath and the versionControl to actually download the files (and e.g. you can check them against the LocalSourcePath)...
foreach (Item item in
versionControl.GetItems(serverPath, VersionSpec.Latest, RecursionType.Full, DeletedState.NonDeleted, ItemType.Any, true).Items)
{
string target = Path.Combine(downloadPath, item.ServerItem.Substring(2));
if (item.ItemType == ItemType.Folder && !Directory.Exists(target))
{
Directory.CreateDirectory(target);
}
else if (item.ItemType == ItemType.File)
{
item.DownloadFile(target);
}
}
...this is probably slightly different for your case but you should be able to work out the specific details from this, hope it helps.
According to you code, you need to pass through a VersionControlServer object, and to obtain such an object you need to know the address of the Tfs server the workspace is mapped to.
If you can determine the physical path of the solution or project file, then you can query that file in TFS and you should see which workspace has been mapped to that local file location. Note: The mapped path for a workspace had to be unique.
Moreover, there is a more powerful way though, using the Workstation class. Ricci Gian Maria has written a quite extensive blog post about this topic.
Use the Workstation class to get the WorkspaceInfo for the path you're looking for, this will search the workpaces for all TFS servers registered on that workstation to see if there's a match:
Workstation workstation = Workstation.Current;
WorkspaceInfo info = workstation.GetLocalWorkspaceInfo(path);
More details please refer his blog: How to get TFS server address from a local folder mapped to a workspace
Related
I want to retrieve a list of all branches of a TFS workspace which are mapped locally. I already got a solution where I retrieve all branches of a VersionControlServer-Object, but that`s not what I want to get here. It should be a list specific for my workspace.
var branchObjects = m_VersionControlServer.QueryRootBranchObjects(RecursionType.Full);
List<string> branches = new List<string>();
foreach (var branch in branchObjects)
{
var branchName = branch.Properties.RootItem.Item;
branches.Add(branchName);
}
Do u got any ideas how to check which of the branches where mapped at the local workspace? An instance of the specific workspace-class is available.
You can achieve this with the TFS tf command line tool
tf workspaces /owner:* /computer:* /collection:https://tfs.yourdomain.com/DefaultCollection /format:xml
If you don't have tf.exe, refer to this page How to get tf.exe (TFS command line client)?
Assuming you know the local path of your workspace you can use:
var workspace = versionControlServer.TryGetWorkspace(...path...)
Or you can use the Workstation class to query local workspaces on your machine.
Then from the workspace you can get the workspaces from the QueryWorkspaceInfo method and from there the mappings WorkspaceInfo.Mappings property. And from there you can check whether your branchroots (which you've already got figured out) are mapped in any of the workspaces on the server. If you want to be able to look up server path, you'll need to call the WorkspacnInfo.GetWorkspace method and from there use the Workspace.Folders property.
I have a C# program which checks if a specific directory exists.
It is simply doing:
Directory.Exists(path).
I tried other ways as well. Using DirectoryInfo and using AlphaFS
On my local machine, the path exists. When I run the same program on a server with the same credentials it doesn't exist.
I wonder if it is a group policy issue. But I am able to go up one level and see it.
\server\volume\share\sub directory - Doesn't exist remotely but on my desktop it does
\server\volume\share - Does exist both on my desktop and remote server
Update
I forgot to mention, that since I had access to my desktop, I got the ACL information.
None of the groups were able to translate.
I really just want to get this application to behave the same way is on the server and find out why it is behaving differently.
Update 2
These are physical servers.
My desktop is Liquid VDI
Below is the code:
var path = txtPath.Text;
using (var user = new Impersonation(fuserdomain, fc_user, fc_pass))
{
var alphaExists = Alphaleonis.Win32.Filesystem.Directory.Exists(path);
var alphaDIExists = new Alphaleonis.Win32.Filesystem.DirectoryInfo(path).Exists;
var SystemExists = System.IO.Directory.Exists(path);
var SystemDIExists = new System.IO.DirectoryInfo(path).Exists;
var AlphaHasFiles = false;
var AlphaDIHasFiles = false;
var SystemHasFiles = false;
var SystemDIHasFiles = false;
try
{
Directory.GetFiles(path);
AlphaHasFiles = true;
}
catch { }
try
{
new DirectoryInfo(path).GetFiles();
AlphaDIHasFiles = true;
}
catch { }
try
{
System.IO.Directory.GetFiles(path);
SystemHasFiles = true;
}
catch { }
try
{
new System.IO.DirectoryInfo(path).GetFiles();
SystemDIHasFiles = true;
}
catch { }
MessageBox.Show(string.Format("alphaExists: {0}\nalphaDIExists: {1}\nSystemExists: {2}\nSystemDIExists: {3}\nAlphaGetFiles: {4}\nAlphaDIGetFiles: {5}\nSystemGetFiles: {6}\nSystemDIGetFiles: {7}\n", alphaExists, alphaDIExists, SystemExists, SystemDIExists, AlphaHasFiles, AlphaDIHasFiles, SystemHasFiles, SystemDIHasFiles));
}
Update 3
Although I have workaround this issue; I am still not sure why I would have a difference between my desktop and server. Is there any tool that can help me see where the issue may be?
I've seen the same thing with File.Exists. I never found an answer and finally threw in the towel, I simply try to use it and catch the exception.
Robust code has to catch it anyway, all the test does is avoid trying if the file or directory is not there. (And the PITA that Visual Studio no longer as any way to ignore an exception on a certain line. No problem runtime, annoying in development.)
This is a complete shot in the dark, since we don't have any specific details to go on. e.g. Is the server you're talking about physically yours, or is it a cloud-based server service?
I'd guess that your machine is an older operating system than the server, and the folder that you're trying to access is one of those special folders that has become more locked down with more recent operating systems (particularly on server operating systems) like the "Program Files" folder. So even though the folder exists on both, the method works on your machine but not on the server, due to permissions.
Hope this helps.
As far as I can tell, the Impersonation class in your code is not part of the dot net framework. Googling finds a couple of implementations. Where does it come from and How confident are you that it actually works in your scenario?
For example, if you remove the Impersonation code, and actually run it as that user, does that make it work?
One other clarification... When you say
\server\volume\share
Do you mean this is a network location (e.g. a UNC location), so is the same network path you are trying to access from both machines? If so, this would open up new possibilities for problems like firewalls, etc... Is that location on either of the two machines that we know about from the question, or a different location?
I'm writing a TFS plugin to automate merging of changesets related to a work item whenever said work item is changed from state "Resolved" to state "Closed". The following code is what I have so far:
C#
private void Action_ResolvedToClosed()
{
//Linq query for getting changesets associated with the current work item
var changeSets = WorkItem.Links
.OfType<ExternalLink>()
.Select(link =>
VersionControlServer.ArtifactProvider.GetChangeset(new Uri(link.LinkedArtifactUri))).ToList();
if (!changeSets.Any())
{
LOG_NOCHANGESETS(WorkItem.Id);
return;
}
Workspace workspace = VersionControlServer.GetWorkspace(<My Workspace>);
var source = URI_LOCAL; // $/<Project Name>/<Working Branch>
var destination = URI_DEV; // $/<Project Name>/<Development Branch>
// Merge applicable changesets
foreach (var versionSpec in changeSets.Select(changeset => new ChangesetVersionSpec(changeset.ChangesetId)))
{
workspace.Merge(source, destination, versionSpec, versionSpec);
workspace.CheckIn(workspace.GetPendingChanges(), "**Automated Merge**");
LOG_SUCCESS(versionSpec.ChangesetId, WorkItem.Id);
}
}
Is there a way to dynamically generate the workspace variable? Odds are I won't be the one actually making changes - the goal is to automate this process for our devs.
UPDATE: I'm pretty sure what I'm looking for in this second part is GetStatus, so it can be ignored. The paragraph above is my real question.
Secondary: I feel like automating merges can't be this simple. What happens if merge conflicts arise? Does Workspace.Merge fail gracefully? Are there any other glaring issues that someone with a bit more experience with the TFS API can point out?
First, it sounds like you want to query the user's workspace cache to get the appropriate Workspace and "realize" it. If
WorkspaceInfo workspaceInfo = Workstation.Current.GetLocalWorkspaceInfo(path);
Workspace workspace = workspaceInfo.GetWorkspace(new TfsTeamProjectCollection(workspaceInfo.ServerUri);
However, as you point out, you may prefer to create a temporary workspace. This will ensure that you do not conflict with any changes the user is trying to make in their own workspace. For example:
TfsTeamProjectCollection tpc = new TfsTeamProjectCollection(new Uri("http://server:8080/tfs/DefaultCollection"));
VersionControlServer vcs = tpc.GetService<VersionControlServer>();
Workspace workspace = vcs.CreateWorkspace("MERGE-TEMP");
workspace.Map("$/Merge-Source", #"C:\Temp\Merge\Source");
workspace.Map("$/Merge-Target", #"C:\Temp\Merge\Target");
Second, if you run into merge conflicts, they will be set in the workspace. You can query the NumConflicts method of the returned GetStatus. (Though you will not be able to Checkin untli you have resolved the conflicts.
I am trying to get a file by name from TFS. I am getting all the files from a location recursively and then looping through these to find a specific file. It appears that the VersionControl.Client.Item object does not expose the filename (or foldername).
tfs.EnsureAuthenticated();
VersionControlServer vcs = versionControlServer)tfs.GetService(typeof(VersionControlServer));
var allStaticFiles = vcs.GetItems(path + "*", RecursionType.Full).Items;
foreach (var staticFile in allStaticFiles)
{
if(staticFile == ?? // need the filename)
{
}
(Assuming TFS2008.)
The type of vcs.GetItems(...).Items is Item[].
So therefore staticFile is an Item instance.
The properties of Item are all server side because details of the path will depend on the client's workspace mapping (there can be multiple workspaces including this item on the same computer for the same user).
You can use Item.ServerItem to get the filename (take the last path element)
To the path, get a Workspace instance representing your current workspace and use one of its methods to map the ServerItem to a local path (there are a few with subtly different behaviour, without more context it is not clear which is the right one).
I have a folder under TFS source control system, let's say under "$/My Project/Branches/Dev" path.
It was just recently moved from another location, which was "$/My Project/Dev".
Now when I request its history from the Source Control Explorer in VS I get the full history, where the described move operation was just one of the changesets.
But when I try to get the history using TFS SDK I only get the recent history started with the move of the folder. How can I get the full history?
I'm using the following code:
TeamFoundationServer tfs = TeamFoundationServerFactory.GetServer(tfsServerURL);
VersionControlServer vcs = (VersionControlServer)tfs.GetService(typeof(VersionControlServer));
// Null means All
VersionSpec versionFrom = null;
System.Collections.IEnumerable enumerable = vcs.QueryHistory(_tfsPath,
VersionSpec.Latest,
0,
RecursionType.Full,
"",
versionFrom,
VersionSpec.Latest,
Int32.MaxValue,
true,
true);
You are passing slotMode = true. Change the final parameter to false.
"Slot mode" means "query by path, not by history." It's useful if you only remember the old name of an item but not where you moved it to, or if >1 item has occupied a given path.
For future reference, if you want to see what parameters VS (or tf.exe) is passing to the server so you can mimic them, turn on tracing.