Commits merged: - feat(FN-3860): complete Step 8 — documentation and delivery - test(FN-3860): complete Step 7 — add scaffold seam coverage - feat(FN-3860): complete Step 6 — re-export scaffold seams - feat(FN-3860): complete Step 5 — add pipeline orchestrator seam - feat(FN-3860): complete Step 4 — add in-memory runs store seam - feat(FN-3860): complete Step 3 — add aggregation seam - feat(FN-3860): complete Step 2 — add cadence resolution seam - feat(FN-3846): short-circuit phantom merges for already-landed branches Files changed: .changeset/fn-3860-reports-scaffold-files.md | 5 ++ plugins/fusion-plugin-reports/README.md | 9 +++ .../src/__tests__/scaffold.test.ts | 60 +++++++++++++++++++ plugins/fusion-plugin-reports/src/aggregation.ts | 23 ++++++++ plugins/fusion-plugin-reports/src/cadence.ts | 23 ++++++++ plugins/fusion-plugin-reports/src/index.ts | 4 ++ plugins/fusion-plugin-reports/src/pipeline.ts | 58 ++++++++++++++++++ plugins/fusion-plugin-reports/src/runs-store.ts | 69 ++++++++++++++++++++++ 8 files changed, 251 insertions(+) Fusion-Task-Id: FN-3860
59 lines
1.8 KiB
TypeScript
59 lines
1.8 KiB
TypeScript
/**
|
|
* INTERIM ORCHESTRATOR. FN-3779 replaces this with cadence-registry + cron-sentinel wiring;
|
|
* FN-3780 replaces the aggregate dependency with the real aggregation layer.
|
|
* Keep the `ReportsPipelineDependencies` shape stable so both can plug in without callsite churn.
|
|
*/
|
|
import type { ReportsAggregator } from "./aggregation.js";
|
|
import type { ReportsCadence } from "./cadence.js";
|
|
import type { ReportRunRecord, ReportsRunsStore } from "./runs-store.js";
|
|
|
|
export interface ReportsPipelineDependencies {
|
|
runsStore: ReportsRunsStore;
|
|
aggregate: ReportsAggregator;
|
|
}
|
|
|
|
export interface StartPipelineInput {
|
|
runId: string;
|
|
cadence: ReportsCadence;
|
|
settings: Record<string, unknown>;
|
|
now?: Date;
|
|
}
|
|
|
|
export async function startReportsPipeline(
|
|
input: StartPipelineInput,
|
|
deps: ReportsPipelineDependencies,
|
|
): Promise<ReportRunRecord> {
|
|
const nowIso = (input.now ?? new Date()).toISOString();
|
|
|
|
const created = await deps.runsStore.create({
|
|
id: input.runId,
|
|
cadence: input.cadence,
|
|
status: "queued",
|
|
createdAt: nowIso,
|
|
updatedAt: nowIso,
|
|
});
|
|
|
|
await deps.runsStore.update(input.runId, { status: "running", updatedAt: nowIso });
|
|
|
|
try {
|
|
await deps.aggregate({
|
|
runId: input.runId,
|
|
cadence: input.cadence,
|
|
settings: input.settings,
|
|
});
|
|
|
|
const updatedAt = new Date().toISOString();
|
|
const reviewed = await deps.runsStore.update(input.runId, { status: "review", updatedAt });
|
|
return reviewed ?? { ...created, status: "review", updatedAt };
|
|
} catch (error) {
|
|
const updatedAt = new Date().toISOString();
|
|
const message = error instanceof Error ? error.message : String(error);
|
|
const failed = await deps.runsStore.update(input.runId, {
|
|
status: "failed",
|
|
error: message,
|
|
updatedAt,
|
|
});
|
|
return failed ?? { ...created, status: "failed", error: message, updatedAt };
|
|
}
|
|
}
|