Last active
October 2, 2017 07:55
-
-
Save praschl/5c6b1ef07c5371ea25f700ddb28bfe56 to your computer and use it in GitHub Desktop.
Query running builds on TFS
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| TimeSpan maxBuildAge = TimeSpan.FromMinutes(15); | |
| void Main() | |
| { | |
| var coll = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri("http://sv-int-tfs-02:8080/tfs/DefaultCollection")); | |
| var buildService = coll.GetService<IBuildServer>(); | |
| var spec = buildService.CreateBuildQueueSpec("*", "*"); | |
| spec.CompletedWindow = maxBuildAge; | |
| var foundBuilds = buildService.QueryQueuedBuilds(spec); | |
| const string xns = "http://schemas.microsoft.com/winfx/2006/xaml"; | |
| const string rootns = "clr-namespace:System.Collections.Generic;assembly=mscorlib"; | |
| var namespaceManager = new XmlNamespaceManager(new NameTable()); | |
| namespaceManager.AddNamespace("x", xns); | |
| namespaceManager.AddNamespace(string.Empty, rootns); | |
| const string arrayName = "{" + xns + "}Array"; | |
| const string stringName = "{" + xns + "}String"; | |
| var result = from b in foundBuilds.QueuedBuilds.OrderBy(b => b.TeamProject).ThenBy(b => b.BuildDefinition.Name) | |
| let xml = XDocument.Parse(b.Build.ProcessParameters ?? b.BuildDefinition.ProcessParameters) | |
| let deploy = xml.Root.Elements(arrayName).Elements(stringName).Select(e => e.Value) | |
| let bc = Connect(b) | |
| select new | |
| { | |
| b.TeamProject, | |
| b.BuildDefinition.Name, | |
| b.BuildDefinition.Workspace.Mappings.First().ServerItem, | |
| b.RequestedBy, | |
| Progress = GetProgress(b, buildService), | |
| Deploy = string.Join(" | ", deploy), | |
| DropLocation = GetDropLocation(b), | |
| Cancel = GetStopLink(b), | |
| //Xml = xml, | |
| }; | |
| result.Dump(); | |
| } | |
| object GetProgress(IQueuedBuild build, IBuildServer buildService) | |
| { | |
| var container = new DumpContainer("Calculating..."); | |
| Task.Run(() => | |
| { | |
| var bar = new Util.ProgressBar(); | |
| var spec = buildService.CreateBuildDetailSpec(build.BuildDefinition); | |
| spec.MaxBuildsPerDefinition = 100; | |
| spec.QueryOrder = BuildQueryOrder.FinishTimeDescending; | |
| spec.QueryDeletedOption = QueryDeletedOption.ExcludeDeleted; | |
| spec.Status = BuildStatus.Succeeded | BuildStatus.PartiallySucceeded; | |
| spec.InformationTypes = new[] { "BuildProject" }; | |
| var calcBuilds = buildService.QueryBuilds(spec); | |
| var seconds = calcBuilds.Builds.OrderByDescending(e => e.FinishTime).Where(b => b.BuildFinished) | |
| .Select(b => (b.FinishTime - b.StartTime).TotalSeconds).DefaultIfEmpty(0).ToArray(); | |
| var min = seconds.Min(); | |
| var max = seconds.Max(); | |
| var expectedSeconds = seconds.Average(); | |
| build.StatusChanged += (o, e) => UpdateProgress(container, bar, build, expectedSeconds, (int)min, (int)max); | |
| UpdateProgress(container, bar, build, expectedSeconds, 0, 0); | |
| }).ConfigureAwait(false); | |
| UpdateProgress(container, null, build, 0, 0, 0); | |
| return container; | |
| } | |
| void UpdateProgress(DumpContainer container, Util.ProgressBar bar, IQueuedBuild build, double expectedSeconds, int min, int max) | |
| { | |
| if (build.Status == QueueStatus.InProgress) | |
| { | |
| if (bar != null) | |
| { | |
| container.Content = bar; | |
| var time = (int)(DateTime.Now - build.QueueTime).TotalSeconds; | |
| var percent = (int)(time / expectedSeconds * 100); | |
| if (percent >= 99) percent = 99; | |
| bar.Percent = percent; | |
| var restSecs = (int)expectedSeconds - time; | |
| if (min == max) | |
| bar.Caption = $"{restSecs} [{min}]"; | |
| else | |
| bar.Caption = $"{restSecs} [{min}-{max}]"; | |
| } | |
| } | |
| else if (build.Status == QueueStatus.Completed || build.Status == QueueStatus.Canceled) | |
| { | |
| if (build.Build.Status == BuildStatus.Succeeded) | |
| container.Content = build.Build.Status; | |
| else | |
| container.Content = $"{build.Build.Status} ({build.Build.CompilationStatus}, {build.Build.TestStatus})"; | |
| build.Disconnect(); | |
| } | |
| } | |
| object GetStopLink(IQueuedBuild build) | |
| { | |
| var container = new DumpContainer(string.Empty); | |
| build.StatusChanged += (o, e) => | |
| { | |
| if (build.Status == QueueStatus.InProgress || build.Status == QueueStatus.Queued) | |
| container.Content = new Hyperlinq(() => build.Build.Stop(), "Stop Build"); | |
| }; | |
| return container; | |
| } | |
| object GetDropLocation(IQueuedBuild build) | |
| { | |
| var container = new DumpContainer(); | |
| if (build.Status != QueueStatus.InProgress && build.Status != QueueStatus.Queued) | |
| container.Content = new Hyperlinq(() => Process.Start(build.Build.DropLocation), build.Build.DropLocation); | |
| build.StatusChanged += (o, e) => | |
| { | |
| if (build.Status != QueueStatus.InProgress && build.Status != QueueStatus.Queued) | |
| container.Content = new Hyperlinq(() => Process.Start(build.Build.DropLocation), build.Build.DropLocation); | |
| }; | |
| return container; | |
| } | |
| object Connect(IQueuedBuild build) | |
| { | |
| build.Connect(2000, int.MaxValue, null); | |
| Util.Cleanup += (o, e) => build?.Disconnect(); | |
| return null; | |
| } | |
| // Define other methods and classes here |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment