Skip to content

Commit 375cfae

Browse files
committed
get codeflows wip
1 parent e6fa94b commit 375cfae

File tree

1 file changed

+77
-30
lines changed

1 file changed

+77
-30
lines changed

src/ProductConstructionService/ProductConstructionService.Common/CodeflowHistoryManager.cs

Lines changed: 77 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ namespace ProductConstructionService.Common;
88

99
public interface ICodeflowHistoryManager
1010
{
11-
void RefreshCodeflowHistory(string repo, string branch);
1211
Task<CodeflowHistoryResult> GetCodeflowHistory(Guid? subscriptionId);
1312
Task<CodeflowHistory?> FetchLatestCodeflowHistoryAsync(Guid? subscriptionId);
1413
}
@@ -32,7 +31,7 @@ public record CodeflowGraphCommit(
3231
DateTimeOffset CommitDate,
3332
string Author,
3433
string Description,
35-
List<CodeflowGraphCommit> IncomingCodeflows);
34+
CodeflowGraphCommit? IncomingCodeflow);
3635

3736
public class CodeflowHistoryManager : ICodeflowHistoryManager
3837
{
@@ -47,60 +46,76 @@ public CodeflowHistoryManager(
4746
_remoteFactory = remoteFactory;
4847
}
4948

50-
public async void RefreshCodeflowHistory(string repo, string branch)
49+
public async Task<CodeflowHistory?> GetCachedCodeflowHistoryAsync(Subscription subscription)
5150
{
52-
//0. Fetch latest commit from local git repo if exists
53-
//1. Fetch new parts from GitHub API
54-
//2. Fetch old parts from disk
55-
//3. Stitch them together
56-
//4. Write contents to cache
57-
await Task.CompletedTask;
51+
string id = subscription.Id.ToString()!;
52+
var cache = _redisCacheFactory.Create<CodeflowGraphCommit>(id);
53+
return await cache.TryGetStateAsync();
5854
}
5955

60-
public async Task<CodeflowHistoryResult> GetCodeflowHistory(Subscription subscription, bool fetchLatest)
56+
public async Task<CodeflowHistory?> GetCachedCodeflowHistoryAsync(
57+
Subscription subscription,
58+
string commitSha,
59+
int commitFetchCount)
6160
{
62-
//todo: implement this method
63-
}
64-
65-
public async Task<CodeflowHistory?> GetCachedCodeflowHistoryAsync(Guid? subscriptionId)
66-
{
67-
string id = subscriptionId.ToString()!;
68-
69-
var cache = _redisCacheFactory.Create<CodeflowHistory>(id);
70-
71-
var cachedHistory = await cache.TryGetStateAsync();
72-
return cachedHistory;
61+
// todo this method returns the codeflow history starting from commitSha.
62+
// It only reads from redis and never modifies the cache
7363
}
74-
75-
76-
public async Task<CodeflowHistory?> FetchLatestCodeflowHistoryAsync(Subscription subscription)
64+
public async Task<CodeflowHistory?> FetchLatestCodeflowHistoryAsync(
65+
Subscription subscription,
66+
int commitFetchCount)
7767
{
68+
//todo acquire lock on the redis Zset here
7869
var cachedCommits = await GetCachedCodeflowHistoryAsync(subscription.Id);
7970

8071
var remote = await _remoteFactory.CreateRemoteAsync(subscription.TargetRepository);
8172

73+
latestCachedCommitSha = cachedCommits?.Commits.FirstOrDefault()?.CommitSha;
74+
8275
var latestCommits = await remote.FetchNewerRepoCommitsAsync(
8376
subscription.TargetBranch,
8477
subscription.TargetBranch,
85-
cachedCommits?.Commits.FirstOrDefault()?.CommitSha,
86-
500);
78+
latestCachedCommitSha,
79+
commitFetchCount);
80+
81+
if (latestCommits.Count == commitFetchCount &&
82+
latestCommits.LastOrDefault()?.CommitSha != latestCachedCommitSha)
83+
{
84+
// we have a gap in the history - throw away cache because we can't form a continuous history
85+
cachedCommits = [];
86+
}
87+
else
88+
{
89+
latestCommits = latestCommits
90+
.Where(commit => commit.CommitSha != latestCachedCommitSha)
91+
.ToList();
92+
}
8793

8894
var latestCachedCodeflow = cachedCommits?.Commits.FirstOrDefault(
89-
x => x.IncomingCodeflows.Count > 0);
95+
commit => commit.IncomingCodeflows != null);
9096

9197
var codeFlows = await FetchLatestIncomingCodeflows(
9298
subscription.TargetRepository,
9399
subscription.TargetBranch,
94-
latestCachedCodeflow,
100+
latestCommits,
95101
remote);
96102

103+
foreach (var commit in latestCommits)
104+
{
105+
string? sourceCommitSha = codeflows.GetCodeflowSourceCommit(commit.CommitSha);
106+
commit.IncomingCodeflow = sourceCommitSha;
107+
}
108+
109+
// todo cache fresh commits and release lock on the Zset
110+
await CacheCommits(latestCommits);
111+
97112
return null;
98113
}
99114

100-
private async Task<List<CodeflowGraphCommit>> FetchLatestIncomingCodeflows(
115+
private async Task<GraphCodeflows> FetchLatestIncomingCodeflows(
101116
string repo,
102117
string branch,
103-
CodeflowGraphCommit? latestCachedCommit,
118+
List<CodeflowGraphCommit> latestCommits,
104119
IRemote? remote)
105120
{
106121
if (remote == null)
@@ -113,4 +128,36 @@ private async Task<List<CodeflowGraphCommit>> FetchLatestIncomingCodeflows(
113128
//todo: implement this method
114129
return null;
115130
}
131+
132+
private async Task CacheCommits(List<CodeflowGraphCommit> commits)
133+
{
134+
// Cache the commits as part of the subscription's redis ZSet of CodeflowGraphCommit objects
135+
if (commits.Count == 0)
136+
{
137+
return;
138+
}
139+
var cache = _redisCacheFactory.Create<CodeflowGraphCommit>(subscription.Id.ToString()!);
140+
await cache.SetStateAsync(new CodeflowHistory(commits, codeflows));
141+
142+
}
143+
}
144+
145+
class GraphCodeflows
146+
{
147+
// keys: target repo commits that have incoing codeflows
148+
// values: commit SHAs of those codeflows in the source repo
149+
public Dictionary<string, string> Codeflows { get; set; } = [];
150+
151+
/// <summary>
152+
/// Returns the source commit of the codeflow if targetCommitSha is a target commit of a codeflow.
153+
/// Otherwise, return null
154+
/// </summary>
155+
public string? GetCodeflowSourceCommit(string targetCommitSha)
156+
{
157+
if (Codeflows.TryGetValue(targetCommitSha, out var sourceCommit))
158+
{
159+
return sourceCommit;
160+
}
161+
return null;
162+
}
116163
}

0 commit comments

Comments
 (0)