I’ve been working with VSTS for quite some time now and wanted to share some of the sample code I’ve written to work with VSTS data. As I work with many teams, there have been requests such as getting specific metadata during and/or after build. Examples would be people wanting to get specific data from associated work-items during builds or collection level licensing information for your users. Here are I’ll tap in to specific areas:
VSTS Builds, VSTS Work-Items, VSTS GIT (Commits), VSTS User License Information
You’ll need to the following Nuget Packages:
- Microsoft.TeamFoundationServer.ExtendedClient
- Microsoft.TeamFoundationServer.Client
- Microsoft.VisualStudio.Services.Client
- Microsoft.VisualStudio.Services.InteractiveClient
Sample Code to retrieve all Builds from a given VSTS Team Project Build Definition containing associated commits and work-items:
using System;
using System.Configuration;
using System.Linq;
using System.Text;
using AAG.Test.Core.Logger;
using Microsoft.TeamFoundation.Build.WebApi;
using Microsoft.TeamFoundation.SourceControl.WebApi;
using Microsoft.VisualStudio.Services.Client;
using VSTSApi.Entities;
using Microsoft.VisualStudio.Services.Common;
using Microsoft.TeamFoundation.WorkItemTracking.WebApi;
namespace VSTSApi
{
class Program
{
private static BuildOutputModel _buildoutputmodel;
private static string VssAccountUrl { get; set; } = ConfigurationManager.AppSettings["VssAccountUrl"];
static void Main(string[] args)
{
try
{
StringBuilder outputStringBuilder = new StringBuilder();
var buildoutputmodel = SetBuildOutputModel(args);
var creds = new VssClientCredentials(false);
creds.PromptType = CredentialPromptType.PromptIfNeeded;
var vssConnection = new VssConnection(new Uri(buildoutputmodel.VSOUrl + "/defaultcollection"), new VssBasicCredential(buildoutputmodel.UserName, buildoutputmodel.Password));
var buildserver = vssConnection.GetClient<BuildHttpClient>();
var workitems = vssConnection.GetClient<WorkItemTrackingHttpClient>();
var commititems = vssConnection.GetClient<GitHttpClient>();
var builds = buildserver.GetBuildsAsync(_buildoutputmodel.TeamProjectName).Result;
var targetbuilds = builds.Where(definition => definition.Definition.Name.Contains(buildoutputmodel.BuilDefinitionName));
foreach (var build in targetbuilds)
{
outputStringBuilder.AppendLine($"Name: {build.Definition.Name} : BuildID: {build.Id}");
var associatedcommits = buildserver.GetBuildCommitsAsync(build.Definition.Project.Name,
build.Id).Result;
if (associatedcommits.Any())
outputStringBuilder.AppendLine($"All Commits Made for this Build: {Environment.NewLine} ========= {Environment.NewLine} ");
associatedcommits.ForEach(commit =>
{
var user = commititems.GetCommitAsync(buildoutputmodel.TeamProjectName, commit.Id, buildoutputmodel.GitRepo).Result.Author;
outputStringBuilder.AppendLine($"ID: {commit.Id} Committed By: {user.Name} E-mail: {user.Email} {Environment.NewLine} Description: {commit.Message} {Environment.NewLine}");
});
var commits = associatedcommits.Select(change => change.Id);
var associatedworkitems = buildserver.GetBuildWorkItemsRefsAsync(commits,
build.Definition.Project.Name, build.Id).Result;
if (associatedworkitems.Any())
outputStringBuilder.AppendLine($"All Associated Workitems for this Build: {Environment.NewLine} ========= {Environment.NewLine} ");
foreach (var wi in associatedworkitems)
{
outputStringBuilder.AppendLine($"ID : {wi.Id} : URL: {wi.Url}");
var workitem = workitems.GetWorkItemAsync(int.Parse(wi.Id)).Result;
outputStringBuilder.AppendLine($"Title : {workitem.Fields["Title"]} : Description: {workitem.Fields["Description"]}");
}
outputStringBuilder.AppendLine($"{Environment.NewLine} ========= {Environment.NewLine} ");
}
//}
DumpData(outputStringBuilder.ToString(), Console.WriteLine);
DumpData(outputStringBuilder.ToString(), print => AsLogger.Info(print));
Console.WriteLine("Press Any Key to Continue...");
Console.ReadKey();
}
catch (Exception exception)
{
throw new Exception($"Error with Application: {exception.Message}", exception.InnerException);
}
}
static void DumpData(string stringoutput, Action<string> print)
{
print(stringoutput);
}
static BuildOutputModel SetBuildOutputModel(string[] args)
{
_buildoutputmodel = new BuildOutputModel
{
UserName = ConfigurationManager.AppSettings["username"],
Password = ConfigurationManager.AppSettings["password"],
VSOUrl = ConfigurationManager.AppSettings["vsourl"],
TeamProjectName = ConfigurationManager.AppSettings["teamproject"],
BuilDefinitionName = ConfigurationManager.AppSettings["builddefinition"],
GitRepo = ConfigurationManager.AppSettings["gitrepo"]
};
return _buildoutputmodel;
}
}
}
Entity
namespace VSTSApi.Entities
{
public class BuildOutputModel
{
public string UserName { get; set; }
public string Password { get; set; }
public string BuilDefinitionName { get; set; }
public string TeamProjectName { get; set; }
public string VSOUrl { get; set; }
public string GitRepo { get; set; }
}
}
Sample Code for Getting User Information/Licenses:
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using VSTSAccountAdmin.Model;
using Microsoft.VisualStudio.Services.Client;
using Microsoft.VisualStudio.Services.Common;
using Microsoft.VisualStudio.Services.Identity.Client;
using Microsoft.VisualStudio.Services.Licensing;
using Microsoft.VisualStudio.Services.Licensing.Client;
namespace VSTSAccountAdmin
{
public class Program
{
private static string VssAccountUrl { get; set; } = ConfigurationManager.AppSettings["VssAccountUrl"];
private static string VssAccountName { get; set; }
private static License VssLicense { get; set; }
private static List<VSOUserInfo> _vsousers;
public static void Main(string[] args)
{
try
{
_vsousers = new List<VSOUserInfo>();
// Create a connection to the specified account.
// If you change the false to true, your credentials will be saved.
var creds = new VssClientCredentials(false);
creds.PromptType = CredentialPromptType.PromptIfNeeded;
var vssConnection = new VssConnection(new Uri(VssAccountUrl), creds);
// We need the clients for tw4o services: Licensing and Identity
var licensingClient = vssConnection.GetClient<LicensingHttpClient>();
var identityClient = vssConnection.GetClient<IdentityHttpClient>();
var entitlements = licensingClient.GetAccountEntitlementsAsync().Result;
IEnumerable<AccountEntitlement> accountEntitlements = entitlements as IList<AccountEntitlement> ??
entitlements.ToList();
var userIds = accountEntitlements.Select(entitlement => entitlement.UserId).ToList();
var users = identityClient.ReadIdentitiesAsync(userIds).Result.ToDictionary(item => item.Id);
foreach (var entitlement in accountEntitlements)
{
var user = users[entitlement.UserId];
_vsousers.Add(new VSOUserInfo()
{
DisplayName = user.DisplayName,
LastAccessDate = entitlement.LastAccessedDate,
License = entitlement.License.ToString().ToLowerInvariant(),
UserID = entitlement.UserId
});
var stringoutput =
$"{Environment.NewLine}Name: {user.DisplayName}, UserId: {entitlement.UserId}, License: {entitlement.License}.";
Console.WriteLine(stringoutput);
}
}
catch (Exception ex)
{
throw new ArgumentException(ex.Message, ex.InnerException);
}
}
}
}
Entity:
namespace VSTSAccountAdmin.Model
{
public class VSOUserInfo
{
public string DisplayName { get; set; }
public Guid UserID { get; set; }
public string License { get; set; }
public DateTimeOffset LastAccessDate { get; set; }
}
}