Building a C# and .NET Git repository reporting tool with Azure DevOps
Tags: csharp, dotnet, devops
Published: 2023-04-24 20:21:35

I've been using the Azure Devops CLI to build programs to generate reports on a TFS repository that uses Git for version controlling (see: [Using Azure Devops CLI to generate repository reports] (https://dev.to/absterellio/using-azure-devops-cli-to-generate-repository-reports-1h7d) and [Adding a simple (old-fashioned) GUI to Azure Devops CLI script
] (https://dev.to/absterellio/adding-a-simple-old-fashioned-gui-to-azure-devops-cli-script-4eoe)). 

I decided to build a more robust C# and .NET application that utilizes the Azure DevOps SDK.

##Overview
This program takes in a TFS iteration path and returns a report of TFS work items, Git pull requests and other details from that iteration. This report is generated as a .csv file with columns for WorkItem, Pull Request, Reviewers, and Target Branch.

##The Code

The project can be found on my GitHub page: {% embed https://github.com/absterellio/azure-csharp-dotnet-tool %}

**The Entry Point**

Program.cs is the main entry point into the application. It creates an instance of IterationLogic.cs and calls the GetIterationInformation method within that class, where all of my main logic lives.

The constructor of this class creates an instance of a VssConnection, passing in an organization URL and a created VssBasicCredential. This VssConnection will be used to access the classes and methods and to return data from the DevOps services.

`Uri orgUrl = new Uri(ConstantValues.OrganizationURL);
this.connection = new VssConnection(orgUrl, new VssBasicCredential(string.Empty, personalAccessToken));`

The constructor also creates a new TeamContext variable which will be required later anywhere the WorkHttpClient is used.

`teamContext = new TeamContext(ConstantValues.PlatformTeamName);`

**Retrieving an Iteration**

The iteration path we want to work with is passed into this method as a string. In order to get information about this iteration we need to create an instance of the WorkHttpClient.

`WorkHttpClient workHttpClient = connection.GetClient<WorkHttpClient>();`

The following code will retrieve all of the iterations based on the TeamContext created earlier. Using the retrieved iterations, we can filter on the specified iteration path string.

`List<TeamSettingsIteration> results workHttpClient.GetTeamIterationsAsync(teamContext).Result;
iterationMatch = results.First(x => x.Path == iterationPath);
`

**Retrieving Work Items for an Iteration**

The following code will retrieve all work items for a given iteration. The WorkHttpClient contains a method to fetch all work items.

`workItems = workHttpClient.GetIterationWorkItemsAsync(teamContext, iteration.Id).Result;`

**Getting Details for a Work Item**

After fetching these work items, we can hammer down further to find more details about a work item. The WorkItemTrackingHttpClient provides a method to get details for a specific work item. This method can also optionally take in a list of specific fields to return as the second argument.

`WorkItemTrackingHttpClient witClient = connection.GetClient<WorkItemTrackingHttpClient>();
workItem = witClient.GetWorkItemAsync(workItemId).Result;
`

**Fetching Git Pull Requests for a Work Item**

Lastly, the final output I want to return is a list of pull requests submitted for each work item. This will require two clients, the WorkItemTrackingHttpClient and GitHttpClient.

`var witClient = connection.GetClient<WorkItemTrackingHttpClient>();
var gitHttpClient = connection.GetClient<GitHttpClient>();`

Fetching the work item can be done with the following code.

`var workItem = witClient.GetWorkItemAsync(workItemId, expand: Microsoft.TeamFoundation.WorkItemTracking.WebApi.Models.WorkItemExpand.Relations).Result;`

The returned work item will have a list of Relation attributes. We can filter out the pull requests from this list, and then loop through and use the GitHttpClient to get details for each PullRequestId returned.

`var gitPullRequest = gitHttpClient.GetPullRequestByIdAsync(Int32.Parse(ids[2]));`

With the pull request returned, I can map the properties back to my own PullRequest view model to print later.

`var prObj = new models.PullRequest
{
    WorkItemId = workItemId,
    ID = pullRequestResult.PullRequestId.ToString(),
    TargetBranch = pullRequestResult.TargetRefName,
    Description = pullRequestResult.Description,
};`

--- 

Overall, this tool ended up being helpful to get some quick data and track workflow on a TFS repository. There are so many more functions that the Azure DevOps .NET SDK provides but I wanted to highlight some of the methods that were helpful to me when building this reporting tool. Writing this program was a great way to get started and jump into programming with the Azure DevOps SDK.

Thanks for reading and feel free to share your thoughts or check out the repository on [GitHub](https://github.com/absterellio/azure-csharp-dotnet-tool)!