From 7014dacd411abc7647577dde45fc395894ca0023 Mon Sep 17 00:00:00 2001 From: ychampion Date: Thu, 9 Jul 2026 08:22:51 +0000 Subject: [PATCH] allow tests to reset dependency cache Expose mg.ResetDeps for tests that run multiple Mage targets in one process without changing normal once-per-run dependency semantics. Constraint: Issue #524 needs a way for same-process tests to rerun dependency functions. Rejected: clearing the cache automatically between Deps calls | that would change normal Mage dependency semantics. Confidence: high Scope-risk: narrow Directive: Do not call ResetDeps while dependencies are running; it only clears the process-global dependency cache. Tested: go test ./mg -run TestResetDepsAllowsDependenciesToRunAgain -count=1; go test ./mg -count=1; GOPATH="/root/go" go test -vet=all -tags CI -race ./... -count=1; golangci-lint run ./...; git diff --check Not-tested: full GitHub Actions matrix --- mg/deps.go | 15 +++++++++++++++ mg/deps_test.go | 19 +++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/mg/deps.go b/mg/deps.go index bed1a972..baf1bef8 100644 --- a/mg/deps.go +++ b/mg/deps.go @@ -44,11 +44,26 @@ func (o *onceMap) LoadOrStore(f Fn) *onceFun { return one } +func (o *onceMap) Reset() { + o.mu.Lock() + defer o.mu.Unlock() + + o.m = map[onceKey]*onceFun{} +} + var onces = &onceMap{ mu: &sync.Mutex{}, m: map[onceKey]*onceFun{}, } +// ResetDeps clears the dependency cache used by Deps, CtxDeps, SerialDeps, and +// SerialCtxDeps. It is intended for tests that need to run the same dependencies +// more than once in a single process. Do not call ResetDeps while dependencies +// are running. +func ResetDeps() { + onces.Reset() +} + // SerialDeps is like Deps except it runs each dependency serially, instead of // in parallel. This can be useful for resource intensive dependencies that // shouldn't be run at the same time. diff --git a/mg/deps_test.go b/mg/deps_test.go index fe39bbb2..07aba82e 100644 --- a/mg/deps_test.go +++ b/mg/deps_test.go @@ -29,6 +29,25 @@ func TestDepsRunOnce(t *testing.T) { } } +func TestResetDepsAllowsDependenciesToRunAgain(t *testing.T) { + var calls int64 + f := func() { + atomic.AddInt64(&calls, 1) + } + + Deps(f) + Deps(f) + if calls != 1 { + t.Fatalf("expected dependency to run once before reset, ran %d times", calls) + } + + ResetDeps() + Deps(f) + if calls != 2 { + t.Fatalf("expected dependency to run again after reset, ran %d times", calls) + } +} + func TestDepsOfDeps(t *testing.T) { ch := make(chan string, 3) // this->f->g->h