diff --git a/internal/modules/hello/hello.go b/internal/modules/hello/hello.go index 30c5b5f..6899596 100644 --- a/internal/modules/hello/hello.go +++ b/internal/modules/hello/hello.go @@ -4,7 +4,6 @@ package hello import ( "context" - "errors" "fmt" "os" "path/filepath" @@ -99,5 +98,18 @@ func (m Module) Verify(ctx context.Context) error { } func (m Module) PlanForce(ctx context.Context) (module.Plan, error) { - return module.Plan{}, errors.New("PlanForce not implemented") + path, err := m.resolve() + if err != nil { + return module.Plan{}, err + } + return module.Plan{Actions: []module.Action{{ + Description: "hello force reapply (rewrite marker " + path + ")", + Kind: module.ActionFileWrite, + Exec: func(ctx context.Context) error { + if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil { + return err + } + return os.WriteFile(path, []byte(markerContent), 0o644) + }, + }}}, nil } diff --git a/internal/modules/hello/hello_test.go b/internal/modules/hello/hello_test.go index 3826fad..e2fd2f8 100644 --- a/internal/modules/hello/hello_test.go +++ b/internal/modules/hello/hello_test.go @@ -55,3 +55,31 @@ func TestHelloFullLifecycle(t *testing.T) { t.Fatalf("content = %q", data) } } + +func TestHelloPlanForceNonEmpty(t *testing.T) { + path := filepath.Join(t.TempDir(), "hello.ok") + m := Module{Path: path} + // Even after marker is present, force plan must run. + if err := os.WriteFile(path, []byte(markerContent), 0o644); err != nil { + t.Fatal(err) + } + plan, err := m.PlanForce(context.Background()) + if err != nil { + t.Fatalf("PlanForce: %v", err) + } + if plan.IsEmpty() { + t.Fatal("force plan must not be empty") + } + for _, a := range plan.Actions { + if err := a.Exec(context.Background()); err != nil { + t.Fatalf("Exec: %v", err) + } + } + data, err := os.ReadFile(path) + if err != nil { + t.Fatal(err) + } + if string(data) != markerContent { + t.Fatalf("content after force = %q", data) + } +}