Is there any way to copy a build definition? I work in a mainline source control methodology which utilizes many different branches that live for very short periods (ie. a few days to a week). I'd really like to copy a build template and just change the solution to build. Is there any way to do this?
You can download the new TFS 2010 power tools. It has the option to clone a build definition.
See http://msmvps.com/blogs/molausson/archive/2010/10/21/clone-a-build-definition.aspx for an example
Note: Be aware that the Clone only works when you did NOT pop out the Build window.
You can write an add-in to do it. Here's the code to copy an existing build definition:
static IBuildDefinition CloneBuildDefinition(IBuildDefinition buildDefinition)
{
var buildDefinitionClone = buildDefinition.BuildServer.CreateBuildDefinition(
buildDefinition.TeamProject);
buildDefinitionClone.BuildController = buildDefinition.BuildController;
buildDefinitionClone.ContinuousIntegrationType = buildDefinition.ContinuousIntegrationType;
buildDefinitionClone.ContinuousIntegrationQuietPeriod = buildDefinition.ContinuousIntegrationQuietPeriod;
buildDefinitionClone.DefaultDropLocation = buildDefinition.DefaultDropLocation;
buildDefinitionClone.Description = buildDefinition.Description;
buildDefinitionClone.Enabled = buildDefinition.Enabled;
buildDefinitionClone.Name = String.Format("Copy of {0}", buildDefinition.Name);
buildDefinitionClone.Process = buildDefinition.Process;
buildDefinitionClone.ProcessParameters = buildDefinition.ProcessParameters;
foreach (var schedule in buildDefinition.Schedules)
{
var newSchedule = buildDefinitionClone.AddSchedule();
newSchedule.DaysToBuild = schedule.DaysToBuild;
newSchedule.StartTime = schedule.StartTime;
newSchedule.TimeZone = schedule.TimeZone;
}
foreach (var mapping in buildDefinition.Workspace.Mappings)
{
buildDefinitionClone.Workspace.AddMapping(
mapping.ServerItem, mapping.LocalItem, mapping.MappingType, mapping.Depth);
}
buildDefinitionClone.RetentionPolicyList.Clear();
foreach (var policy in buildDefinition.RetentionPolicyList)
{
buildDefinitionClone.AddRetentionPolicy(
policy.BuildReason, policy.BuildStatus, policy.NumberToKeep, policy.DeleteOptions);
}
return buildDefinitionClone;
}
The following tool (VS Addin) will satisfy your requirement>
Community TFS Build Manager
http://visualstudiogallery.msdn.microsoft.com/16bafc63-0f20-4cc3-8b67-4e25d150102c
I just had a need to copy build definitions, and found Jim's answer above to be helpful. However, being new to the TFS API, I needed help connecting to the server and getting the existing build definition through code. These two links helped fill in the gaps:
http://msdn.microsoft.com/en-us/library/bb286958.aspx
http://geekswithblogs.net/jakob/archive/2010/04/26/creating-a-build-definition-using-the-tfs-2010-api.aspx
You can right click the build definition and select 'clone build definition' to copy the definition file. You can then edit it from there.
Here is the soltion if you want to move the Build definition from one Team Project to other Team project.
public void MoveBuild(string fromTeamProject, string toTeamProject, string buildName, string newBuildName)
{
var _server = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new
Uri("http://Mytfs:8080/defaultcollection"));
IBuildServer _buildServer = _server.GetService<IBuildServer>();
var buildDetails = _buildServer.QueryBuildDefinitions(fromTeamProject);
foreach (var fromBuild in buildDetails)
{
if (fromBuild.Name != buildName) continue;
var newBuildDefinition = _buildServer.CreateBuildDefinition(toTeamProject);
newBuildDefinition.Name = !string.IsNullOrEmpty(newBuildName) ? newBuildName : fromBuild.Name;
newBuildDefinition.BuildController = fromBuild.BuildController;
// This finds the template to use
foreach (var mapping in fromBuild.Workspace.Mappings)
{
newBuildDefinition.Workspace.AddMapping(
mapping.ServerItem, mapping.LocalItem, mapping.MappingType, mapping.Depth);
}
newBuildDefinition.DefaultDropLocation = fromBuild.DefaultDropLocation;
newBuildDefinition.Description = fromBuild.Description;
// buildDefinition.Workspace.AddMapping(build.Workspace.);
newBuildDefinition.Process = _buildServer.QueryProcessTemplates(fromBuild)[2];
newBuildDefinition.ProcessParameters = fromBuild.ProcessParameters;
newBuildDefinition.Enabled = false;
newBuildDefinition.Save();
}//end of for each loop
}
From your message it is not clear which template is your build definition using (default, upgrade or lab management). If I understand correctly you would like to easily set up a build definition which builds the same solution but from a different branch.
One thing that you could try instead of copying the definition is to edit it. When the branch dies, rename the build definition (might help with reporting), change the workspace mapping of the build and you should be done.
Thanks, Ladislau
Related
Can anyone help me to understand the below query,Actually in our tfs we have huge number of build definition those are not in use so far hence i want to delete old build definition by seraching all the builds those are older more than one year.
how to search build definitions in TFS2013 those are no longer in use??
Please help.
Thanks,
You can query out the definitions those are older more than one year by this query in SQL Server.
SELECT [DefinitionId],[DefinitionVersion],[DefinitionName] FROM [Tfs_CollectionLC].[Build].[tbl_Definition]
WHERE [CreatedOn] < '2016-06-12 00:00:00.000'
But for the definitions are no longer in use, you have to get the last build for each definition and check whether the build FinishTime is before a year ago (Where [FinishTime] < '2016-06-12 00:00:00.000' ).
You can use TFS API/Client API to get the build details which including the build FinishTime, then filter them accordingly.You can reference below code which enumerates each team project and gets the latest build status for each of the definitions:
TfsTeamProjectCollection tfs = new TfsTeamProjectCollection(new Uri("http://tfs:8080"));
var vcs = tfs.GetService<VersionControlServer>();
var teamProjects = vcs.GetAllTeamProjects(true);
IBuildServer buildServer = (IBuildServer)tfs.GetService(typeof(IBuildServer));
foreach (TeamProject proj in teamProjects)
{
var defs = buildServer.QueryBuildDefinitions(proj.Name);
System.Console.WriteLine(string.Format("Team Project: {0}", proj.Name));
foreach(IBuildDefinition def in defs)
{
IBuildDetailSpec spec = buildServer.CreateBuildDetailSpec(proj.Name, def.Name);
spec.MaxBuildsPerDefinition = 1;
spec.QueryOrder = BuildQueryOrder.FinishTimeDescending;
var builds = buildServer.QueryBuilds(spec);
if (builds.Builds.Length > 0)
{
var buildDetail = builds.Builds[0];
System.Console.WriteLine(string.Format(" {0} - {1} - {2}", def.Name, buildDetail.Status.ToString(), buildDetail.FinishTime));
}
}
System.Console.WriteLine();
}
Reference this thread:TFS API - How to query builds independent of which build definition they belong to
Update: Based on #Dhurva's comments below:
We can also use the utility from github TFS Manager that finds all build definition from team project:
https://github.com/jelledruyts/TfsTeamProjectManager
Does anyone know of a way to quickly get at the unit test results of a build in TFS2012?
Currently I have to find the build in visual studio and collapse the various other nodes in the summary as shown in the screenshot below. Then I have to expand each set of results to get at the failures. I just want a list of all failed tests.
I'd be happy to use SQL, SQL Reporting services or even a text file from the build.
Thanks
You can use TFS API to get the test result. Check the code snippet below:
TfsTeamProjectCollection tfs = new TfsTeamProjectCollection(new Uri("http://tfsserver:8080/tfs/collectionname"));
tfs.EnsureAuthenticated();
IBuildServer tfsBuildServer = tfs.GetService<IBuildServer>();
IBuildDefinition buildDef = tfsBuildServer.GetBuildDefinition("teamproject", "project");
var BuildUri = buildDef.LastBuildUri;
ITestManagementService testManagement = (ITestManagementService)tfs.GetService(typeof(ITestManagementService));
ITestManagementTeamProject testManagementTeamProject = testManagement.GetTeamProject("teamproject");
IEnumerable<ITestRun> testRuns = testManagementTeamProject.TestRuns.ByBuild(BuildUri);
foreach (ITestRun testRun in testRuns)
{
foreach (ITestCaseResult result in testRun.QueryResults())
{
Console.WriteLine(string.Format("TestCaseID:{0}", result.TestCaseTitle.ToString()));
Console.WriteLine(string.Format("TestCaseOutcome:{0}", result.Outcome.ToString()));
}
}
Here is my code:
var tfs = new TfsTeamProjectCollection(new Uri(TFS_SERVER_URL));
tfs.EnsureAuthenticated();
var buildServer = (IBuildServer)tfs.GetService(typeof(IBuildServer));
var spec = buildServer.CreateBuildDetailSpec(projectName);
spec.QueryOrder = BuildQueryOrder.FinishTimeDescending;
spec.MinFinishTime = DateTime.Now.Subtract(minFinishTimeOfs);
spec.MaxFinishTime = DateTime.Now.Subtract(maxFinishTimeOfs);
if (reason != null)
{
spec.Reason = reason.Value;
}
var buildDetails = buildServer.QueryBuilds(spec).Builds;
As you can see, I know how to query by time and build reason. But I want to be able to query by the build controller and I do not see how to do it efficiently. The inefficient way is to get the builds across all the build controllers and then filter them out, but I would like to avoid fetching irrelevant build details in the first place.
There is no API to judge from build definition to get IBuildDetail builds. As you mentioned above, you have to get firstly get all builds, and filter out unwanted builds with the IBuildDetail.BuildControllerUri property.
I want to programmatically delete a branch in TFS that was create automatically.
There is an existing method "ICommonStructureService.DeleteBranches" that should do the work.
My problem is that the method requires a parameter "string[] nodeUris" that specifies the branch to delete using a "vstfs://... " URI and I just don't know how to get that for my branch.
What I need is something like:
var projectCollection = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri <myCollectionUrl>));
var cssService = projectCollection.GetService<ICommonStructureService3>();
var project = cssService.GetProjectFromName(<myProjectName>);
But how can I get the Branch Uri from there?
Meanwhile I found a solution. For deleting the branches I am using
versionControl.Destroy(new ItemSpec(myBranchPath, RecursionType.Full), VersionSpec.Latest, null, DestroyFlags.KeepHistory);
This does exactly what I needed.
versionControl is of type VersionControlServer and must be initialized using the Team Collection
Deleting a branch in version control is like deleting any other version control item. You will need to pend a delete with Workspace.PendDelete on the Item.
The method you reference is wholly unrelated to version control, it's part of the TFS common structure service, which controls the "areas and iterations" that TFS work items can be assigned to.
In short, there's no way to perform any sort of version control operations against the common structure service. You delete a branch by creating a Workspace against a VersionControlServer, pending a delete and then checking in your pending changes.
I agree to Edward Thomson about using Destroy command. So I followed on advice from him and came up with following,
public void DeleteBranch(string path)
{
var vcs = GetVersionControlServer();
var itemSpec = new ItemSpec(path, RecursionType.Full);
var itemSpecs = new[] {itemSpec};
var workSpace = GetOrCreateWorkSpace(vcs);
try
{
workSpace.Map(path, #"c:\Temp\tfs");
var request = new GetRequest(itemSpec, VersionSpec.Latest);
workSpace.Get(request, GetOptions.GetAll | GetOptions.Overwrite);
workSpace.PendDelete(path, RecursionType.Full);
var pendingchanges = workSpace.GetPendingChanges(itemSpecs);
workSpace.CheckIn(pendingchanges, "Deleting The Branch");
}
finally
{
if (workSpace != null)
{
workSpace.Delete();
}
}
}
If there is a neat way to do the same than I am looking forward to it. This is bit slow as it does too many things,
Creates Temp Workspace
Gets All changes to that
Performs Delete to whole change set
checks it in
Cleans up the workspace
I'm working on customizing our build activity. I'd like to have your help for an issue.
Following is our version control hierarchy.
Main
|- Dev
|- QA
we are working on Dev branch and while taking the build we need to merge Dev branch to Main then to QA.
Main is the root branch as you might know.
In our build template, I've added two custom activities to merge one from Dev to Main and another one to merge from Main to QA. Following is the code for the custom activity.
protected override string Execute(CodeActivityContext context)
{
string lstrStatus = string.Empty;
string lstrSourceBranchPath = context.GetValue(this.SourceBranchPath);
string lstrTargetBranchPath = context.GetValue(this.TargetBranchPath);
// Obtain the runtime value of the input arguments
Workspace workspace = context.GetValue(this.Workspace);
GetStatus status = workspace.Merge(lstrSourceBranchPath,
lstrTargetBranchPath,
null,
null,
LockLevel.None,
RecursionType.Full,
MergeOptions.None);
// resolve the conflicts, if any
if (status.NumConflicts > 0)
{
Conflict[] conflicts = workspace.QueryConflicts(new string[]
{ lstrTargetBranchPath }, true);
foreach (Conflict conflict in conflicts)
{
conflict.Resolution = Resolution.AcceptTheirs;
workspace.ResolveConflict(conflict);
}
}
// checkin the changes
PendingChange[] pendingChanges = workspace.GetPendingChanges();
if (pendingChanges != null && pendingChanges.Length > 0)
{
workspace.CheckIn(pendingChanges, "Merged by MERGE BRANCHES activity");
}
return lstrStatus;
}
Problem is, merging happens perfectly in the server. But, it's not getting reflected in the local folder. I tried to add SyncWorkspace activity after each Merge custom activity. Still not working.
My guess was that a SyncWorkspace should be the only thing to do.
You could try doing a RevertWorkspace before that.
EDIT
After you now stated that even this wouldn't work, I would generate a bug against MS at least to get an official answer.
In the meanwhile you can try with the following method, which I absolutely see as an overkill: Once you have checked in, redo all the steps within sequence Initialize Workspace.
If even that doesn't work I'd consider two different builds, one that does your merge & one that does the actual build. You can then organize a scheme where your first build, once it's done, triggers the second one. Here is a good resource for that.