mirror of
https://github.com/Matysh/houseplan-card
synced 2026-09-28 19:01:34 +00:00
fix(metrics): сохранить нулевые медианы процесса (#637)
Issue: #637 User-Visible: no
This commit is contained in:
@@ -32,6 +32,10 @@ const median = (values) => {
|
||||
const mid = Math.floor(sorted.length / 2);
|
||||
return sorted.length % 2 ? sorted[mid] : (sorted[mid - 1] + sorted[mid]) / 2;
|
||||
};
|
||||
const medianHours = (values) => {
|
||||
const value = median(values);
|
||||
return value === null ? null : hours(value);
|
||||
};
|
||||
const mean = (values) => {
|
||||
const finite = values.filter(Number.isFinite);
|
||||
return finite.length ? finite.reduce((a, b) => a + b, 0) / finite.length : null;
|
||||
@@ -159,10 +163,10 @@ export function buildReport({ since, until, issues = [], timelines = new Map(),
|
||||
closed: perIssue.length,
|
||||
completed: completed.length,
|
||||
notPlanned: perIssue.filter((issue) => issue.stateReason === 'not_planned').length,
|
||||
medianLeadToS7Hours: hours(median(completed.map((i) => i.leadToS7Ms)) ?? NaN) || null,
|
||||
medianReviewToMergeHours: hours(median(completed.map((i) => i.reviewToMergeMs)) ?? NaN) || null,
|
||||
medianLeadToS8Hours: hours(median(completed.map((i) => i.leadToS8Ms)) ?? NaN) || null,
|
||||
medianSpecLeadHours: hours(median(completed.map((i) => i.specLeadMs)) ?? NaN) || null,
|
||||
medianLeadToS7Hours: medianHours(completed.map((i) => i.leadToS7Ms)),
|
||||
medianReviewToMergeHours: medianHours(completed.map((i) => i.reviewToMergeMs)),
|
||||
medianLeadToS8Hours: medianHours(completed.map((i) => i.leadToS8Ms)),
|
||||
medianSpecLeadHours: medianHours(completed.map((i) => i.specLeadMs)),
|
||||
codeReviewRounds: { mean: mean(codeRounds), distribution: dist(codeRounds), issues: codeRounds.length },
|
||||
specReviewRounds: { mean: mean(specRounds), distribution: dist(specRounds), issues: specRounds.length },
|
||||
s7RepeatRequests: completed.filter((i) => i.s7Requests > 1).length,
|
||||
|
||||
@@ -105,6 +105,29 @@ test('#637 buildReport + renderMarkdown: сводка воспроизводит
|
||||
assert.equal(report.jobs, null, 'без jobs job-минуты не выдумываются');
|
||||
});
|
||||
|
||||
test('#637 buildReport: нулевая медиана не смешивается с отсутствием данных', () => {
|
||||
const issue = { number: 637, title: 'fast', closed_at: T(4 / 60), state_reason: 'completed' };
|
||||
const timelines = new Map([[637, [
|
||||
labeled('S1-new', 0),
|
||||
labeled('S4-spec-review', 0),
|
||||
labeled('S5-ready', 1 / 60),
|
||||
labeled('S7-code-review', 2 / 60),
|
||||
labeled('S8-merged', 3 / 60),
|
||||
]] ]);
|
||||
const report = buildReport({ since: T(0), until: T(1), issues: [issue], timelines });
|
||||
assert.deepEqual([
|
||||
report.issues.medianLeadToS7Hours,
|
||||
report.issues.medianReviewToMergeHours,
|
||||
report.issues.medianLeadToS8Hours,
|
||||
report.issues.medianSpecLeadHours,
|
||||
], [0, 0, 0.1, 0]);
|
||||
assert.match(renderMarkdown(report), /Медиана вход → S7 \| 0 ч/);
|
||||
|
||||
const empty = buildReport({ since: T(0), until: T(1) });
|
||||
assert.equal(empty.issues.medianLeadToS7Hours, null);
|
||||
assert.match(renderMarkdown(empty), /Медиана вход → S7 \| —/);
|
||||
});
|
||||
|
||||
test('#637 workflow: еженедельный запуск читает только, публикует summary и artifact', () => {
|
||||
const wf = readFileSync(new URL('../.github/workflows/process-metrics.yml', import.meta.url), 'utf8');
|
||||
assert.match(wf, /schedule:\n(?:\s+#[^\n]*\n)*\s+- cron: '/);
|
||||
|
||||
Reference in New Issue
Block a user