File: Clients\AzureDevOpsClient.cs
Web Access
Project: src\src\Microsoft.DotNet.Git.IssueManager\src\Microsoft.DotNet.Git.IssueManager.csproj (Microsoft.DotNet.Git.IssueManager)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using Newtonsoft.Json;
using System;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
 
namespace Microsoft.DotNet.Git.IssueManager.Clients
{
    static class AzureDevOpsClient
    {
        private static readonly Regex RepositoryUriPattern = new Regex(
            @"^https://dev\.azure\.com\/(?<account>[a-zA-Z0-9]+)/(?<project>[a-zA-Z0-9-]+)/_git/(?<repo>[a-zA-Z0-9-\\.]+)");
 
        private static readonly Regex LegacyRepositoryUriPattern = new Regex(
            @"^https://(?<account>[a-zA-Z0-9]+)\.visualstudio\.com/(?<project>[a-zA-Z0-9-]+)/_git/(?<repo>[a-zA-Z0-9-\.]+)");
 
        private const string DefaultApiVersion = "5.0";
 
        public static async Task<string> GetCommitAuthorAsync(
            string repositoryUrl,
            string commit,
            string personalAccessToken)
        {
            (string accountName, string projectName, string repoName) = ParseRepoUri(repositoryUrl);
 
            using (HttpClient httpClient = GetHttpClient(accountName, projectName, personalAccessToken))
            {
                HttpRequestMessage getMessage = new HttpRequestMessage(HttpMethod.Get, $"_apis/git/repositories/{repoName}/commits?searchCriteria.ids={commit}");
                HttpResponseMessage response = await httpClient.SendAsync(getMessage);
 
                response.EnsureSuccessStatusCode();
 
                AzureDevOpsCommit commitResponse = JsonConvert.DeserializeObject<AzureDevOpsCommit>(await response.Content.ReadAsStringAsync());
 
                if (commitResponse == null)
                {
                    throw new Exception($"No commit with id {commit} found in '{repositoryUrl}'");
                }
 
                return $"Azure DevOps user: {commitResponse.Value.First().Author.Name}";
            }
        }
 
        private static HttpClient GetHttpClient(string accountName, string projectName, string personalAccessToken)
        {
            HttpClient client = new HttpClient(new HttpClientHandler { CheckCertificateRevocationList = true })
            {
                BaseAddress = new Uri($"https://dev.azure.com/{accountName}/{projectName}/")
            };
 
            client.DefaultRequestHeaders.Add(
                "Accept",
                $"application/json;api-version={DefaultApiVersion}");
            client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
                "Basic",
                Convert.ToBase64String(Encoding.ASCII.GetBytes(string.Format("{0}:{1}", "", personalAccessToken))));
 
            return client;
        }
 
        private static (string accountName, string projectName, string repoName) ParseRepoUri(string repositoryUri)
        {
            Match m = RepositoryUriPattern.Match(repositoryUri);
            if (!m.Success)
            {
                m = LegacyRepositoryUriPattern.Match(repositoryUri);
                if (!m.Success)
                {
                    throw new ArgumentException(
                        "Repository URI should be in the form https://dev.azure.com/:account/:project/_git/:repo or " +
                        "https://:account.visualstudio.com/:project/_git/:repo");
                }
            }
 
            return (m.Groups["account"].Value,
                    m.Groups["project"].Value,
                    m.Groups["repo"].Value);
        }
    }
}