feat: Implement approvals workflow and notifications integration
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled

- Added approvals orchestration with persistence and workflow scaffolding.
- Integrated notifications insights and staged resume hooks.
- Introduced approval coordinator and policy notification bridge with unit tests.
- Added approval decision API with resume requeue and persisted plan snapshots.
- Documented the Excitor consensus API beta and provided JSON sample payload.
- Created analyzers to flag usage of deprecated merge service APIs.
- Implemented logging for artifact uploads and approval decision service.
- Added tests for PackRunApprovalDecisionService and related components.
This commit is contained in:
master
2025-11-06 08:48:13 +02:00
parent 21a2759412
commit dd217b4546
98 changed files with 3883 additions and 2381 deletions

View File

@@ -1,4 +1,5 @@
using StellaOps.TaskRunner.Core.Execution;
using System.Text.Json.Nodes;
using StellaOps.TaskRunner.Core.Execution;
using StellaOps.TaskRunner.Core.Planning;
using StellaOps.TaskRunner.Infrastructure.Execution;
@@ -60,12 +61,34 @@ public sealed class FilePackRunStateStoreTests
private static PackRunState CreateState(string runId)
{
var failurePolicy = new TaskPackPlanFailurePolicy(MaxAttempts: 3, BackoffSeconds: 30, ContinueOnError: false);
var steps = new Dictionary<string, PackRunStepStateRecord>(StringComparer.Ordinal)
{
["step-a"] = new PackRunStepStateRecord(
StepId: "step-a",
Kind: PackRunStepKind.Run,
var failurePolicy = new TaskPackPlanFailurePolicy(MaxAttempts: 3, BackoffSeconds: 30, ContinueOnError: false);
var metadata = new TaskPackPlanMetadata("sample", "1.0.0", null, Array.Empty<string>());
var parameters = new Dictionary<string, TaskPackPlanParameterValue>(StringComparer.Ordinal);
var stepPlan = new TaskPackPlanStep(
Id: "step-a",
TemplateId: "run/image",
Name: "Run step",
Type: "run",
Enabled: true,
Uses: "builtin/run",
Parameters: parameters,
ApprovalId: null,
GateMessage: null,
Children: Array.Empty<TaskPackPlanStep>());
var plan = new TaskPackPlan(
metadata,
new Dictionary<string, JsonNode?>(StringComparer.Ordinal),
new[] { stepPlan },
"hash-123",
Array.Empty<TaskPackPlanApproval>(),
Array.Empty<TaskPackPlanSecret>(),
Array.Empty<TaskPackPlanOutput>(),
failurePolicy);
var steps = new Dictionary<string, PackRunStepStateRecord>(StringComparer.Ordinal)
{
["step-a"] = new PackRunStepStateRecord(
StepId: "step-a",
Kind: PackRunStepKind.Run,
Enabled: true,
ContinueOnError: false,
MaxParallel: null,
@@ -75,10 +98,11 @@ public sealed class FilePackRunStateStoreTests
Attempts: 1,
LastTransitionAt: DateTimeOffset.UtcNow,
NextAttemptAt: null,
StatusReason: null)
};
return PackRunState.Create(runId, "hash-123", failurePolicy, steps, DateTimeOffset.UtcNow);
StatusReason: null)
};
var timestamp = DateTimeOffset.UtcNow;
return PackRunState.Create(runId, "hash-123", plan, failurePolicy, timestamp, steps, timestamp);
}
private static string CreateTempDirectory()