Reputation: 32169
When creating TFS build definitions via the API, I need to first delete, if the definition pre-exists:
if (BuildServer.QueryBuildDefinitions(teamProject).Any(d => d.Name == buildDefinitionName))
{
buildDefinition = BuildServer.GetBuildDefinition(teamProject, buildDefinitionName);
var builds = BuildServer.QueryBuilds(buildDefinition);
if (builds != null && builds.Any())
{
Console.WriteLine("delete {0} builds for build definition: {1}", builds.Count(), buildDefinition.Name);
BuildServer.DeleteBuilds(builds);
}
if (buildDefinition.Workspace.Mappings.Any())
{
var mappings = buildDefinition.Workspace.Mappings.Select(m => m.ServerItem).ToArray();
foreach (var mapping in mappings)
{
Console.WriteLine("remove workspace mapping: {0}", mapping);
buildDefinition.Workspace.RemoveMapping(mapping);
}
}
Console.WriteLine("delete build definition: {0}", buildDefinition.Name);
BuildServer.DeleteBuildDefinitions(new[] { buildDefinition });
}
This works as does the subsequent:
buildDefinition = BuildServer.CreateBuildDefinition(teamProject);
buildDefinition.Name = buildDefinitionName;
However, when the first build gets run, it throws an error about conflicting workspaces:
Exception Message: Unable to create the workspace 'some-new-workspace' due to a mapping conflict. You may need to manually delete an old workspace. You can get a list of workspaces on a computer with the command 'tf workspaces /computer:%COMPUTERNAME%'.
Details: The path C:\some-path is already mapped in workspace some-old-workspace. (type MappingConflictException)
As you can see in the first snippet, my attempt to delete workspaces with .Workspace.RemoveMapping()
, has no effect. The workspaces still exist on the build controller. I can delete them manually but they really should get deleted when I delete the build definition. Is there some other DeleteWorkspace()
mechanism in the API?
A more complete code gist is here: https://gist.github.com/grenade/cce374cb4e27e366bc5b
Upvotes: 0
Views: 721
Reputation: 32169
It turns out that the reason it's complicated is that the owner of the various workspaces created by the build could be some other user (that the build agent runs under).
I found a way to do it by relying on the previous build definition id which is used in the workspace naming convention [build definition id]_[build agent id]_[workspace host]
:
var workspaceNamePrefix = string.Concat(buildDefinition.Id, '_');
var workSpaces = VersionControlServer.QueryWorkspaces(null, null, null).Where(w => w.Name.StartsWith(workspaceNamePrefix)).ToArray();
for (var i = workSpaces.Count() - 1; i > -1; i--)
{
try
{
workSpaces[i].Delete();
Console.WriteLine("delete workspace: {0}", workSpaces[i].Name);
}
catch (ResourceAccessException rae)
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine(rae.Message);
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("workspace needs to be deleted by an administrator using the following command:");
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("tf workspace /delete {0};{1}", workSpaces[i].Name, workSpaces[i].OwnerName);
Console.ResetColor();
}
}
I have updated the gist: https://gist.github.com/grenade/cce374cb4e27e366bc5b
Upvotes: 1