126 lines
5.5 KiB
Go
Executable file
126 lines
5.5 KiB
Go
Executable file
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()
|
||
}
|