package sdlc import ( "fmt" "os" "slices" "gopkg.in/yaml.v3" ) // Config represents the project SDLC configuration in .sdlc/config.yaml. type Config struct { Version int `yaml:"version" json:"version"` Project ProjectConfig `yaml:"project" json:"project"` Branches BranchConfig `yaml:"branches" json:"branches"` Phases PhaseConfig `yaml:"phases" json:"phases"` Compliance ComplianceConfig `yaml:"compliance" json:"compliance"` Patterns PatternsConfig `yaml:"patterns,omitempty" json:"patterns,omitempty"` //nolint:omitzero } // ProjectConfig holds project-level settings. type ProjectConfig struct { Name string `yaml:"name" json:"name"` Type string `yaml:"type,omitempty" json:"type,omitempty"` } // BranchConfig defines branch naming conventions. type BranchConfig struct { Main string `yaml:"main" json:"main"` FeaturePrefix string `yaml:"feature_prefix" json:"feature_prefix"` } // PhaseConfig defines which phases are enabled and what artifacts are required. type PhaseConfig struct { Enabled []FeaturePhase `yaml:"enabled" json:"enabled"` RequiredArtifacts map[FeaturePhase][]ArtifactType `yaml:"required_artifacts" json:"required_artifacts"` } // ComplianceConfig defines approval and gate requirements. type ComplianceConfig struct { RequireApprovals bool `yaml:"require_approvals" json:"require_approvals"` RequireBranch bool `yaml:"require_branch" json:"require_branch"` RequireQA bool `yaml:"require_qa" json:"require_qa"` } // PatternsConfig defines pattern enforcement. type PatternsConfig struct { AutoEnforce []string `yaml:"auto_enforce,omitempty" json:"auto_enforce,omitempty"` } // LoadConfig reads and parses .sdlc/config.yaml from the given project root. func LoadConfig(root string) (*Config, error) { path := ConfigPath(root) data, err := os.ReadFile(path) if err != nil { if os.IsNotExist(err) { return nil, ErrNotInitialized } return nil, fmt.Errorf("read config file: %w", err) } var c Config if err := yaml.Unmarshal(data, &c); err != nil { return nil, fmt.Errorf("parse config file: %w", err) } return &c, nil } // Save writes the config to .sdlc/config.yaml. func (c *Config) Save(root string) error { data, err := yaml.Marshal(c) if err != nil { return fmt.Errorf("marshal config: %w", err) } path := ConfigPath(root) if err := os.WriteFile(path, data, 0o644); err != nil { return fmt.Errorf("write config file: %w", err) } return nil } // DefaultConfig returns a config with all phases enabled and standard requirements. func DefaultConfig(projectName string) *Config { return &Config{ Version: 1, Project: ProjectConfig{ Name: projectName, }, Branches: BranchConfig{ Main: "main", FeaturePrefix: "feature/", }, Phases: PhaseConfig{ Enabled: ValidPhases, RequiredArtifacts: map[FeaturePhase][]ArtifactType{ PhaseSpecified: {ArtifactSpec}, PhasePlanned: {ArtifactSpec, ArtifactDesign, ArtifactTasks, ArtifactQAPlan}, PhaseReview: {ArtifactReview}, PhaseAudit: {ArtifactAudit}, PhaseQA: {ArtifactQAResults}, }, }, Compliance: ComplianceConfig{ RequireApprovals: true, RequireBranch: true, RequireQA: true, }, } } // IsPhaseEnabled returns true if the phase is in the enabled list. func (c *Config) IsPhaseEnabled(phase FeaturePhase) bool { return slices.Contains(c.Phases.Enabled, phase) }