Skip to content

Commit

Permalink
Made shared Discovery Service (#37)
Browse files Browse the repository at this point in the history
* very basic http tests

* Discovery service now abstract class which encapsulates the shared logic. ALl discovery services have the same patterns, the only difference is where and how they fetch and store the data.

* Added correct package
  • Loading branch information
james-d12 authored Mar 1, 2025
1 parent 78cc0b0 commit 989c971
Show file tree
Hide file tree
Showing 11 changed files with 150 additions and 102 deletions.
29 changes: 27 additions & 2 deletions src/backend/CodeHub.Api/CodeHub.Api.http
Original file line number Diff line number Diff line change
@@ -1,6 +1,31 @@
@CodeHub.Api_HostAddress = http://localhost:5104
### Get list of all pipelines
GET {{BaseAddress}}/resources/pipelines/
Accept: application/json

> {%
client.test('Can Get List Of Resource Pipelines', function () {
client.assert(response.status == 200)
})
%}

### Get list of all pull requests
GET {{BaseAddress}}/resources/pull-requests/
Accept: application/json

> {%
client.test('Can Get List Of Resource Pull Requests', function () {
client.assert(response.status == 200)
})
%}

GET {{CodeHub.Api_HostAddress}}/weatherforecast/
### Get list of all repositories
GET {{BaseAddress}}/resources/repositories/
Accept: application/json

> {%
client.test('Can Get List Of Resource Repositories', function () {
client.assert(response.status == 200)
})
%}

###
2 changes: 1 addition & 1 deletion src/backend/CodeHub.Api/Jobs/DiscoveryHostedService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken)

foreach (var discoveryService in _discoveryServices)
{
await discoveryService.DiscoverAsync(stoppingToken);
await discoveryService.DiscoveryAsync(stoppingToken);
}

