fix: respect hierarchy.max-depth config setting (GH#995) (#997)
* fix: respect hierarchy.max-depth config setting (GH#995) The hierarchy.max-depth config setting was being ignored because storage implementations had the depth limit hardcoded to 3. This fix: - Registers hierarchy.max-depth default (3) in config initialization - Adds hierarchy.max-depth to yaml-only keys for config.yaml storage - Updates SQLite and Memory storage to read max depth from config - Adds validation to reject hierarchy.max-depth values < 1 - Adds tests for configurable hierarchy depth Users can now set deeper hierarchies: bd config set hierarchy.max-depth 10 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * refactor: extract shared CheckHierarchyDepth function (GH#995) - Extract duplicated depth-checking logic to types.CheckHierarchyDepth() - Update sqlite and memory storage backends to use shared function - Add t.Cleanup() for proper test isolation in sqlite test - Add equivalent test coverage for memory storage backend - Add comprehensive unit tests for CheckHierarchyDepth function Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -6,6 +6,7 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -18,16 +19,16 @@ import (
|
||||
// at startup, not from SQLite).
|
||||
var YamlOnlyKeys = map[string]bool{
|
||||
// Bootstrap flags (affect how bd starts)
|
||||
"no-db": true,
|
||||
"no-daemon": true,
|
||||
"no-auto-flush": true,
|
||||
"no-auto-import": true,
|
||||
"json": true,
|
||||
"no-db": true,
|
||||
"no-daemon": true,
|
||||
"no-auto-flush": true,
|
||||
"no-auto-import": true,
|
||||
"json": true,
|
||||
"auto-start-daemon": true,
|
||||
|
||||
// Database and identity
|
||||
"db": true,
|
||||
"actor": true,
|
||||
"db": true,
|
||||
"actor": true,
|
||||
"identity": true,
|
||||
|
||||
// Timing settings
|
||||
@@ -36,14 +37,14 @@ var YamlOnlyKeys = map[string]bool{
|
||||
"remote-sync-interval": true,
|
||||
|
||||
// Git settings
|
||||
"git.author": true,
|
||||
"git.no-gpg-sign": true,
|
||||
"no-push": true,
|
||||
"no-git-ops": true, // Disable git ops in bd prime session close protocol (GH#593)
|
||||
"git.author": true,
|
||||
"git.no-gpg-sign": true,
|
||||
"no-push": true,
|
||||
"no-git-ops": true, // Disable git ops in bd prime session close protocol (GH#593)
|
||||
|
||||
// Sync settings
|
||||
"sync-branch": true,
|
||||
"sync.branch": true,
|
||||
"sync-branch": true,
|
||||
"sync.branch": true,
|
||||
"sync.require_confirmation_on_mass_delete": true,
|
||||
|
||||
// Daemon settings (GH#871: team-wide auto-sync config)
|
||||
@@ -64,6 +65,9 @@ var YamlOnlyKeys = map[string]bool{
|
||||
// Values: "warn" | "error" | "none"
|
||||
"validation.on-create": true,
|
||||
"validation.on-sync": true,
|
||||
|
||||
// Hierarchy settings (GH#995)
|
||||
"hierarchy.max-depth": true,
|
||||
}
|
||||
|
||||
// IsYamlOnlyKey returns true if the given key should be stored in config.yaml
|
||||
@@ -75,7 +79,7 @@ func IsYamlOnlyKey(key string) bool {
|
||||
}
|
||||
|
||||
// Check prefix matches for nested keys
|
||||
prefixes := []string{"routing.", "sync.", "git.", "directory.", "repos.", "external_projects.", "validation.", "daemon."}
|
||||
prefixes := []string{"routing.", "sync.", "git.", "directory.", "repos.", "external_projects.", "validation.", "daemon.", "hierarchy."}
|
||||
for _, prefix := range prefixes {
|
||||
if strings.HasPrefix(key, prefix) {
|
||||
return true
|
||||
@@ -105,6 +109,11 @@ func normalizeYamlKey(key string) string {
|
||||
// It handles both adding new keys and updating existing (possibly commented) keys.
|
||||
// Keys are normalized to their canonical yaml format (e.g., sync.branch -> sync-branch).
|
||||
func SetYamlConfig(key, value string) error {
|
||||
// Validate specific keys (GH#995)
|
||||
if err := validateYamlConfigValue(key, value); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
configPath, err := findProjectConfigYaml()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -274,3 +283,20 @@ func needsQuoting(s string) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// validateYamlConfigValue validates a configuration value before setting.
|
||||
// Returns an error if the value is invalid for the given key.
|
||||
func validateYamlConfigValue(key, value string) error {
|
||||
switch key {
|
||||
case "hierarchy.max-depth":
|
||||
// Must be a positive integer >= 1 (GH#995)
|
||||
depth, err := strconv.Atoi(value)
|
||||
if err != nil {
|
||||
return fmt.Errorf("hierarchy.max-depth must be a positive integer, got %q", value)
|
||||
}
|
||||
if depth < 1 {
|
||||
return fmt.Errorf("hierarchy.max-depth must be at least 1, got %d", depth)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user