fix: show a visible error screen instead of silently swallowing errors on resetToMenu

This commit is contained in:
Stefan Koelle
2026-08-09 12:31:43 +02:00
parent 4be10b6432
commit 9daba2a3f0
+28 -26
View File
@@ -31,6 +31,7 @@ const (
stepForceSyncConfirm stepForceSyncConfirm
stepExternalSecretName stepExternalSecretName
stepDone stepDone
stepError
) )
type panelModel struct { type panelModel struct {
@@ -150,7 +151,7 @@ func (m *panelModel) handleEnter() (tea.Model, tea.Cmd) {
return m.fromForceSyncConfirm() return m.fromForceSyncConfirm()
case stepExternalSecretName: case stepExternalSecretName:
return m.doForceSync() return m.doForceSync()
case stepDiffResult, stepDone: case stepDiffResult, stepDone, stepError:
m.resetToMenu() m.resetToMenu()
return m, nil return m, nil
} }
@@ -165,6 +166,15 @@ func (m *panelModel) resetToMenu() {
m.err = nil m.err = nil
} }
// showError switches to a dedicated error screen so failures from
// kubectl/aws calls stay visible until the user explicitly acknowledges
// them with Enter, instead of being silently discarded.
func (m *panelModel) showError(err error) (tea.Model, tea.Cmd) {
m.err = err
m.step = stepError
return m, nil
}
func (m *panelModel) fromMenu() (tea.Model, tea.Cmd) { func (m *panelModel) fromMenu() (tea.Model, tea.Cmd) {
item, ok := m.list.SelectedItem().(simpleItem) item, ok := m.list.SelectedItem().(simpleItem)
if !ok { if !ok {
@@ -174,8 +184,7 @@ func (m *panelModel) fromMenu() (tea.Model, tea.Cmd) {
case "redeploy": case "redeploy":
deployments, err := kubeexec.GetDeployments(m.ns) deployments, err := kubeexec.GetDeployments(m.ns)
if err != nil { if err != nil {
m.err = err return m.showError(err)
return m, nil
} }
items := make([]list.Item, 0, len(deployments)) items := make([]list.Item, 0, len(deployments))
for _, d := range deployments { for _, d := range deployments {
@@ -218,9 +227,12 @@ func (m *panelModel) fromRedeployConfirm() (tea.Model, tea.Cmd) {
deployment := m.k8sSecretName // set in fromRedeployList deployment := m.k8sSecretName // set in fromRedeployList
_, err := kubeexec.RolloutRestart(m.ns, deployment) _, err := kubeexec.RolloutRestart(m.ns, deployment)
if err != nil { if err != nil {
m.err = err return m.showError(err)
}
status, err := kubeexec.RolloutStatus(m.ns, deployment)
if err != nil {
return m.showError(err)
} }
status, _ := kubeexec.RolloutStatus(m.ns, deployment)
m.message = "Rollout status: " + status m.message = "Rollout status: " + status
m.step = stepDone m.step = stepDone
return m, nil return m, nil
@@ -231,14 +243,10 @@ func (m *panelModel) fromRedeployConfirm() (tea.Model, tea.Cmd) {
func (m *panelModel) fetchSecretList() (tea.Model, tea.Cmd) { func (m *panelModel) fetchSecretList() (tea.Model, tea.Cmd) {
names, err := kubeexec.ListAWSSecrets(m.awsRegion) names, err := kubeexec.ListAWSSecrets(m.awsRegion)
if err != nil { if err != nil {
m.err = err return m.showError(err)
m.resetToMenu()
return m, nil
} }
if len(names) == 0 { if len(names) == 0 {
m.err = fmt.Errorf("no AWS secrets found in region %s (or missing IAM permissions)", m.awsRegion) return m.showError(fmt.Errorf("no AWS secrets found in region %s (or missing IAM permissions)", m.awsRegion))
m.resetToMenu()
return m, nil
} }
items := make([]list.Item, 0, len(names)) items := make([]list.Item, 0, len(names))
for _, n := range names { for _, n := range names {
@@ -259,9 +267,7 @@ func (m *panelModel) fromSecretList() (tea.Model, tea.Cmd) {
raw, err := kubeexec.GetAWSSecretString(m.awsSecretID, m.awsRegion) raw, err := kubeexec.GetAWSSecretString(m.awsSecretID, m.awsRegion)
if err != nil { if err != nil {
m.err = err return m.showError(err)
m.resetToMenu()
return m, nil
} }
var parsed map[string]interface{} var parsed map[string]interface{}
if err := json.Unmarshal([]byte(raw), &parsed); err != nil { if err := json.Unmarshal([]byte(raw), &parsed); err != nil {
@@ -286,9 +292,7 @@ func (m *panelModel) fromSecretList() (tea.Model, tea.Cmd) {
func (m *panelModel) compareAllFields() (tea.Model, tea.Cmd) { func (m *panelModel) compareAllFields() (tea.Model, tea.Cmd) {
k8sValues, err := kubeexec.GetSecretAllFields(m.ns, m.k8sSecretName) k8sValues, err := kubeexec.GetSecretAllFields(m.ns, m.k8sSecretName)
if err != nil { if err != nil {
m.err = err return m.showError(err)
m.resetToMenu()
return m, nil
} }
m.k8sValues = k8sValues m.k8sValues = k8sValues
m.diffEntries = diffSecretValues(m.awsValues, m.k8sValues) m.diffEntries = diffSecretValues(m.awsValues, m.k8sValues)
@@ -348,7 +352,7 @@ func (m *panelModel) doForceSync() (tea.Model, tea.Cmd) {
ts := time.Now().Unix() ts := time.Now().Unix()
_, err := kubeexec.AnnotateForceSync(m.ns, name, ts) _, err := kubeexec.AnnotateForceSync(m.ns, name, ts)
if err != nil { if err != nil {
m.err = err return m.showError(err)
} }
m.message += fmt.Sprintf("\nForce-sync requested for %s (timestamp %s).", name, strconv.FormatInt(ts, 10)) m.message += fmt.Sprintf("\nForce-sync requested for %s (timestamp %s).", name, strconv.FormatInt(ts, 10))
m.step = stepDone m.step = stepDone
@@ -358,19 +362,17 @@ func (m *panelModel) doForceSync() (tea.Model, tea.Cmd) {
func (m *panelModel) View() string { func (m *panelModel) View() string {
switch m.step { switch m.step {
case stepMenu, stepRedeployList, stepRedeployConfirm, stepSecretList: case stepMenu, stepRedeployList, stepRedeployConfirm, stepSecretList:
v := m.list.View() return m.list.View()
if m.err != nil {
v += "\nerror: " + m.err.Error()
}
return v
case stepForceSyncConfirm: case stepForceSyncConfirm:
return m.message + "\n\n" + m.list.View() return m.message + "\n\n" + m.list.View()
case stepDiffResult, stepDone: case stepDiffResult, stepDone:
v := m.message return m.message + "\n\n(press enter to return to menu, esc to close session)"
case stepError:
errText := "unknown error"
if m.err != nil { if m.err != nil {
v += "\nerror: " + m.err.Error() errText = m.err.Error()
} }
return v + "\n\n(press enter to return to menu, esc to close session)" return "ERROR:\n\n" + errText + "\n\n(press enter to return to menu, esc to close session)"
default: default:
return fmt.Sprintf("%s\n\n%s\n\n(enter = confirm, esc = back to menu/close session)", return fmt.Sprintf("%s\n\n%s\n\n(enter = confirm, esc = back to menu/close session)",
m.stepPrompt(), m.input.View()) m.stepPrompt(), m.input.View())