Forge
csharp3407750f
1using System.Text.Json;
2using AgentForge.Data;
3using AgentForge.Data.Entities;
4using AgentForge.Plugin.Ci.Ir;
5using Microsoft.EntityFrameworkCore;
6
7namespace AgentForge.Plugin.Ci.Data;
8
9public sealed class ForgeCiRunStore(ForgeDbContext db)
10{
11 public ForgeCiPipelineRunRecord? GetRun(string repoId, string runId)
12 {
13 var entity = db.CiPipelineRuns.AsNoTracking()
14 .FirstOrDefault(r => r.RepoId == repoId && r.Id == runId);
15 return entity is null ? null : ToRunRecord(entity);
16 }
17
18 public IReadOnlyList<ForgeCiPipelineRunRecord> ListRuns(string repoId, int limit = 20) =>
19 db.CiPipelineRuns.AsNoTracking()
20 .Where(r => r.RepoId == repoId)
21 .OrderByDescending(r => r.CreatedAt)
22 .Take(limit)
23 .AsEnumerable()
24 .Select(ToRunRecord)
25 .ToList();
26
27 public IReadOnlyList<ForgeCiStepRunRecord> ListSteps(string runId) =>
28 db.CiStepRuns.AsNoTracking()
29 .Where(s => s.RunId == runId)
30 .OrderBy(s => s.OrderIndex)
31 .Select(s => ToStepRecord(s))
32 .ToList();
33
34 public ForgeCiPipelineRunRecord CreateQueuedRun(
35 string repoId,
36 string definitionName,
37 string gitRef,
38 string commit,
39 int? mrNumber,
40 IReadOnlyList<ForgeCiPlanStep> plan,
41 string queuedBy)
42 {
43 var now = DateTimeOffset.UtcNow;
44 var runId = Guid.NewGuid().ToString("N");
45 var planJson = JsonSerializer.Serialize(plan, ForgeCiDocument.JsonOptions);
46
47 var run = new ForgeCiPipelineRunEntity
48 {
49 Id = runId,
50 RepoId = repoId,
51 DefinitionName = definitionName,
52 Ref = gitRef,
53 Commit = commit,
54 MrNumber = mrNumber,
55 Status = ForgeCiRunStatusSlugs.Pending,
56 PlanJson = planJson,
57 QueuedBy = queuedBy,
58 CreatedAt = now,
59 UpdatedAt = now,
60 };
61
62 var steps = new List<ForgeCiStepRunEntity>(plan.Count);
63 for (var i = 0; i < plan.Count; i++)
64 {
65 var step = plan[i];
66 steps.Add(new ForgeCiStepRunEntity
67 {
68 Id = Guid.NewGuid().ToString("N"),
69 RunId = runId,
70 NodeId = step.NodeId,
71 TaskId = step.TaskId,
72 DisplayName = step.DisplayName,
73 OrderIndex = i,
74 Status = ForgeCiRunStatusSlugs.Pending,
75 });
76 }
77
78 db.CiPipelineRuns.Add(run);
79 db.CiStepRuns.AddRange(steps);
80 db.SaveChanges();
81 return ToRunRecord(run);
82 }
83
84 public void MarkRunRunning(string runId)
85 {
86 var run = db.CiPipelineRuns.First(r => r.Id == runId);
87 var now = DateTimeOffset.UtcNow;
88 run.Status = ForgeCiRunStatusSlugs.Running;
89 run.StartedAt ??= now;
90 run.UpdatedAt = now;
91 db.SaveChanges();
92 }
93
94 public void MarkRunFinished(string runId, string status)
95 {
96 var run = db.CiPipelineRuns.First(r => r.Id == runId);
97 var now = DateTimeOffset.UtcNow;
98 run.Status = status;
99 run.FinishedAt = now;
100 run.UpdatedAt = now;
101 db.SaveChanges();
102 }
103
104 public void MarkStepRunning(string stepId)
105 {
106 var step = db.CiStepRuns.First(s => s.Id == stepId);
107 var now = DateTimeOffset.UtcNow;
108 step.Status = ForgeCiRunStatusSlugs.Running;
109 step.StartedAt = now;
110 db.SaveChanges();
111 }
112
113 public void MarkStepFinished(string stepId, string status, string logText)
114 {
115 var step = db.CiStepRuns.First(s => s.Id == stepId);
116 step.Status = status;
117 step.LogText = logText;
118 step.FinishedAt = DateTimeOffset.UtcNow;
119 db.SaveChanges();
120
121 var run = db.CiPipelineRuns.First(r => r.Id == step.RunId);
122 run.UpdatedAt = DateTimeOffset.UtcNow;
123 db.SaveChanges();
124 }
125
126 public IReadOnlyList<ForgeCiPlanStep> LoadPlan(string runId)
127 {
128 var planJson = db.CiPipelineRuns.AsNoTracking().First(r => r.Id == runId).PlanJson;
129 return JsonSerializer.Deserialize<List<ForgeCiPlanStep>>(planJson, ForgeCiDocument.JsonOptions) ?? [];
130 }
131
132 private static ForgeCiPipelineRunRecord ToRunRecord(ForgeCiPipelineRunEntity entity) =>
133 new(
134 entity.Id,
135 entity.RepoId,
136 entity.DefinitionName,
137 entity.Ref,
138 entity.Commit,
139 entity.MrNumber,
140 entity.Status,
141 entity.QueuedBy,
142 entity.CreatedAt,
143 entity.UpdatedAt,
144 entity.StartedAt,
145 entity.FinishedAt);
146
147 private static ForgeCiStepRunRecord ToStepRecord(ForgeCiStepRunEntity entity) =>
148 new(
149 entity.Id,
150 entity.RunId,
151 entity.NodeId,
152 entity.TaskId,
153 entity.DisplayName,
154 entity.OrderIndex,
155 entity.Status,
156 entity.LogText,
157 entity.StartedAt,
158 entity.FinishedAt);
159}
160
View only · write via MCP/CIDE