Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions internal/cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ type Flags struct {
InstallerVersion string

Lang, Version, Role, Mode, Runtime string
// LangAsked : the language was asked in this run (not given with --lang), so its step stays
// at the left once answered
LangAsked bool
InstallRuntime bool
Dir, Name string
Port int
Expand Down
20 changes: 15 additions & 5 deletions internal/cli/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ type wstep struct {
label string
// skip : not asked (a flag answered it, or the role or the mode has no such step)
skip func() bool
// shown : at the left even when skipped (the language, asked before the wizard began)
shown func() bool
// ask asks and keeps the answer ; ui.ErrBack goes to the step before
ask func() error
}
Expand All @@ -43,21 +45,26 @@ type wstep struct {
//
// ErrAborted when stopped, or a step's own error.
func runWizard(list []wstep) error {
// back : the step is reached with Esc, so one answered before the wizard began (shown at
// the left though skipped, the language) is asked again
back := false
for i := 0; i < len(list); {
ui.Steps(visibleLabels(list)...)
s := list[i]
if s.skip != nil && s.skip() {
if s.skip != nil && s.skip() && !(back && s.shown != nil && s.shown()) {
i++
continue
}
back = false
ui.Section(stepName(s.label))
err := s.ask()
if errors.Is(err, ui.ErrBack) {
j := i - 1
for j > 0 && list[j].skip != nil && list[j].skip() {
for j > 0 && list[j].skip != nil && list[j].skip() && (list[j].shown == nil || !list[j].shown()) {
j--
}
i = max(0, j)
back = true
continue
}
if err != nil {
Expand All @@ -69,7 +76,8 @@ func runWizard(list []wstep) error {
return nil
}

// visibleLabels are the steps at the left : those not skipped, each once, in order.
// visibleLabels are the steps at the left : those not skipped, or shown anyway, each once, in
// order.
//
// Args:
//
Expand All @@ -82,7 +90,8 @@ func visibleLabels(list []wstep) []string {
var out []string
seen := map[string]bool{}
for _, s := range list {
if (s.skip != nil && s.skip()) || seen[s.label] {
hidden := s.skip != nil && s.skip() && (s.shown == nil || !s.shown())
if hidden || seen[s.label] {
continue
}
seen[s.label] = true
Expand Down Expand Up @@ -138,6 +147,7 @@ func install(ctx context.Context, f Flags) error {
return err
}
f.Lang = i18n.Current()
f.LangAsked = true
}
if st, err := state.Load(); err == nil {
ui.Warn(i18n.T("install.already", "version", st.Version, "mode", string(st.Mode)))
Expand Down Expand Up @@ -182,7 +192,7 @@ func install(ctx context.Context, f Flags) error {
var list []wstep
list = []wstep{
// first the language, the server's locale chosen ; its steps renamed once changed
{label: "language", skip: func() bool { return ui.Unattended || f.Lang != "" }, ask: func() error {
{label: "language", skip: func() bool { return ui.Unattended || f.Lang != "" }, shown: func() bool { return f.LangAsked }, ask: func() error {
return chooseLanguage(func() { ui.Relabel(visibleLabels(list)...) })
}},
// then what this version brings : its breaking changes, removals and deprecations on top
Expand Down
64 changes: 64 additions & 0 deletions internal/cli/install_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package cli

import (
"reflect"
"testing"

"github.com/ansibleforms/installer/internal/ui"
)

// TestVisibleLabelsKeepsAnsweredLanguage checks that the language, asked before the wizard
// began (so its own step is skipped), stays at the left, while a step skipped for another
// reason does not show.
func TestVisibleLabelsKeepsAnsweredLanguage(t *testing.T) {
asked := true
skipped := func() bool { return true }
list := []wstep{
{label: "language", skip: skipped, shown: func() bool { return asked }},
{label: "notes"},
{label: "folder", skip: skipped},
{label: "role"},
}
want := []string{stepName("language"), stepName("notes"), stepName("role")}
if got := visibleLabels(list); !reflect.DeepEqual(got, want) {
t.Fatalf("visibleLabels = %v, want %v", got, want)
}
// given with --lang : never asked, so not at the left
asked = false
want = []string{stepName("notes"), stepName("role")}
if got := visibleLabels(list); !reflect.DeepEqual(got, want) {
t.Fatalf("visibleLabels with --lang = %v, want %v", got, want)
}
}

// TestRunWizardBackToAnsweredLanguage checks that Esc on the step after the language, asked
// before the wizard began, asks the language again, then goes on.
func TestRunWizardBackToAnsweredLanguage(t *testing.T) {
var asked []string
notesSeen := 0
list := []wstep{
{label: "language", skip: func() bool { return true }, shown: func() bool { return true }, ask: func() error {
asked = append(asked, "language")
return nil
}},
{label: "notes", ask: func() error {
asked = append(asked, "notes")
notesSeen++
if notesSeen == 1 {
return ui.ErrBack
}
return nil
}},
{label: "role", ask: func() error {
asked = append(asked, "role")
return nil
}},
}
if err := runWizard(list); err != nil {
t.Fatal(err)
}
want := []string{"notes", "language", "notes", "role"}
if !reflect.DeepEqual(asked, want) {
t.Fatalf("asked %v, want %v", asked, want)
}
}
30 changes: 24 additions & 6 deletions internal/cli/upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ func upgrade(ctx context.Context, f Flags) error {
if err := chooseLanguage(func() { ui.Relabel(langLabels()...) }); err != nil {
return err
}
f.Lang = i18n.Current()
f.LangAsked = true
}
if st == nil {
if st, err = offerFound(ctx, f, found, false); err != nil {
Expand Down Expand Up @@ -86,25 +88,41 @@ func upgrade(ctx context.Context, f Flags) error {

labels := func() []string {
l := []string{stepName("version"), stepName("notes"), stepName("upgrade")}
if askLang {
// asked here, or by the install before it came to this upgrade
if f.LangAsked {
l = append([]string{stepName("language")}, l...)
}
return l
}
ui.Steps(labels()...)
ui.Section(stepName("version"))
ui.Answered(from.String() + " → " + to.String())
ui.Section(stepName("notes"))
entries, err := releases.FetchChangelog(ctx, to)
if err != nil {
ui.Warn(err.Error())
}
skipped := releases.Between(entries, from, to)
if len(skipped) > 0 {
for {
ui.Section(stepName("version"))
ui.Answered(from.String() + " → " + to.String())
ui.Section(stepName("notes"))
if len(skipped) == 0 {
break
}
ui.Explain(i18n.T("upgrade.notesHelp", "from", from.String(), "to", to.String()))
if err := ui.Document(i18n.T("upgrade.notesTitle", "count", len(skipped)), func() { showNotes(skipped) }); err != nil && !errors.Is(err, ui.ErrBack) {
err := ui.Document(i18n.T("upgrade.notesTitle", "count", len(skipped)), func() { showNotes(skipped) })
if errors.Is(err, ui.ErrBack) && f.LangAsked {
// Esc : back to the language, asked in this run, then the notes again in it
ui.Section(stepName("language"))
if err := chooseLanguage(func() { ui.Relabel(labels()...) }); err != nil && !errors.Is(err, ui.ErrBack) {
return err
}
f.Lang = i18n.Current()
ui.Steps(labels()...)
continue
}
if err != nil && !errors.Is(err, ui.ErrBack) {
return err
}
break
}
// a Runner of 7.2 in database mode : its runner, its app and its mode asked and reviewed,
// then moved to the installer's Runner layout (migrate.go)
Expand Down
Loading