Skip to content

Commit 6e51122

Browse files
committed
First pass at migrating the code and tests
1 parent 3b719d2 commit 6e51122

17 files changed

+483
-170
lines changed

.github/workflows/dotnet.yml

Lines changed: 66 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,77 @@
1-
# This workflow will build a .NET project
2-
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net
3-
4-
name: .NET
1+
name: .NET - Build NuGet and Publish
52

63
on:
4+
workflow_dispatch:
75
push:
86
branches: [ "main" ]
97
pull_request:
108
branches: [ "main" ]
119

1210
jobs:
1311
build:
14-
12+
name: Build and analyze
1513
runs-on: ubuntu-latest
16-
14+
env:
15+
ProjectName: 'AStar.Dev.Admin.Api.Client.Sdk'
16+
RepositoryName: 'astar-dev-admin-api-client-sdk'
1717
steps:
18-
- uses: actions/checkout@v4
19-
20-
- name: Setup .NET
21-
uses: actions/setup-dotnet@v4
22-
with:
23-
dotnet-version: 9.0.x
24-
25-
- name: Delete nuget*.config files
26-
run: rm -f nuget*.config
27-
28-
- name: Restore dependencies
29-
run: dotnet restore
30-
31-
- name: Build
32-
run: dotnet build --no-restore
33-
34-
- name: Test
35-
run: dotnet test --no-build --verbosity normal
18+
- name: Set up JDK
19+
uses: actions/[email protected]
20+
with:
21+
java-version: 17
22+
distribution: 'zulu'
23+
24+
- name: Setup .NET
25+
uses: actions/setup-dotnet@v4
26+
with:
27+
dotnet-version: 9.0.x
28+
29+
- name: Checkout
30+
uses: actions/[email protected]
31+
with:
32+
fetch-depth: 0
33+
34+
- name: Delete nuget*.config files
35+
run: rm -f nuget*.config
36+
37+
- name: Cache SonarCloud packages
38+
uses: actions/[email protected]
39+
with:
40+
path: ~\sonar\cache
41+
key: ${{ runner.os }}-sonar
42+
restore-keys: ${{ runner.os }}-sonar
43+
44+
- name: Cache SonarCloud scanner
45+
id: cache-sonar-scanner
46+
uses: actions/[email protected]
47+
with:
48+
path: .\.sonar\scanner
49+
key: ${{ runner.os }}-sonar-scanner
50+
restore-keys: ${{ runner.os }}-sonar-scanner
51+
52+
- name: Install SonarCloud scanner
53+
if: steps.cache-sonar-scanner.outputs.cache-hit != 'true'
54+
shell: powershell
55+
run: |
56+
New-Item -Path .\.sonar\scanner -ItemType Directory
57+
dotnet tool update dotnet-sonarscanner --tool-path .\.sonar\scanner
58+
59+
- name: Build and analyze
60+
env:
61+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
62+
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
63+
shell: powershell
64+
run: |
65+
dotnet tool install --global dotnet-coverage
66+
.\.sonar\scanner\dotnet-sonarscanner begin /k:"astar-development_${{ env.RepositoryName }}" /o:"astar-development" /d:sonar.token="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io" /d:sonar.cs.vscoveragexml.reportsPaths=coverage.xml /d:sonar.scanner.scanAll=false
67+
dotnet build --configuration Release
68+
dotnet-coverage collect 'dotnet test --filter "FullyQualifiedName!~Acceptance.Tests"' -f xml -o 'coverage.xml'
69+
.\.sonar\scanner\dotnet-sonarscanner end /d:sonar.token="${{ secrets.SONAR_TOKEN }}"
70+
71+
- name: Pack NuGet package
72+
if: github.ref == 'refs/heads/main'
73+
run: dotnet pack .\src\${{ env.ProjectName }}\${{ env.ProjectName }}.csproj
74+
75+
- name: Push to NuGet
76+
if: github.ref == 'refs/heads/main'
77+
run: dotnet nuget push "**\${{ env.ProjectName }}.*.nupkg" --api-key ${{secrets.nuget_api_key}} --skip-duplicate --source https://api.nuget.org/v3/index.json

