diff --git a/DotNet.DocsTools/DotNet.DocsTools.csproj b/DotNet.DocsTools/DotNet.DocsTools.csproj index 9933475a..481747ef 100644 --- a/DotNet.DocsTools/DotNet.DocsTools.csproj +++ b/DotNet.DocsTools/DotNet.DocsTools.csproj @@ -9,6 +9,7 @@ + diff --git a/DotNet.DocsTools/OspoClientServices/OspoClient.cs b/DotNet.DocsTools/OspoClientServices/OspoClient.cs index a0347b74..e82b8069 100644 --- a/DotNet.DocsTools/OspoClientServices/OspoClient.cs +++ b/DotNet.DocsTools/OspoClientServices/OspoClient.cs @@ -7,7 +7,6 @@ using System.Net; using System.Net.Http.Headers; using System.Net.Http.Json; -using System.Text; namespace Microsoft.DotnetOrg.Ospo; @@ -22,6 +21,7 @@ public sealed class OspoClient : IDisposable public OspoClient(string token, bool useAllCache) { ArgumentNullException.ThrowIfNull(token); + _useAllCache = useAllCache; _httpClient = new HttpClient @@ -30,7 +30,8 @@ public OspoClient(string token, bool useAllCache) }; _httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); _httpClient.DefaultRequestHeaders.Add("api-version", "2019-10-01"); - _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("basic", Convert.ToBase64String(Encoding.ASCII.GetBytes($":{token}"))); + _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue( + "Bearer", token); var delay = Backoff.DecorrelatedJitterBackoffV2( medianFirstRetryDelay: TimeSpan.FromMinutes(3), retryCount: 2); @@ -48,29 +49,31 @@ public OspoClient(string token, bool useAllCache) .WaitAndRetryAsync(delay); } - public void Dispose() - { - _httpClient.Dispose(); - } + public void Dispose() => _httpClient.Dispose(); public async Task GetAsync(string gitHubLogin) { if ((_useAllCache) || (_allLinks is not null)) { _allLinks ??= await GetAllAsync(); + return _allLinks.LinkByLogin.GetValueOrDefault(gitHubLogin); } if (_allEmployeeQueries.TryGetValue(gitHubLogin, out var query)) + { return query; + } var result = await _retryPolicy.ExecuteAndCaptureAsync(async () => { var link = await _httpClient.GetFromJsonAsync( - $"people/links/github/{gitHubLogin}", JsonSerializerOptionsDefaults.Shared); + $"people/links/github/{gitHubLogin}", JsonSerializerOptionsDefaults.Shared); + return link; }); - if (result.Outcome == OutcomeType.Failure) + + if (result is { Outcome: OutcomeType.Failure }) { Console.WriteLine("WARNING: OSPO REST API failure. Check access token rights"); Console.WriteLine("WARNING: App running in degraded mode."); @@ -82,22 +85,26 @@ public void Dispose() public async Task GetAllAsync() { if (_allLinks is not null) + { return _allLinks; + } + var result = await _retryPolicy.ExecuteAndCaptureAsync(async () => { var links = await _httpClient.GetFromJsonAsync>( - $"people/links", JsonSerializerOptionsDefaults.Shared); + $"people/links", JsonSerializerOptionsDefaults.Shared); var linkSet = new OspoLinkSet { - Links = links ?? Array.Empty() + Links = links ?? [] }; linkSet.Initialize(); + return linkSet; }); - if (result.Outcome == OutcomeType.Failure) + if (result is { Outcome: OutcomeType.Failure }) { Console.WriteLine("WARNING: OSPO REST API failure. Check access token rights"); Console.WriteLine("WARNING: App running in degraded mode."); @@ -108,6 +115,7 @@ public async Task GetAllAsync() { _allLinks = result.Result; } + return _allLinks; } } diff --git a/DotNet.DocsTools/OspoClientServices/OspoClientFactory.cs b/DotNet.DocsTools/OspoClientServices/OspoClientFactory.cs new file mode 100644 index 00000000..ae5e36a9 --- /dev/null +++ b/DotNet.DocsTools/OspoClientServices/OspoClientFactory.cs @@ -0,0 +1,69 @@ +using CliWrap; +using CliWrap.Buffered; +using DotNetDocs.Tools.Utility; +using Microsoft.DotnetOrg.Ospo; + +namespace DotNet.DocsTools.OspoClientServices; + +public static class OspoClientFactory +{ + public static async Task CreateAsync() + { + await LoginAsync(); + + var token = await GetTokenAsync(); + + return new OspoClient(token, true); + } + + private static async ValueTask LoginAsync() + { + // az login + var result = await Cli.Wrap("az") + .WithArguments( + [ + "login", + "--scope", + "links" + ]) + .WithValidation(CommandResultValidation.None) + .ExecuteAsync(); + + if (result.IsSuccess == false) + { + Console.WriteLine($"The 'az login' command supposedly failed with {result.ExitCode} after {result.RunTime}."); + } + } + + private static async ValueTask GetTokenAsync() + { + //var resource = CommandLineUtility.GetEnvVariable( + // "OSMP_API_AUDIENCE", "Unable to get the scoped/resource.", null); + + // az account get-access-token + // --query 'accessToken' + // -o tsv + // --scope "links" + // --resource "Some test audience" + var tokenResult = await Cli.Wrap("az") + .WithArguments( + [ + "account", + "get-access-token", + "--query", "accessToken", + "-o", "tsv", + "--scope", "links", + //"--resource", resource + ]) + .ExecuteBufferedAsync(); + + var token = tokenResult.StandardOutput.Trim(); + + if (string.IsNullOrEmpty(token)) + { + Console.WriteLine($"az account get-access-token failed"); + } + + return token; + } +} diff --git a/Sandbox/Program.cs b/Sandbox/Program.cs new file mode 100644 index 00000000..40b3cee4 --- /dev/null +++ b/Sandbox/Program.cs @@ -0,0 +1,10 @@ +using DotNet.DocsTools.OspoClientServices; + +var client = await OspoClientFactory.CreateAsync(); + +var link = await client.GetAsync("IEvangelist"); + +if (link is not null) +{ + _ = link; +} diff --git a/Sandbox/Sandbox.csproj b/Sandbox/Sandbox.csproj new file mode 100644 index 00000000..009e34d0 --- /dev/null +++ b/Sandbox/Sandbox.csproj @@ -0,0 +1,14 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + diff --git a/docs-tools.sln b/docs-tools.sln index 41620a82..e2210611 100644 --- a/docs-tools.sln +++ b/docs-tools.sln @@ -1,4 +1,3 @@ - Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.4.33205.214 @@ -78,6 +77,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "XmlDocConflictResolver", "X EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RepoManCheckerCLI", "RepoManChecker\RepoManCheckerCLI.csproj", "{1C59182B-9266-43FB-8398-86AE0F5012D6}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sandbox", "Sandbox\Sandbox.csproj", "{C93AB0B6-1B1A-4172-909B-81249CDAFC6D}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -116,6 +117,10 @@ Global {BCDD57DA-6C08-49CA-8F03-D4FC4FF2ABCC}.Debug|Any CPU.Build.0 = Debug|Any CPU {BCDD57DA-6C08-49CA-8F03-D4FC4FF2ABCC}.Release|Any CPU.ActiveCfg = Release|Any CPU {BCDD57DA-6C08-49CA-8F03-D4FC4FF2ABCC}.Release|Any CPU.Build.0 = Release|Any CPU + {C93AB0B6-1B1A-4172-909B-81249CDAFC6D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C93AB0B6-1B1A-4172-909B-81249CDAFC6D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C93AB0B6-1B1A-4172-909B-81249CDAFC6D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C93AB0B6-1B1A-4172-909B-81249CDAFC6D}.Release|Any CPU.Build.0 = Release|Any CPU {D9BB2E16-F28E-4BA7-98F9-4303891C3C34}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D9BB2E16-F28E-4BA7-98F9-4303891C3C34}.Debug|Any CPU.Build.0 = Debug|Any CPU {D9BB2E16-F28E-4BA7-98F9-4303891C3C34}.Release|Any CPU.ActiveCfg = Release|Any CPU