From 606f8fb7686e6706a5afadbec6638be65ee85abe Mon Sep 17 00:00:00 2001 From: Sagi levy Date: Tue, 26 May 2026 13:42:48 +0300 Subject: [PATCH] feat: bind R to terraform init -reconfigure Pressing R on a module (or selection of modules / workspaces) now runs `terraform init -reconfigure`, mirroring the existing `i` (init) and `u` (init -upgrade) bindings. Refactors `module.Service.Init` to take an `InitOptions` struct so future init flags can be added without breaking call sites. Capital R was chosen because lowercase `r` is already "retry"; capital `I` is already "toggle task info". Co-authored-by: Cursor --- README.md | 1 + internal/integration/module_test.go | 28 ++++++++++++++++++++ internal/module/service.go | 15 +++++++++-- internal/tui/actions.go | 16 ++++++----- internal/tui/keys/common.go | 41 ++++++++++++++++------------- 5 files changed, 75 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index cdfd4df..bf7594f 100644 --- a/README.md +++ b/README.md @@ -107,6 +107,7 @@ The number of resources in the state is shown alongside the workspace. |--|--|--|--|--| |`i`|Run `terraform init`|✓|✓|✓\*\*| |`u`|Run `terraform init -upgrade`|✓|✓|✓\*\*| +|`R`|Run `terraform init -reconfigure`|✓|✓|✓\*\*| |`f`|Run `terraform fmt`|✓|✓|✓\*\*| |`v`|Run `terraform validate`|✓|✓|✓\*\*| |`p`|Run `terraform plan`|✓|✓\*|✓| diff --git a/internal/integration/module_test.go b/internal/integration/module_test.go index a5befa9..30c5dd7 100644 --- a/internal/integration/module_test.go +++ b/internal/integration/module_test.go @@ -147,6 +147,34 @@ func TestExplorer_SingleInitUpgrade(t *testing.T) { }) } +func TestExplorer_SingleInitReconfigure(t *testing.T) { + t.Parallel() + + tm := setup(t, "./testdata/single_module") + + // Expect single module in tree + waitFor(t, tm, func(s string) bool { + return strings.Contains(s, "└ 󰠱 a") + }) + + // Cursor should automatically be on module. + // Initialize module, reconfiguring the backend. + tm.Type("R") + + // Expect to see task header + waitFor(t, tm, func(s string) bool { + return strings.Contains(s, "init 󰠱 modules/a") + }) + + // Show task info sidebar + tm.Type("I") + + // Expect to see -reconfigure argument + waitFor(t, tm, func(s string) bool { + return strings.Contains(s, "-reconfigure") + }) +} + func TestExplorer_SingleFormat(t *testing.T) { t.Parallel() diff --git a/internal/module/service.go b/internal/module/service.go index bc48906..ff7ad99 100644 --- a/internal/module/service.go +++ b/internal/module/service.go @@ -204,16 +204,27 @@ func (s *Service) loadTerragruntDependenciesFromDigraph(r io.Reader) error { const InitTask task.Identifier = "init" +// InitOptions configures a terraform init task. +type InitOptions struct { + // Upgrade adds the -upgrade flag. + Upgrade bool + // Reconfigure adds the -reconfigure flag. + Reconfigure bool +} + // Init invokes terraform init on the module. -func (s *Service) Init(moduleID resource.ID, upgrade bool) (task.Spec, error) { +func (s *Service) Init(moduleID resource.ID, opts InitOptions) (task.Spec, error) { mod, err := s.table.Get(moduleID) if err != nil { return task.Spec{}, err } args := []string{"-input=false"} - if upgrade { + if opts.Upgrade { args = append(args, "-upgrade") } + if opts.Reconfigure { + args = append(args, "-reconfigure") + } spec := task.Spec{ ModuleID: mod.ID, Path: mod.Path, diff --git a/internal/tui/actions.go b/internal/tui/actions.go index 28aedab..9271a72 100644 --- a/internal/tui/actions.go +++ b/internal/tui/actions.go @@ -6,6 +6,7 @@ import ( "github.com/charmbracelet/bubbles/key" tea "github.com/charmbracelet/bubbletea" + "github.com/leg100/pug/internal/module" "github.com/leg100/pug/internal/plan" "github.com/leg100/pug/internal/resource" "github.com/leg100/pug/internal/task" @@ -29,21 +30,23 @@ func (m *ActionHandler) Update(msg tea.Msg) tea.Cmd { // TODO: if only one worskpace is being applied, then customise message // to mention name of workspace being applied. applyPrompt = "Auto-apply %d workspaces?" - upgrade bool ) switch msg := msg.(type) { case tea.KeyMsg: switch { - case key.Matches(msg, keys.Common.InitUpgrade): - upgrade = true - fallthrough - case key.Matches(msg, keys.Common.Init): + case key.Matches(msg, keys.Common.Init), + key.Matches(msg, keys.Common.InitUpgrade), + key.Matches(msg, keys.Common.InitReconfigure): + initOpts := module.InitOptions{ + Upgrade: key.Matches(msg, keys.Common.InitUpgrade), + Reconfigure: key.Matches(msg, keys.Common.InitReconfigure), + } ids, err := m.GetModuleIDs() if err != nil { return ReportError(err) } fn := func(moduleID resource.ID) (task.Spec, error) { - return m.Modules.Init(moduleID, upgrade) + return m.Modules.Init(moduleID, initOpts) } return m.CreateTasks(fn, ids...) case key.Matches(msg, keys.Common.Execute): @@ -153,6 +156,7 @@ func (m *ActionHandler) HelpBindings() []key.Binding { return []key.Binding{ keys.Common.Init, keys.Common.InitUpgrade, + keys.Common.InitReconfigure, keys.Common.Format, keys.Common.Validate, keys.Common.Plan, diff --git a/internal/tui/keys/common.go b/internal/tui/keys/common.go index 38cd4ae..6b3f126 100644 --- a/internal/tui/keys/common.go +++ b/internal/tui/keys/common.go @@ -3,24 +3,25 @@ package keys import "github.com/charmbracelet/bubbles/key" type common struct { - Plan key.Binding - PlanDestroy key.Binding - AutoApply key.Binding - Destroy key.Binding - Cancel key.Binding - Delete key.Binding - Execute key.Binding - State key.Binding - Retry key.Binding - Reload key.Binding - Edit key.Binding - Init key.Binding - InitUpgrade key.Binding - Validate key.Binding - Format key.Binding - Cost key.Binding - LastTask key.Binding - Back key.Binding + Plan key.Binding + PlanDestroy key.Binding + AutoApply key.Binding + Destroy key.Binding + Cancel key.Binding + Delete key.Binding + Execute key.Binding + State key.Binding + Retry key.Binding + Reload key.Binding + Edit key.Binding + Init key.Binding + InitUpgrade key.Binding + InitReconfigure key.Binding + Validate key.Binding + Format key.Binding + Cost key.Binding + LastTask key.Binding + Back key.Binding } // Keys shared by several models. @@ -77,6 +78,10 @@ var Common = common{ key.WithKeys("u"), key.WithHelp("u", "init -upgrade"), ), + InitReconfigure: key.NewBinding( + key.WithKeys("R"), + key.WithHelp("R", "init -reconfigure"), + ), Validate: key.NewBinding( key.WithKeys("v"), key.WithHelp("v", "validate"),