Gitfed
bastien-mrq/gitfed/ Commits/ 5710606

gitfed-install now bootstraps gitfed-ctl for future updates

Installs it straight into /usr/local/bin via a throwaway golang container right after the pod comes up, so a fresh instance is ready for sudo gitfed-ctl without a manual step. Best-effort — falls back to deploy/update.sh in the success screen's suggestions if it fails. Also fixes the gitfed-ctl install instructions in INSTALL.md, verified live: go install run directly on the VPS fails since nothing puts a system Go there.

bastien-mrq 2026-07-29 18:08 commit 5710606c821871ee57c7c0bba0170ec97840f4e3 parent 6e4d93c3b04037b477871fe046972a826d533c76
4 files changed +60 −2
M CHANGELOG.md +5 −0
M cmd/gitfed-install/actions.go +16 −0
M cmd/gitfed-install/model.go +23 −1
M cmd/gitfed-install/screens_finish.go +16 −1
CHANGELOG.md
diff --git a/CHANGELOG.md b/CHANGELOG.md index 91514ee..74fc41c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ A bullet starting with `**BREAKING:**` flags a change gitfed-ctl's update wizard makes you acknowledge individually before it will let you upgrade past that version. +## 1.2.9 + +- `gitfed-install` now installs `gitfed-ctl` into `/usr/local/bin` itself (via a throwaway `golang` container, no system Go needed on the host — same trick the fix below uses) right after the pod comes up, so a fresh instance is ready for `sudo gitfed-ctl` updates without a separate manual step. Best-effort: a failure here doesn't block the install, it just falls back to `deploy/update.sh` in the final screen's suggestions. +- Fixed `INSTALL.md`'s `gitfed-ctl` install instructions from 1.2.8: `go install` run directly on the VPS fails, since nothing in the install flow puts a system Go there (the main image build compiles inside Docker). Verified fix: run it inside a throwaway `golang:1.25-bookworm` container instead, writing straight into `/usr/local/bin`. + ## 1.2.8 - New `gitfed-ctl`: an update utility for instances that follow someone else's releases rather than cutting their own. Runs locally on the VPS (no SSH-to-self, no repeated password prompt — the problem with `deploy/update.sh current` observed live), checks for new versions, makes any `**BREAKING:**` CHANGELOG.md entry something you have to individually acknowledge before continuing, optionally backs up the data volume, then rebuilds and redeploys. `GOPRIVATE=git.neuromancer.ovh/* go install git.neuromancer.ovh/bastien-mrq/gitfed/cmd/gitfed-ctl@latest`, then `sudo gitfed-ctl` from inside a checkout. Account and federation-trust management stay on the web admin UI, which already covers both.
cmd/gitfed-install/actions.go
diff --git a/cmd/gitfed-install/actions.go b/cmd/gitfed-install/actions.go index df98a48..399dcdf 100644 --- a/cmd/gitfed-install/actions.go +++ b/cmd/gitfed-install/actions.go @@ -190,6 +190,22 @@ func diagnoseStuckPod(ctx context.Context, sourceDir string) tagDiagnosis { return diagnoseImageTag(string(deployYAML), imagesOut) } +// installGitfedCtl installs gitfed-ctl (see cmd/gitfed-ctl) straight into +// /usr/local/bin via a throwaway golang container — no system Go needed on +// the host (nothing else in this flow puts one there; the main image build +// compiles inside Docker too). The golang:1.25-bookworm base is already +// cached locally from runBuildImage a moment ago, so this is fast, not a +// second cold pull. +func installGitfedCtl(ctx context.Context) error { + _, err := runQuiet(ctx, "", "docker", "run", "--rm", + "-e", "GOPRIVATE=git.neuromancer.ovh/*", + "-e", "GOBIN=/out", + "-v", "/usr/local/bin:/out", + "golang:1.25-bookworm", + "go", "install", "git.neuromancer.ovh/bastien-mrq/gitfed/cmd/gitfed-ctl@latest") + return err +} + func runVerify(ctx context.Context, domain string) []verifyResult { client := &http.Client{Timeout: 8 * time.Second} check := func(label, url string) verifyResult {
cmd/gitfed-install/model.go
diff --git a/cmd/gitfed-install/model.go b/cmd/gitfed-install/model.go index 491c14e..b3273cd 100644 --- a/cmd/gitfed-install/model.go +++ b/cmd/gitfed-install/model.go @@ -93,6 +93,9 @@ type model struct { verify []verifyResult verifyDone bool + ctlInstallDone bool + ctlInstallErr error + spin spinner.Model } @@ -198,7 +201,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { m.podPolling = false if msg.err == nil && msg.status.Phase == podReady { m.step = stepVerify - return m, tea.Batch(m.cmdVerify(), listen(m.msgCh)) + return m, tea.Batch(m.cmdVerify(), m.cmdInstallCtl(), listen(m.msgCh)) } if msg.err == nil && msg.status.Phase == podErrImageNeverPull { m.step = stepPodStuck @@ -218,6 +221,11 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { m.verifyDone = true return m, listen(m.msgCh) + case ctlInstallMsg: + m.ctlInstallDone = true + m.ctlInstallErr = msg.err + return m, listen(m.msgCh) + case accountHandoffDoneMsg: m.step = stepSuccess return m, listen(m.msgCh) @@ -301,6 +309,7 @@ type podPollMsg struct { err error } type verifyResultMsg struct{ results []verifyResult } +type ctlInstallMsg struct{ err error } type stuckDiagMsg struct{ diag tagDiagnosis } type accountHandoffDoneMsg struct{} type fatalErrMsg struct{ err error } @@ -407,6 +416,19 @@ func (m model) cmdVerify() tea.Cmd { } } +// cmdInstallCtl installs gitfed-ctl (the update utility, see cmd/gitfed-ctl) +// straight into /usr/local/bin so it's ready for future updates without a +// separate manual step — best-effort, never blocks the wizard from +// finishing (see viewVerify/viewSuccess for how a failure here is shown). +func (m model) cmdInstallCtl() tea.Cmd { + ch := m.msgCh + ctx := m.ctx + return func() tea.Msg { + go func() { ch <- ctlInstallMsg{err: installGitfedCtl(ctx)} }() + return nil + } +} + // launchAccountTUI suspends gitfed-install and hands the terminal to a // real, unmodified, interactive `kubectl exec -it ... gitfed-tui` session // — see screens_finish.go for why this is a handoff rather than gitfed-
cmd/gitfed-install/screens_finish.go
diff --git a/cmd/gitfed-install/screens_finish.go b/cmd/gitfed-install/screens_finish.go index ca48131..8866355 100644 --- a/cmd/gitfed-install/screens_finish.go +++ b/cmd/gitfed-install/screens_finish.go @@ -14,6 +14,16 @@ func (m model) viewVerify() string { } b.WriteString(row(g, v.Label, v.Detail) + "\n") } + + switch { + case !m.ctlInstallDone: + b.WriteString(row(m.spin.View(), "gitfed-ctl (mises à jour futures)", "installation…") + "\n") + case m.ctlInstallErr != nil: + b.WriteString(row(glyph(statusWarn), "gitfed-ctl (mises à jour futures)", "échec — voir INSTALL.md") + "\n") + default: + b.WriteString(row(glyph(statusOK), "gitfed-ctl (mises à jour futures)", "installé") + "\n") + } + return stylePanel.Render(b.String()) } @@ -41,9 +51,14 @@ func (m model) viewSuccess() string { b.WriteString(row("", "Interface web", "https://"+domain) + "\n") b.WriteString(row("", "Connexion", "https://"+domain+"/login") + "\n") b.WriteString(row("", "Clone SSH", "git clone ssh://git@"+domain+":2222/<utilisateur>/<dépôt>") + "\n\n") + + updateHint := "sudo gitfed-ctl depuis ce checkout" + if m.ctlInstallErr != nil { + updateHint = "deploy/update.sh (l'installation de gitfed-ctl a échoué — voir INSTALL.md)" + } b.WriteString(styleMuted.Render( "Suggéré pour la suite : sauvegardes régulières (deploy/backup.sh), mises à jour\n" + - "(deploy/update.sh), et la page /security de ta propre instance pour le détail\n" + + "(" + updateHint + "), et la page /security de ta propre instance pour le détail\n" + "du modèle de confiance.")) return stylePanel.Render(b.String()) }