diff --git a/SSW.Rules.AzFuncs/Domain/LatestRules.cs b/SSW.Rules.AzFuncs/Domain/LatestRules.cs deleted file mode 100644 index 4fe874e..0000000 --- a/SSW.Rules.AzFuncs/Domain/LatestRules.cs +++ /dev/null @@ -1,16 +0,0 @@ -using AzureGems.Repository.Abstractions; - -namespace SSW.Rules.AzFuncs.Domain; - -public class LatestRules : BaseEntity -{ - public string CommitHash { get; set; } - public string RuleUri { get; set; } - public string RuleGuid { get; set; } - public string RuleName { get; set; } - public DateTime CreatedAt { get; set; } - public DateTime UpdatedAt { get; set; } - public string CreatedBy { get; set; } - public string UpdatedBy { get; set; } - public string GitHubUsername { get; set; } -} diff --git a/SSW.Rules.AzFuncs/Functions/Widget/GetLatestRules.cs b/SSW.Rules.AzFuncs/Functions/Widget/GetLatestRules.cs deleted file mode 100644 index 3d75917..0000000 --- a/SSW.Rules.AzFuncs/Functions/Widget/GetLatestRules.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System.Net; -using System.Web; -using Microsoft.Azure.Functions.Worker; -using Microsoft.Azure.Functions.Worker.Http; -using Microsoft.Extensions.Logging; -using SSW.Rules.AzFuncs.helpers; -using SSW.Rules.AzFuncs.Persistence; - -namespace SSW.Rules.AzFuncs.Functions.Widget; - -public class GetLatestRules(ILoggerFactory loggerFactory, RulesDbContext context) -{ - private readonly ILogger _logger = loggerFactory.CreateLogger(); - - [Function("GetLatestRules")] - public async Task Run( - [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] - HttpRequestData req, - FunctionContext executionContext) - { - var query = HttpUtility.ParseQueryString(req.Url.Query); - var skip = int.Parse(query["skip"] ?? "0"); - var take = int.Parse(query["take"] ?? "10"); - var githubUsername = query["githubUsername"]?.Trim('\"') ?? String.Empty; - - _logger.LogInformation($"Fetching latest rules, Skip: {skip}, Take: {take}, GitHubUsername: {githubUsername}"); - - var rules = await context.LatestRules.GetAll(); - var filteredRules = rules - .Where(r => string.IsNullOrEmpty(githubUsername) || r.GitHubUsername == githubUsername || - r.CreatedBy == githubUsername || r.UpdatedBy == githubUsername) - .GroupBy(r => r.RuleGuid) - .Select(group => group.First()) - .DistinctBy(r => r.RuleGuid) - .OrderByDescending(r => r.UpdatedAt) - .Skip(skip) - .Take(take); - - var filteredRulesList = filteredRules.ToList(); - return filteredRulesList.Count == 0 - ? req.CreateJsonErrorResponse(HttpStatusCode.NotFound, "Not Found") - : req.CreateJsonResponse(filteredRules); - } -} diff --git a/SSW.Rules.AzFuncs/Functions/Widget/UpdateLatestRules.cs b/SSW.Rules.AzFuncs/Functions/Widget/UpdateLatestRules.cs deleted file mode 100644 index 0806bb7..0000000 --- a/SSW.Rules.AzFuncs/Functions/Widget/UpdateLatestRules.cs +++ /dev/null @@ -1,147 +0,0 @@ -using System.Net; -using Microsoft.Azure.Functions.Worker; -using Microsoft.Azure.Functions.Worker.Http; -using Microsoft.Extensions.Logging; -using Octokit; -using SSW.Rules.AzFuncs.Domain; -using SSW.Rules.AzFuncs.helpers; -using SSW.Rules.AzFuncs.Persistence; - -namespace SSW.Rules.AzFuncs.Functions.Widget; - -public class UpdateLatestRules(ILoggerFactory loggerFactory, IGitHubClient gitHubClient, RulesDbContext context) -{ - private readonly ILogger _logger = loggerFactory.CreateLogger(); - - [Function("UpdateLatestRules")] - public async Task Run( - [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] - HttpRequestData req, - FunctionContext executionContext) - { - _logger.LogInformation("Processing UpdateLatestRules request."); - try - { - // TODO: Get these from the ENV - const string repositoryOwner = "SSWConsulting"; - const string repositoryName = "SSW.Rules.Content"; - var request = new PullRequestRequest - { - State = ItemStateFilter.Closed, - }; - var apiOptions = new ApiOptions - { - PageSize = 50, - PageCount = 1, - StartPage = 1 - }; - - var pullRequests = - await gitHubClient.PullRequest.GetAllForRepository(repositoryOwner, repositoryName, request, - apiOptions); - - if (pullRequests == null || !pullRequests.Any()) - { - throw new Exception("No Pull Requests found"); - } - - var syncHistoryHash = await context.SyncHistory.GetAll(); - var existingCommitHashes = new HashSet(syncHistoryHash.Select(sh => sh.CommitHash)); - HttpClient httpClient = new HttpClient(); - var newRules = new List(); - var updatedCount = 0; - - - foreach (var pr in pullRequests) - { - _logger.LogInformation($"Scanning PR {pr.Number}"); - if (existingCommitHashes.Contains(pr.MergeCommitSha)) break; - if (!pr.Merged) continue; - - var files = await gitHubClient.PullRequest.Files(repositoryOwner, repositoryName, pr.Number); - if (files.Count > 100) // Skips big PRs as these will fail https://github.com/SSWConsulting/SSW.Rules/issues/1367 - { - _logger.LogInformation($"Skipping PR {pr.Number} because there are too many files changed"); - continue; - }; - - foreach (var file in files) - { - if (!file.FileName.Contains("rule.md")) continue; - - var response = await httpClient.GetAsync(file.RawUrl); - if (!response.IsSuccessStatusCode) continue; - - var fileContent = await response.Content.ReadAsStringAsync(); - var frontMatter = Utils.ParseFrontMatter(fileContent); - - if (frontMatter is null) continue; - - var ruleHistoryCache = await context.RuleHistoryCache.Query(rhc => - rhc.Where(w => w.MarkdownFilePath == file.FileName)); - var foundRule = ruleHistoryCache.FirstOrDefault(); - - var searchLatest = - await context.LatestRules.Query(q => q.Where(w => w.RuleGuid == frontMatter.Guid)); - var latestFound = searchLatest.FirstOrDefault(); - - if (latestFound is not null) - { - UpdateLatestRule(latestFound, pr, frontMatter); - updatedCount++; - continue; - } - - var rule = CreateLatestRule(pr, frontMatter, foundRule); - newRules.Add(rule); - updatedCount++; - } - } - - foreach (var rule in newRules) - { - await context.LatestRules.Add(rule); - } - - _logger.LogInformation($"Updated Latest rules with {updatedCount} new entries."); - - return req.CreateJsonResponse(new - { message = $"Latest rules updated successfully with {updatedCount} new entries." }); - } - catch (Exception ex) - { - _logger.LogError($"Something went wrong: {ex.Message}"); - return req.CreateJsonErrorResponse(HttpStatusCode.BadRequest, ex.Message); - } - } - - private void UpdateLatestRule(LatestRules latestRule, PullRequest pr, FrontMatter frontMatter) - { - latestRule.CommitHash = pr.MergeCommitSha; - latestRule.RuleUri = frontMatter.Uri; - latestRule.RuleName = frontMatter.Title; - latestRule.UpdatedAt = pr.UpdatedAt.UtcDateTime; - latestRule.UpdatedBy = pr.User.Login; - latestRule.GitHubUsername = pr.User.Login; - - context.LatestRules.Update(latestRule); - } - - private static LatestRules CreateLatestRule(PullRequest pr, FrontMatter frontMatter, RuleHistoryCache? foundRule) - { - var rule = new LatestRules - { - CommitHash = pr.MergeCommitSha, - RuleGuid = frontMatter.Guid, - RuleUri = frontMatter.Uri, - RuleName = frontMatter.Title, - CreatedAt = foundRule?.CreatedAtDateTime ?? frontMatter.Created, - UpdatedAt = pr.UpdatedAt.UtcDateTime, - CreatedBy = foundRule?.CreatedByDisplayName ?? pr.User.Location, - UpdatedBy = foundRule?.ChangedByDisplayName ?? pr.User.Login, - GitHubUsername = pr.User.Login - }; - - return rule; - } -} \ No newline at end of file diff --git a/SSW.Rules.AzFuncs/Persistence/RulesDbContext.cs b/SSW.Rules.AzFuncs/Persistence/RulesDbContext.cs index db4a390..bea36db 100644 --- a/SSW.Rules.AzFuncs/Persistence/RulesDbContext.cs +++ b/SSW.Rules.AzFuncs/Persistence/RulesDbContext.cs @@ -11,5 +11,4 @@ public class RulesDbContext : CosmosContext public IRepository Users { get; set; } public IRepository SyncHistory { get; set; } public IRepository RuleHistoryCache { get; set; } - public IRepository LatestRules { get; set; } } \ No newline at end of file diff --git a/SSW.Rules.AzFuncs/Program.cs b/SSW.Rules.AzFuncs/Program.cs index 1ac67a5..532e435 100644 --- a/SSW.Rules.AzFuncs/Program.cs +++ b/SSW.Rules.AzFuncs/Program.cs @@ -46,12 +46,10 @@ c.AddContainer(containerId: nameof(User), partitionKeyPath: "/id"); c.AddContainer(containerId: nameof(SyncHistory), partitionKeyPath: "/id"); c.AddContainer(containerId: nameof(RuleHistoryCache), partitionKeyPath: "/id"); - c.AddContainer(containerId: nameof(LatestRules), partitionKeyPath: "/id"); }); }); services.AddCosmosContext(); }) .Build(); - host.Run(); \ No newline at end of file diff --git a/SSW.Rules.AzFuncs/docs/Functions/Functions.http b/SSW.Rules.AzFuncs/docs/Functions/Functions.http index a501e67..b2143ea 100644 --- a/SSW.Rules.AzFuncs/docs/Functions/Functions.http +++ b/SSW.Rules.AzFuncs/docs/Functions/Functions.http @@ -16,20 +16,6 @@ GET {{BaseApiUrl}}/GenerateHistoryFileFunction # History - SyncCommitHash GET {{BaseApiUrl}}/GetHistorySyncCommitHash -### -# Widget - Get LatestRules (with GitHub) -@skip = 0 -@take = 10 -@githubUsername = "BrookJeynes" - -GET {{BaseApiUrl}}/GetLatestRules?skip={{skip}}&take={{take}}&githubUsername={{githubUsername}} -# Content-Type: application/json - -### -# Widget - Get LatestRules (No GitHub) - -GET {{BaseApiUrl}}/GetLatestRules?skip={{skip}}&take={{take}} - ### # Reactions - ReactFunction POST {{BaseApiUrl}}/ReactFunction diff --git a/docs/Functions/Functions.http b/docs/Functions/Functions.http deleted file mode 100644 index 038aa7f..0000000 --- a/docs/Functions/Functions.http +++ /dev/null @@ -1,38 +0,0 @@ -@BaseApiUrl = http://localhost:7071/api - -# Health -GET {{BaseApiUrl}}/HealthCheckFunction -Content-Type: application/json - -### -# History - Generate -GET {{BaseApiUrl}}/GenerateHistoryFileFunction -Content-Type: application/json - -### -# History - SyncCommitHash -GET {{BaseApiUrl}}/GetHistorySyncCommitHash -Content-Type: application/json - - -### -# Widget - Get LatestRules (with GitHub) -@skip = 0 -@take = 10 -@githubUsername = "BrookJeynes" - -GET {{BaseApiUrl}}/GetLatestRules?skip={{skip}}&take={{take}}&githubUsername={{githubUsername}} -Content-Type: application/json - -### -# Widget - Get LatestRules (No GitHub) - -GET {{BaseApiUrl}}/GetLatestRules?skip={{skip}}&take={{take}} -Content-Type: application/json - - -### -# Widget - Update LatestRules - -POST {{BaseApiUrl}}/UpdateLatestRules -Content-Type: application/json \ No newline at end of file