feat: dependency cycle detection

Signed-off-by: Brian McGee <brian@bmcgee.ie>
This commit is contained in:
Brian McGee 2024-01-12 10:08:13 +00:00
parent d323715fa8
commit 23c86cee02
Signed by: brianmcgee
GPG Key ID: D49016E76AD1E8C0
2 changed files with 47 additions and 2 deletions

View File

@ -6,6 +6,7 @@ import (
"fmt"
"os"
"os/signal"
"strings"
"syscall"
"time"
@ -66,8 +67,7 @@ func (f *Format) Run() error {
formatters := make(map[string]*format.Formatter)
// detect dependency cycles and broken dependencies
// todo dependency cycle detection
// detect broken dependencies
for name, config := range cfg.Formatters {
before := config.Before
if before != "" {
@ -79,6 +79,30 @@ func (f *Format) Run() error {
}
}
// dependency cycle detection
for name, config := range cfg.Formatters {
var ok bool
var history []string
childName := name
for {
// add to history
history = append(history, childName)
if config.Before == "" {
break
} else if config.Before == name {
return fmt.Errorf("formatter cycle detected %v", strings.Join(history, " -> "))
}
// load child config
childName = config.Before
config, ok = cfg.Formatters[config.Before]
if !ok {
return fmt.Errorf("formatter not found: %v", config.Before)
}
}
}
// init formatters
for name, config := range cfg.Formatters {
if !includeFormatter(name) {

View File

@ -39,6 +39,27 @@ func TestAllowMissingFormatter(t *testing.T) {
as.NoError(err)
}
func TestDependencyCycle(t *testing.T) {
as := require.New(t)
tempDir := t.TempDir()
configPath := tempDir + "/treefmt.toml"
test.WriteConfig(t, configPath, format.Config{
Formatters: map[string]*format.FormatterConfig{
"a": {Command: "echo", Before: "b"},
"b": {Command: "echo", Before: "c"},
"c": {Command: "echo", Before: "a"},
"d": {Command: "echo", Before: "e"},
"e": {Command: "echo", Before: "f"},
"f": {Command: "echo"},
},
})
_, err := cmd(t, "--config-file", configPath, "--tree-root", tempDir)
as.ErrorContains(err, "formatter cycle detected a -> b -> c")
}
func TestSpecifyingFormatters(t *testing.T) {
as := require.New(t)