Gitfed
bastien-mrq/gitfed / cmd / gitfed-install / screens_deploy.go
package main

import (
	"strconv"
	"strings"
)

func (m model) viewK3s() string {
	var b strings.Builder
	b.WriteString(row(stepGlyph(m.k3sDone, m.installErr), "[1/3] k3s", stepDetail(m.k3sDone)) + "\n")
	b.WriteString(row(stepGlyph(m.certManagerDone, m.installErr), "[2/3] cert-manager", stepDetail(m.certManagerDone)) + "\n")
	b.WriteString(row(stepGlyph(m.issuerDone, m.installErr), "[3/3] Émetteur Let's Encrypt", stepDetail(m.issuerDone)) + "\n")

	if m.installErr != nil {
		b.WriteString("\n" + styleDanger.Render("Erreur : "+m.installErr.Error()))
	}

	b.WriteString("\n\n" + styleLog.Render(tailLines(m.k3sLines, 8)))
	return stylePanel.Render(b.String())
}

func (m model) viewBuild() string {
	var b strings.Builder
	b.WriteString(row(stepGlyph(m.buildDone, m.buildErr), "docker build", stepDetail(m.buildDone)) + "\n")
	b.WriteString(row(stepGlyph(m.importDone, m.buildErr), "import dans containerd", stepDetail(m.importDone)) + "\n")

	if m.buildErr != nil {
		b.WriteString("\n" + styleDanger.Render("Erreur : "+m.buildErr.Error()))
	}

	b.WriteString("\n\n" + styleLog.Render(tailLines(m.buildLines, 10)))
	b.WriteString("\n" + styleMuted.Render("Construit ici, sur cette machine — jamais copié depuis un poste de travail d'une autre architecture."))
	return stylePanel.Render(b.String())
}

func (m model) viewDeploy() string {
	var b strings.Builder
	for i, f := range m.deployStatus {
		g := glyph(statusMissing)
		if f.Err != nil {
			g = glyph(statusWarn)
		} else if f.Done {
			g = glyph(statusOK)
		} else if i == m.deployIdx {
			g = m.spin.View()
		}
		b.WriteString(row(g, shortManifestName(f.Label), "") + "\n")
	}
	if m.deployErr != nil {
		b.WriteString("\n" + styleDanger.Render("Erreur : "+m.deployErr.Error()))
	}
	return stylePanel.Render(b.String())
}

func shortManifestName(path string) string {
	if i := strings.LastIndex(path, "/"); i >= 0 {
		return path[i+1:]
	}
	return path
}

func (m model) viewPodStatus() string {
	var b strings.Builder
	if m.pod.Name == "" {
		b.WriteString(m.spin.View() + " " + styleBody.Render("En attente que le pod soit planifié…"))
		if m.podErr != nil {
			b.WriteString("\n\n" + styleWarn.Render("!") + " " + styleMuted.Render(m.podErr.Error()))
		}
		return stylePanel.Render(b.String())
	}
	ready := m.pod.Phase == podReady
	g := m.spin.View()
	if ready {
		g = glyph(statusOK)
	}
	b.WriteString(row(g, m.pod.Name, itoaFrac(m.pod.ReadyContainers, m.pod.TotalContainers)+" "+m.pod.RawStatus) + "\n")
	if ready {
		b.WriteString(row(glyph(statusOK), "server — socket admin actif", "") + "\n")
		b.WriteString(row(glyph(statusOK), "web — répond sur :8088", "") + "\n")
	} else {
		b.WriteString("\n" + styleMuted.Render("Un bref 0/2 juste après le déploiement est normal — web attend le socket admin de server."))
	}
	return stylePanel.Render(b.String())
}

func (m model) viewPodStuck() string {
	var b strings.Builder
	b.WriteString(row(glyph(statusWarn), m.pod.Name, itoaFrac(m.pod.ReadyContainers, m.pod.TotalContainers)+" "+m.pod.RawStatus) + "\n\n")

	if !m.stuckDiagDone {
		b.WriteString(m.spin.View() + " " + styleBody.Render("Comparaison des tags d'image…"))
		return stylePanelDanger.Render(b.String())
	}

	diag := m.stuckDiag
	b.WriteString(styleBold.Render("Ce que ça veut dire :") + " " +
		styleBody.Render("l'image importée n'a pas le tag attendu par le déploiement.") + "\n\n")
	b.WriteString(row("", "deployment.yaml attend", diag.Expected) + "\n")
	if len(diag.Imported) == 0 {
		b.WriteString(row(glyph(statusWarn), "images importées trouvées", "aucune") + "\n")
	}
	for _, tag := range diag.Imported {
		g := glyph(statusMissing)
		if tag == diag.Expected {
			g = glyph(statusOK)
		}
		b.WriteString(row(g, "images importées trouvées", tag) + "\n")
	}

	b.WriteString("\n" + styleBody.Render("→ Reconstruire avec le bon tag corrige ça automatiquement (r)."))
	return stylePanelDanger.Render(b.String())
}

func stepGlyph(done bool, err error) string {
	if err != nil {
		return glyph(statusWarn)
	}
	if done {
		return glyph(statusOK)
	}
	return glyph(statusMissing)
}

func stepDetail(done bool) string {
	if done {
		return "prêt"
	}
	return ""
}

func tailLines(lines []string, n int) string {
	if len(lines) == 0 {
		return styleMuted.Render("(pas encore de sortie)")
	}
	if len(lines) > n {
		lines = lines[len(lines)-n:]
	}
	return strings.Join(lines, "\n")
}

func itoaFrac(a, b int) string {
	return strconv.Itoa(a) + "/" + strconv.Itoa(b)
}