AStar.Dev.Admin.Api.Client.Sdk.sln

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,16 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AStar.Dev.Admin.Api.Client.
1111
EndProject
1212
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit", "test\AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit\AStar.Dev.Admin.Api.Client.Sdk.Tests.Unit.csproj", "{20915888-5AEA-4918-8DE4-FBE77EFCC758}"
1313
EndProject
14+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{94A53025-23C4-4B9D-B015-B7CDBD1E2275}"
15+
ProjectSection(SolutionItems) = preProject
16+
.github\dependabot.yml = .github\dependabot.yml
17+
EndProjectSection
18+
EndProject
19+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{790D531F-FFB9-4C8C-A861-C469CDF5DB9D}"
20+
ProjectSection(SolutionItems) = preProject
21+
.github\workflows\dotnet.yml = .github\workflows\dotnet.yml
22+
EndProjectSection
23+
EndProject
1424
Global
1525
GlobalSection(SolutionConfigurationPlatforms) = preSolution
1626
Debug|Any CPU = Debug|Any CPU
@@ -22,6 +32,7 @@ Global
2232
GlobalSection(NestedProjects) = preSolution
2333
{1A33B6F9-9126-43D5-962B-6BA2DBE5B052} = {F881F2A5-6B1D-4E4F-A698-C3D5E760E509}
2434
{20915888-5AEA-4918-8DE4-FBE77EFCC758} = {F205434D-6BE3-414B-A17D-A12F8E78C58F}
35+
{790D531F-FFB9-4C8C-A861-C469CDF5DB9D} = {94A53025-23C4-4B9D-B015-B7CDBD1E2275}
2536
EndGlobalSection
2637
GlobalSection(ProjectConfigurationPlatforms) = postSolution
2738
{1A33B6F9-9126-43D5-962B-6BA2DBE5B052}.Debug|Any CPU.ActiveCfg = Debug|Any CPU

src/AStar.Dev.Admin.Api.Client.Sdk/AStar.Dev.Admin.Api.Client.Sdk.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
<PackageReference Include="AStar.Dev.Api.HealthChecks" Version="0.4.0"/>
4141
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions" Version="9.0.4"/>
4242
<PackageReference Include="AStar.Dev.Functional.Extensions" Version="0.2.0"/>
43-
<PackageReference Include="AStar.Dev.Logging.Extensions" Version="0.5.1" />
43+
<PackageReference Include="AStar.Dev.Logging.Extensions" Version="0.5.3"/>
4444
<PackageReference Include="AStar.Dev.Utilities" Version="1.6.1"/>
4545
<PackageReference Include="AStar.Dev.Technical.Debt.Reporting" Version="0.1.0"/>
4646
<PackageReference Include="Microsoft.Identity.Web" Version="3.8.4"/>

src/AStar.Dev.Admin.Api.Client.Sdk/AStar.Dev.Admin.Api.Client.Sdk.xml

Lines changed: 24 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/AStar.Dev.Admin.Api.Client.Sdk/AdminApi/AdminApiClient.cs

Lines changed: 40 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
using AStar.Dev.Api.HealthChecks;
55
using AStar.Dev.Functional.Extensions;
66
using AStar.Dev.Logging.Extensions;
7+
using AStar.Dev.Technical.Debt.Reporting;
8+
using AStar.Dev.Utilities;
79
using Microsoft.Identity.Web;
810

