From b070267bde5afe25ef655887db0b73787dc5637a Mon Sep 17 00:00:00 2001 From: Micheal Wilkinson Date: Fri, 20 Mar 2026 18:05:07 +0000 Subject: [PATCH] feat(rc): add --force guard for legacy homesickrc --- internal/homesick/cli/cli.go | 19 +++++++++++++------ internal/homesick/core/core.go | 4 ++++ internal/homesick/core/rc_test.go | 3 +++ 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/internal/homesick/cli/cli.go b/internal/homesick/cli/cli.go index 90acf6c..b1bfa1c 100644 --- a/internal/homesick/cli/cli.go +++ b/internal/homesick/cli/cli.go @@ -191,6 +191,7 @@ type execAllCmd struct { } type rcCmd struct { + Force bool `help:"Bypass legacy .homesickrc safety confirmation."` Castle string `arg:"" optional:"" name:"CASTLE" help:"Castle name."` } @@ -211,12 +212,18 @@ func (c *pushCmd) Run(app *core.App) error { return app.Push(defaultCastle(c.Cas func (c *commitCmd) Run(app *core.App) error { return app.Commit(defaultCastle(c.Castle), c.Message) } -func (c *destroyCmd) Run(app *core.App) error { return app.Destroy(defaultCastle(c.Castle)) } -func (c *cdCmd) Run(app *core.App) error { return app.ShowPath(defaultCastle(c.Castle)) } -func (c *openCmd) Run(app *core.App) error { return app.Open(defaultCastle(c.Castle)) } -func (c *execCmd) Run(app *core.App) error { return app.Exec(c.Castle, c.Command) } -func (c *execAllCmd) Run(app *core.App) error { return app.ExecAll(c.Command) } -func (c *rcCmd) Run(app *core.App) error { return app.Rc(defaultCastle(c.Castle)) } +func (c *destroyCmd) Run(app *core.App) error { return app.Destroy(defaultCastle(c.Castle)) } +func (c *cdCmd) Run(app *core.App) error { return app.ShowPath(defaultCastle(c.Castle)) } +func (c *openCmd) Run(app *core.App) error { return app.Open(defaultCastle(c.Castle)) } +func (c *execCmd) Run(app *core.App) error { return app.Exec(c.Castle, c.Command) } +func (c *execAllCmd) Run(app *core.App) error { return app.ExecAll(c.Command) } +func (c *rcCmd) Run(app *core.App) error { + originalForce := app.Force + app.Force = c.Force + err := app.Rc(defaultCastle(c.Castle)) + app.Force = originalForce + return err +} func (c *generateCmd) Run(app *core.App) error { return app.Generate(c.Path) } func defaultCastle(castle string) string { diff --git a/internal/homesick/core/core.go b/internal/homesick/core/core.go index 876ab1a..eada338 100644 --- a/internal/homesick/core/core.go +++ b/internal/homesick/core/core.go @@ -780,6 +780,10 @@ func (a *App) Rc(castle string) error { homesickD := filepath.Join(castleRoot, ".homesick.d") homesickRc := filepath.Join(castleRoot, ".homesickrc") + if _, err := os.Stat(homesickRc); err == nil && !a.Force { + return errors.New("refusing to run legacy .homesickrc without --force") + } + // If .homesickrc exists, ensure .homesick.d/parity.rb wrapper is created // (but do not overwrite an existing parity.rb). if _, err := os.Stat(homesickRc); err == nil { diff --git a/internal/homesick/core/rc_test.go b/internal/homesick/core/rc_test.go index 7361024..2403dac 100644 --- a/internal/homesick/core/rc_test.go +++ b/internal/homesick/core/rc_test.go @@ -130,6 +130,7 @@ func (s *RcSuite) TestRc_HomesickrcCreatesRubyWrapper() { castleRoot := s.createCastle("dotfiles") homesickRc := filepath.Join(castleRoot, ".homesickrc") require.NoError(s.T(), os.WriteFile(homesickRc, []byte("# ruby setup code\n"), 0o644)) + s.app.Force = true require.NoError(s.T(), s.app.Rc("dotfiles")) @@ -151,6 +152,7 @@ func (s *RcSuite) TestRc_HomesickrcWrapperNotOverwrittenIfExists() { castleRoot := s.createCastle("dotfiles") homesickRc := filepath.Join(castleRoot, ".homesickrc") require.NoError(s.T(), os.WriteFile(homesickRc, []byte("# ruby setup code\n"), 0o644)) + s.app.Force = true homesickD := filepath.Join(castleRoot, ".homesick.d") require.NoError(s.T(), os.MkdirAll(homesickD, 0o755)) @@ -171,6 +173,7 @@ func (s *RcSuite) TestRc_HomesickrcWrapperCreatedBeforeExecution() { castleRoot := s.createCastle("dotfiles") homesickRc := filepath.Join(castleRoot, ".homesickrc") require.NoError(s.T(), os.WriteFile(homesickRc, []byte("# ruby setup code\n"), 0o644)) + s.app.Force = true homesickD := filepath.Join(castleRoot, ".homesick.d") require.NoError(s.T(), os.MkdirAll(homesickD, 0o755))