_logger.LogDebug("Worker finished running at: {time}", DateTimeOffset.Now);
Expand Down
5 changes: 5 additions & 0 deletions src/backend/CodeHub.Api/http-client.env.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"dev": {
"BaseAddress": "http://localhost:5104"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,32 @@

namespace CodeHub.Platform.Azure.Services;

internal sealed class AzureDiscoveryService : IDiscoveryService
internal sealed class AzureDiscoveryService : DiscoveryService
{
private readonly ILogger<AzureDiscoveryService> _logger;
private readonly IAzureService _azureService;

public AzureDiscoveryService(ILogger<AzureDiscoveryService> logger, IAzureService azureService)
public AzureDiscoveryService(
ILogger<AzureDiscoveryService> logger,
IAzureService azureService) : base(logger)
{
_logger = logger;
_azureService = azureService;
}

public async Task DiscoverAsync(CancellationToken cancellationToken)
public override string Platform => "Azure";

protected override async Task StartAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Discovering Azure resources...");
try
{
_logger.LogInformation("Discovering Azure Tenant resources...");
await _azureService.GetTenantsAsync(cancellationToken);
_logger.LogInformation("Discovering Azure Tenant resources...");
await _azureService.GetTenantsAsync(cancellationToken);

_logger.LogInformation("Discovering Azure Subscription resources.");
var subscriptions = await _azureService.GetSubscriptionsAsync(cancellationToken);
_logger.LogInformation("Discovering Azure Subscription resources.");
var subscriptions = await _azureService.GetSubscriptionsAsync(cancellationToken);

foreach (var subscription in subscriptions)
{
await _azureService.GetSubscriptionResourcesAsync(subscription.Id, cancellationToken);
}
}
catch (Exception exception)
foreach (var subscription in subscriptions)
{
_logger.LogError(exception, "Error occurred whilst trying to discover Azure resources.");
await _azureService.GetSubscriptionResourcesAsync(subscription.Id, cancellationToken);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

namespace CodeHub.Platform.AzureDevOps.Services;

internal sealed class AzureDevOpsDiscoveryService : IDiscoveryService
internal sealed class AzureDevOpsDiscoveryService : DiscoveryService
{
private readonly IAzureDevOpsService _azureDevOpsService;
private readonly ILogger<AzureDevOpsDiscoveryService> _logger;
Expand All @@ -15,55 +15,50 @@ internal sealed class AzureDevOpsDiscoveryService : IDiscoveryService
public AzureDevOpsDiscoveryService(
ILogger<AzureDevOpsDiscoveryService> logger,
IAzureDevOpsService azureDevOpsService,
IMemoryCache memoryCache)
IMemoryCache memoryCache) : base(logger)
{
_logger = logger;
_azureDevOpsService = azureDevOpsService;
_memoryCache = memoryCache;
}

public async Task DiscoverAsync(CancellationToken cancellationToken)
{
try
{
_logger.LogInformation("Discovering Azure DevOps team resources...");
var teams = await _azureDevOpsService.GetTeamsAsync(cancellationToken);
public override string Platform => "Azure DevOps";

_logger.LogInformation("Discovering Azure DevOps project resources...");
var projects = await _azureDevOpsService.GetProjectsAsync(cancellationToken);
protected override async Task StartAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Discovering Azure DevOps team resources...");
var teams = await _azureDevOpsService.GetTeamsAsync(cancellationToken);

var pipelines = new List<AzureDevOpsPipeline>();
var repositories = new List<AzureDevOpsRepository>();
var pullRequests = new List<AzureDevOpsPullRequest>();
_logger.LogInformation("Discovering Azure DevOps project resources...");
var projects = await _azureDevOpsService.GetProjectsAsync(cancellationToken);

foreach (var project in projects)
{
_logger.LogInformation("Discovering Azure DevOps Repository resources for {ProjectName}", project.Name);
var projectRepositories =
await _azureDevOpsService.GetRepositoriesAsync(project.Id, cancellationToken);
repositories.AddRange(projectRepositories);
var pipelines = new List<AzureDevOpsPipeline>();
var repositories = new List<AzureDevOpsRepository>();
var pullRequests = new List<AzureDevOpsPullRequest>();

_logger.LogInformation("Discovering Azure DevOps Pipeline resources for {ProjectName}", project.Name);
var projectPipelines = await _azureDevOpsService.GetPipelinesAsync(project.Id, cancellationToken);
pipelines.AddRange(projectPipelines);
foreach (var project in projects)
{
_logger.LogInformation("Discovering Azure DevOps Repository resources for {ProjectName}", project.Name);
var projectRepositories =
await _azureDevOpsService.GetRepositoriesAsync(project.Id, cancellationToken);
repositories.AddRange(projectRepositories);

_logger.LogInformation("Discovering Azure DevOps Pipeline resources for {ProjectName}", project.Name);
var projectPullRequests = await _azureDevOpsService.GetPullRequestsAsync(project.Id, cancellationToken);
pullRequests.AddRange(projectPullRequests);
_logger.LogInformation("Discovering Azure DevOps Pipeline resources for {ProjectName}", project.Name);
var projectPipelines = await _azureDevOpsService.GetPipelinesAsync(project.Id, cancellationToken);
pipelines.AddRange(projectPipelines);

//_logger.LogInformation("Discovering Azure DevOps Work Item resources for {ProjectName}", project.Name);
//await _azureDevOpsService.GetWorkItemsAsync(project.Name, cancellationToken);
}
_logger.LogInformation("Discovering Azure DevOps Pipeline resources for {ProjectName}", project.Name);
var projectPullRequests = await _azureDevOpsService.GetPullRequestsAsync(project.Id, cancellationToken);
pullRequests.AddRange(projectPullRequests);

_memoryCache.Set(CacheConstants.ProjectCacheKey, projects);
_memoryCache.Set(CacheConstants.TeamCacheKey, teams);
_memoryCache.Set(CacheConstants.PipelineCacheKey, pipelines);
_memoryCache.Set(CacheConstants.RepositoryCacheKey, repositories);
_memoryCache.Set(CacheConstants.PullRequestCacheKey, pullRequests);
}
catch (Exception exception)
{
_logger.LogError(exception, "Error occurred whilst trying to discover the latest Azure DevOps resources.");
//_logger.LogInformation("Discovering Azure DevOps Work Item resources for {ProjectName}", project.Name);
//await _azureDevOpsService.GetWorkItemsAsync(project.Name, cancellationToken);
}

_memoryCache.Set(CacheConstants.ProjectCacheKey, projects);
_memoryCache.Set(CacheConstants.TeamCacheKey, teams);
_memoryCache.Set(CacheConstants.PipelineCacheKey, pipelines);
_memoryCache.Set(CacheConstants.RepositoryCacheKey, repositories);
_memoryCache.Set(CacheConstants.PullRequestCacheKey, pullRequests);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,33 +5,25 @@

namespace CodeHub.Platform.GitHub.Services;

internal sealed class GitHubDiscoveryService : IDiscoveryService
internal sealed class GitHubDiscoveryService : DiscoveryService
{
private readonly ILogger<GitHubDiscoveryService> _logger;
private readonly IGitHubService _gitHubService;
private readonly IMemoryCache _memoryCache;

public GitHubDiscoveryService(ILogger<GitHubDiscoveryService> logger, IGitHubService gitHubService,
IMemoryCache memoryCache)
public GitHubDiscoveryService(
ILogger<GitHubDiscoveryService> logger,
IGitHubService gitHubService,
IMemoryCache memoryCache) : base(logger)
{
_logger = logger;
_gitHubService = gitHubService;
_memoryCache = memoryCache;
}

public async Task DiscoverAsync(CancellationToken cancellationToken)
{
try
{
_logger.LogInformation("Discovering GitHub repositories...");

var repositories = await _gitHubService.GetRepositoriesAsync(cancellationToken);
public override string Platform => "GitHub";

_memoryCache.Set(CacheConstants.RepositoryCacheKey, repositories);
}
catch (Exception exception)
{
_logger.LogError(exception, "Error occurred whilst trying to discover the latest GitHub resources.");
}
protected override async Task StartAsync(CancellationToken cancellationToken)
{
var repositories = await _gitHubService.GetRepositoriesAsync(cancellationToken);
_memoryCache.Set(CacheConstants.RepositoryCacheKey, repositories);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,48 +7,40 @@

namespace CodeHub.Platform.GitLab.Services;

internal sealed class GitLabDiscoveryService : IDiscoveryService
internal sealed class GitLabDiscoveryService : DiscoveryService
{
private readonly ILogger<GitLabDiscoveryService> _logger;
private readonly IGitLabService _gitLabService;
private readonly IMemoryCache _memoryCache;

public GitLabDiscoveryService(
ILogger<GitLabDiscoveryService> logger,
IGitLabService gitLabService,
IMemoryCache memoryCache)
IMemoryCache memoryCache) : base(logger)
{
_logger = logger;
_gitLabService = gitLabService;
_memoryCache = memoryCache;
}

public Task DiscoverAsync(CancellationToken cancellationToken)
{
try
{
var projects = _gitLabService.GetProjects();
public override string Platform => "GitLab";

var repositories = projects.Select(p => p.MapToGitLabRepository()).ToList();
var pullRequests = _gitLabService.GetPullRequests();

var pipelines = new List<GitLabPipeline>();
foreach (var project in projects)
{
var projectPipelines = _gitLabService.GetPipelines(project);
pipelines.AddRange(projectPipelines);
}
protected override Task StartAsync(CancellationToken cancellationToken)
{
var projects = _gitLabService.GetProjects();

_memoryCache.Set(CacheConstants.PipelineCacheKey, pipelines);
_memoryCache.Set(CacheConstants.PullRequestCacheKey, pullRequests);
_memoryCache.Set(CacheConstants.RepositoryCacheKey, repositories);
var repositories = projects.Select(p => p.MapToGitLabRepository()).ToList();
var pullRequests = _gitLabService.GetPullRequests();

return Task.FromResult(true);
}
catch (Exception exception)
var pipelines = new List<GitLabPipeline>();
foreach (var project in projects)
{
_logger.LogError(exception, "Error occurred whilst trying to discover the latest GitHub resources.");
return Task.FromResult(false);
var projectPipelines = _gitLabService.GetPipelines(project);
pipelines.AddRange(projectPipelines);
}

_memoryCache.Set(CacheConstants.PipelineCacheKey, pipelines);
_memoryCache.Set(CacheConstants.PullRequestCacheKey, pullRequests);
_memoryCache.Set(CacheConstants.RepositoryCacheKey, repositories);

return Task.FromResult(true);
}
}
1 change: 1 addition & 0 deletions src/backend/CodeHub.Shared/CodeHub.Shared.csproj
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration.Binder"/>
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions"/>
</ItemGroup>
</Project>
40 changes: 40 additions & 0 deletions src/backend/CodeHub.Shared/Services/DiscoveryService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using System.Diagnostics;
using Microsoft.Extensions.Logging;

namespace CodeHub.Shared.Services;

public abstract class DiscoveryService : IDiscoveryService
{
private readonly ILogger<DiscoveryService> _logger;

protected DiscoveryService(ILogger<DiscoveryService> logger)
{
_logger = logger;
}

public virtual string Platform => string.Empty;

public async Task DiscoveryAsync(CancellationToken cancellationToken)
{
try
{
_logger.LogInformation("{Platform} Discovery Service started.", Platform);
var stopWatch = new Stopwatch();
stopWatch.Start();

await StartAsync(cancellationToken);

stopWatch.Stop();
var milliseconds = stopWatch.Elapsed.TotalMilliseconds;

_logger.LogInformation("{Platform} Discovery Service took: {Milliseconds} ms", Platform, milliseconds);
}
catch (Exception exception)
{
_logger.LogError(exception, $"Error occurred whilst trying to discover the latest {Platform} resources.");
throw;
}
}

protected abstract Task StartAsync(CancellationToken cancellationToken);
}
3 changes: 2 additions & 1 deletion src/backend/CodeHub.Shared/Services/IDiscoveryService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@

public interface IDiscoveryService
{
Task DiscoverAsync(CancellationToken cancellationToken);
string Platform { get; }
Task DiscoveryAsync(CancellationToken cancellationToken);
}
1 change: 1 addition & 0 deletions src/backend/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<PackageVersion Include="Microsoft.Extensions.Configuration" Version="9.0.2"/>
<PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.2"/>
<PackageVersion Include="Microsoft.Extensions.Logging" Version="9.0.2"/>
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.2"/>
<PackageVersion Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="9.0.2"/>
<PackageVersion Include="Microsoft.Extensions.Caching.Memory" Version="9.0.2"/>
<PackageVersion Include="Microsoft.Extensions.Configuration.Abstractions" Version="9.0.2"/>
Expand Down

0 comments on commit 989c971

Please sign in to comment.