911
namespace AStar.Dev.Admin.Api.Client.Sdk.AdminApi;
@@ -16,7 +18,7 @@ public sealed class AdminApiClient(HttpClient httpClient, ITokenAcquisition toke
1618
private static readonly JsonSerializerOptions JsonSerializerOptions = new(JsonSerializerDefaults.Web);
1719

1820
/// <inheritdoc />
19-
public async Task<HealthStatusResponse> GetHealthAsync(CancellationToken cancellationToken = default)
21+
[Refactor(1,1,"Remove from the Interface")]public async Task<HealthStatusResponse> GetHealthAsync(CancellationToken cancellationToken = default)
2022
{
2123
logger.LogHealthCheckStart(Constants.ApiName);
2224

@@ -26,7 +28,7 @@ public async Task<HealthStatusResponse> GetHealthAsync(CancellationToken cancell
2628

2729
return response.IsSuccessStatusCode
2830
? (await JsonSerializer.DeserializeAsync<HealthStatusResponse>(await response.Content.ReadAsStreamAsync(cancellationToken), JsonSerializerOptions, cancellationToken))!
29-
: ReturnLoggedFailure(response);
31+
: logger.ReturnLoggedFailure(response, Constants.ApiName);
3032
}
3133
catch (HttpRequestException ex)
3234
{
@@ -38,55 +40,60 @@ public async Task<HealthStatusResponse> GetHealthAsync(CancellationToken cancell
3840

3941
/// <inheritdoc />
4042
public async Task<Result<string, HealthStatusResponse>> GetHealthCheckAsync(CancellationToken cancellationToken = new ())
41-
{
42-
logger.LogHealthCheckStart(Constants.ApiName);
43-
44-
try
45-
{
46-
var response = await httpClient.GetAsync("/health/ready", cancellationToken);
47-
48-
return response.IsSuccessStatusCode
49-
? (await JsonSerializer.DeserializeAsync<HealthStatusResponse>(await response.Content.ReadAsStreamAsync(cancellationToken), JsonSerializerOptions, cancellationToken))!
50-
: ReturnLoggedFailure(response);
51-
}
52-
catch (HttpRequestException ex)
53-
{
54-
logger.LogException(ex);
55-
56-
return new HealthStatusResponse { Status = $"Could not get a response from the {Constants.ApiName}." };
57-
}
58-
}
43+
=> await GetSafelyAsync<HealthStatusResponse>("/health/ready?version=1.0");
5944

6045
/// <summary>
6146
/// The GetSiteConfigurationAsync method will get the User Configuration.
6247
/// </summary>
6348
/// <returns>The Site Configuration - populated or empty</returns>
6449
public async Task<Result<string, IEnumerable<SiteConfiguration>>> GetSiteConfigurationAsync()
65-
{
66-
var token = await tokenAcquisitionService.GetAccessTokenForUserAsync(["api://2ca26585-5929-4aae-86a7-a00c3fc2d061/ToDoList.Write"]);
50+
=> await GetSafelyAsync<IEnumerable<SiteConfiguration>>("site-configurations?version=1.0");
6751

68-
httpClient.AddBearerToken(token);
69-
var response = await GetSafelyAsync<IEnumerable<SiteConfiguration>>("site-configurations?version=1.0");
52+
/// <summary>
53+
/// The GetModelsToIgnoreAsync method will get the models to ignore.
54+
/// </summary>
55+
/// <returns>A collection of 0 or more models to ignore</returns>
56+
public async Task<Result<string, IEnumerable<ModelToIgnore>>> GetModelsToIgnoreAsync()
57+
=> await GetSafelyAsync<IEnumerable<ModelToIgnore>>("models-to-ignore?version=1");
7058

71-
return response.IsSuccess
72-
? response
73-
: ReturnLoggedFailure("GetSiteConfiguration", response.Error);
74-
}
59+
/// <summary>
60+
/// The GetScrapeDirectoriesAsync method will get the Scrape Directories.
61+
/// </summary>
62+
/// <returns>The Scrape Directories - populated or empty</returns>
63+
public async Task<Result<string, ScrapeDirectories>> GetScrapeDirectoriesAsync()
64+
=> await GetSafelyAsync<ScrapeDirectories>("scrape-directories?version=1");
65+
66+
/// <summary>
67+
/// The GetSearchConfigurationAsync method will get the Search Configuration.
68+
/// </summary>
69+
/// <returns>The Search Configuration - populated or empty</returns>
70+
public async Task<Result<string, SearchConfiguration>> GetSearchConfigurationAsync()
71+
=> await GetSafelyAsync<SearchConfiguration>("search-configuration?version=1");
72+
73+
/// <summary>
74+
/// The GetTagsToIgnoreAsync method will get the Tags to Ignore.
75+
/// </summary>
76+
/// <returns>A collection of 0 or more Tags to Ignore</returns>
77+
public async Task<Result<string, IEnumerable<TagToIgnore>>> GetTagsToIgnoreAsync()
78+
=> await GetSafelyAsync<IEnumerable<TagToIgnore>>("search-configuration?version=1");
7579

7680
private async Task<Result<string, TResponse>> GetSafelyAsync<TResponse>( string uri)
7781
{
7882
try
7983
{
84+
logger.LogApiCallStart(Constants.ApiName, uri);
85+
var token = await tokenAcquisitionService.GetAccessTokenForUserAsync(["api://2ca26585-5929-4aae-86a7-a00c3fc2d061/ToDoList.Write"]);
86+
87+
_ = httpClient.AddBearerToken(token);
8088
var response = await httpClient.GetAsync(uri);
8189

82-
if(response.IsSuccessStatusCode)
90+
if (!response.IsSuccessStatusCode)
8391
{
84-
return (await response.Content.ReadFromJsonAsync<TResponse>())!;
92+
return logger.ReturnLoggedFailure<TResponse>( Constants.ApiName, uri, response.ReasonPhrase ?? response.StatusCode.ToString());
8593
}
8694

87-
logger.LogApiCallFailed("AStar.Dev.Admin.Api", uri, $"StatusCode: {response.StatusCode}, ResponseCode: {response.ReasonPhrase}");
88-
89-
return Result<string, TResponse>.Failure($"Call to {uri} failed with {(response.ReasonPhrase ?? response?.ReasonPhrase)}")!;
95+
var result = (await response.Content.ReadFromJsonAsync<TResponse>(Utilities.Constants.WebDeserialisationSettings))!;
96+
return logger.ReturnLoggedSuccess(result, Constants.ApiName, "uri");
9097
}
9198
catch(Exception ex)
9299
{
@@ -95,94 +102,4 @@ private async Task<Result<string, TResponse>> GetSafelyAsync<TResponse>( string
95102
return Result<string, TResponse>.Failure(ex.Message)!;
96103
}
97104
}
98-
99-
private HealthStatusResponse ReturnLoggedFailure(HttpResponseMessage response)
100-
{
101-
logger.LogHealthCheckFailure(Constants.ApiName, response.ReasonPhrase ?? "Failure reason not known");
102-
103-
return new() { Status = $"Health Check failed - {response.ReasonPhrase}." };
104-
}
105-
106-
private string ReturnLoggedFailure(string endpointName, string? reasonPhrase)
107-
{
108-
logger.LogApiCallFailed(Constants.ApiName, endpointName,reasonPhrase ?? "Failure reason not known");
109-
110-
return $"Call to {endpointName} failed - {reasonPhrase}.";
111-
}
112-
113-
//
114-
// /// <summary>
115-
// /// The GetModelsToIgnoreAsync method will get the models to ignore.
116-
// /// </summary>
117-
// /// <returns>A collection of 0 or more models to ignore</returns>
118-
// public async Task<IEnumerable<ModelToIgnore>> GetModelsToIgnoreAsync()
119-
// {
120-
// logger.LogInformation("Getting the models-to-ignore.");
121-
// var response = await httpClient.GetAsync("models-to-ignore?version=1");
122-
//
123-
// return response.IsSuccessStatusCode
124-
// ? (await response.Content.ReadAsStringAsync()).FromJson<IEnumerable<ModelToIgnore>>(Utilities.Constants
125-
// .WebDeserialisationSettings)
126-
// : [];
127-
// }
128-
//
129-
// /// <summary>
130-
// /// The GetScrapeDirectoriesAsync method will get the Scrape Directories.
131-
// /// </summary>
132-
// /// <returns>The Scrape Directories - populated or empty</returns>
133-
// public async Task<ScrapeDirectories> GetScrapeDirectoriesAsync()
134-
// {
135-
// logger.LogInformation("Getting the scrape-directories.");
136-
// var response = await httpClient.GetAsync("scrape-directories?version=1");
137-
//
138-
// return response.IsSuccessStatusCode
139-
// ? (await response.Content.ReadAsStringAsync()).FromJson<ScrapeDirectories>(Utilities.Constants
140-
// .WebDeserialisationSettings)
141-
// : new ScrapeDirectories();
142-
// }
143-
//
144-
// /// <summary>
145-
// /// The GetSearchConfigurationAsync method will get the Search Configuration.
146-
// /// </summary>
147-
// /// <returns>The Search Configuration - populated or empty</returns>
148-
// public async Task<SearchConfiguration> GetSearchConfigurationAsync()
149-
// {
150-
// logger.LogInformation("Getting the search-configuration.");
151-
// var response = await httpClient.GetAsync("search-configuration?version=1");
152-
//
153-
// return response.IsSuccessStatusCode
154-
// ? (await response.Content.ReadAsStringAsync()).FromJson<SearchConfiguration>(Utilities.Constants
155-
// .WebDeserialisationSettings)
156-
// : new SearchConfiguration();
157-
// }
158-
//
159-
// /// <summary>
160-
// /// The GetTagsToIgnoreAsync method will get the Tags to Ignore.
161-
// /// </summary>
162-
// /// <returns>A collection of 0 or more Tags to Ignore</returns>
163-
// public async Task<IEnumerable<TagToIgnore>> GetTagsToIgnoreAsync()
164-
// {
165-
// logger.LogInformation("Getting the Tags-to-ignore.");
166-
// var response = await httpClient.GetAsync("tags-to-ignore?version=1");
167-
//
168-
// return response.IsSuccessStatusCode
169-
// ? (await response.Content.ReadAsStringAsync()).FromJson<IEnumerable<TagToIgnore>>(Utilities.Constants
170-
// .WebDeserialisationSettings)
171-
// : [];
172-
// }
173-
//
174-
// /// <summary>
175-
// /// The GetUserConfigurationAsync method will get the User Configuration.
176-
// /// </summary>
177-
// /// <returns>The User Configuration - populated or empty</returns>
178-
// public async Task<UserConfiguration> GetUserConfigurationAsync()
179-
// {
180-
// logger.LogInformation("Getting the User Configuration.");
181-
// var response = await httpClient.GetAsync("user-configuration?version=1");
182-
//
183-
// return response.IsSuccessStatusCode
184-
// ? (await response.Content.ReadAsStringAsync()).FromJson<UserConfiguration>(Utilities.Constants
185-
// .WebDeserialisationSettings)
186-
// : new UserConfiguration();
187-
// }
188105
}

0 commit comments

Comments
 (0)