postmortem/render.go
2026-03-24 17:56:59 +03:00

126 lines
5.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package main
import (
"fmt"
"strings"
)
// renderMarkdown генерирует готовый Markdown-документ из структуры PostMortem.
func renderMarkdown(pm PostMortem) string {
var sb strings.Builder
line := func(s string) { sb.WriteString(s + "\n") }
linef := func(format string, a ...any) { sb.WriteString(fmt.Sprintf(format, a...) + "\n") }
blank := func() { sb.WriteString("\n") }
hr := func() { line("---"); blank() }
// ── Заголовок ────────────────────────────────────────────────────────────
line("# 🔥 Post Mortem: " + pm.Title)
blank()
linef("> **Статус:** %s ", pm.Status)
linef("> **Severity:** %s ", pm.Severity)
linef("> **Дата инцидента:** %s ", pm.IncidentDate)
linef("> **Дата постмортема:** %s ", pm.PostmortemDate)
linef("> **Автор:** %s ", pm.Author)
linef("> **Участники разбора:** %s ", pm.Participants)
blank()
hr()
// ── Резюме ───────────────────────────────────────────────────────────────
line("## 📋 Краткое резюме")
blank()
line(pm.Summary)
blank()
hr()
// ── Impact ───────────────────────────────────────────────────────────────
line("## 💥 Влияние (Impact)")
blank()
line("| Параметр | Значение |")
line("|----------|----------|")
linef("| Длительность | %s |", pm.Duration)
linef("| Затронутые пользователи | %s |", pm.AffectedUsers)
linef("| Затронутые сервисы | %s |", pm.AffectedServices)
linef("| Финансовые потери | %s |", pm.FinancialLoss)
linef("| Нарушение SLA | %s |", pm.SLABreach)
linef("| Обращений в поддержку | %s |", pm.SupportTickets)
blank()
hr()
// ── Хронология ───────────────────────────────────────────────────────────
line("## 🕐 Хронология (Timeline)")
blank()
line("| Время | Событие |")
line("|-------|---------|")
for _, e := range pm.Timeline {
linef("| %s | %s |", e.Time, e.Event)
}
blank()
hr()
// ── Корневая причина ─────────────────────────────────────────────────────
line("## 🔍 Корневая причина (Root Cause)")
blank()
line(pm.RootCause)
blank()
line("### Анализ «5 Почему»")
blank()
for i, item := range pm.WhyAnalysis {
linef("%d. **Почему** %s → %s", i+1, item.Why, item.Answer)
}
blank()
hr()
// ── Сопутствующие факторы ────────────────────────────────────────────────
line("## ⚠️ Сопутствующие факторы")
blank()
for _, f := range pm.Contributing {
linef("- %s", f)
}
blank()
hr()
// ── Что сработало хорошо ─────────────────────────────────────────────────
line("## ✅ Что сработало хорошо")
blank()
for _, f := range pm.WentWell {
linef("- %s", f)
}
blank()
hr()
// ── Что улучшить ─────────────────────────────────────────────────────────
line("## 🔧 Что можно улучшить")
blank()
for _, f := range pm.ToImprove {
linef("- %s", f)
}
blank()
hr()
// ── Action Items ─────────────────────────────────────────────────────────
line("## 📌 Action Items")
blank()
line("| # | Задача | Ответственный | Дедлайн | Статус |")
line("|---|--------|---------------|---------|--------|")
for i, item := range pm.ActionItems {
linef("| %d | %s | %s | %s | 🔲 Открыта |", i+1, item.Task, item.Assignee, item.Deadline)
}
blank()
hr()
// ── Ссылки ───────────────────────────────────────────────────────────────
line("## 💬 Дополнительные материалы")
blank()
linef("- Тикет инцидента: %s", pm.TicketLink)
linef("- Логи / дашборд: %s", pm.LogsLink)
linef("- PR / деплой: %s", pm.PRLink)
linef("- Запись встречи: %s", pm.MeetingLink)
blank()
hr()
// ── Футер ────────────────────────────────────────────────────────────────
line("*Документ подготовлен в соответствии с процессом blameless post mortem. Цель — улучшение системы, а не поиск виноватых.*")
return sb.String()
}