Skip to content

Instantly share code, notes, and snippets.

@praschl
Last active October 2, 2017 07:55
Show Gist options
  • Select an option

  • Save praschl/5c6b1ef07c5371ea25f700ddb28bfe56 to your computer and use it in GitHub Desktop.

Select an option

Save praschl/5c6b1ef07c5371ea25f700ddb28bfe56 to your computer and use it in GitHub Desktop.
Query running builds on TFS
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