package service import ( "fmt" "strings" "github.com/orchard9/rdev/internal/domain" ) // updateProcfile adds an entry for the component. func (s *ComponentService) updateProcfile(existing string, componentType domain.ComponentType, componentName, componentPath string, _ int) string { var entry string switch componentType { case domain.ComponentTypeService: entry = fmt.Sprintf("%s: cd %s && make run", componentName, componentPath) case domain.ComponentTypeWorker: entry = fmt.Sprintf("%s: cd %s && make run", componentName, componentPath) case domain.ComponentTypeAppAstro, domain.ComponentTypeAppReact: entry = fmt.Sprintf("%s: cd %s && npm run dev", componentName, componentPath) case domain.ComponentTypeCLI: // CLIs don't run as processes return existing } // Add the entry before any empty line at the end, or at the end lines := strings.Split(strings.TrimRight(existing, "\n"), "\n") lines = append(lines, entry) return strings.Join(lines, "\n") + "\n" } // updateGoWork adds a use directive for Go components. func (s *ComponentService) updateGoWork(existing, componentPath string) string { useLine := fmt.Sprintf("use ./%s", componentPath) // Check if already present if strings.Contains(existing, useLine) { return existing } // Find where to insert: after the last 'use' line or after 'go X.XX' lines := strings.Split(existing, "\n") insertIdx := len(lines) - 1 // Find the last use statement for i := len(lines) - 1; i >= 0; i-- { trimmed := strings.TrimSpace(lines[i]) if strings.HasPrefix(trimmed, "use ") { insertIdx = i + 1 break } if strings.HasPrefix(trimmed, "go ") { insertIdx = i + 1 } } // Insert the new use line newLines := make([]string, 0, len(lines)+1) newLines = append(newLines, lines[:insertIdx]...) newLines = append(newLines, useLine) newLines = append(newLines, lines[insertIdx:]...) return strings.Join(newLines, "\n") } // updateWoodpeckerYml inserts the component step at the COMPONENT_STEPS_BELOW marker. func (s *ComponentService) updateWoodpeckerYml(existing, stepYaml string) string { marker := "# COMPONENT_STEPS_BELOW" if !strings.Contains(existing, marker) { s.logger.Warn("COMPONENT_STEPS_BELOW marker not found in .woodpecker.yml") return existing } // Indent the step YAML properly (2 spaces for YAML steps) var sb strings.Builder lines := strings.Split(strings.TrimSpace(stepYaml), "\n") for _, line := range lines { sb.WriteString(" ") sb.WriteString(line) sb.WriteString("\n") } // Insert after the marker return strings.Replace(existing, marker, marker+"\n\n"+strings.TrimRight(sb.String(), "\n"), 1) } // updateClaudeMd adds the component to the routing table. func (s *ComponentService) updateClaudeMd(existing string, componentType domain.ComponentType, componentName, componentPath string) string { // Find the "## Components" section and add entry marker := "" var description string switch componentType { case domain.ComponentTypeService: description = "API service" case domain.ComponentTypeWorker: description = "Background worker" case domain.ComponentTypeAppAstro: description = "Astro app" case domain.ComponentTypeAppReact: description = "React app" case domain.ComponentTypeCLI: description = "CLI tool" } entry := fmt.Sprintf("| **%s** | %s | `%s/` |", componentName, description, componentPath) if strings.Contains(existing, marker) { // First component - replace the marker with a table table := fmt.Sprintf(`| Component | Type | Path | |-----------|------|------| %s `, entry) return strings.Replace(existing, marker, table, 1) } // Add to existing table - find the last table row in ## Components section lines := strings.Split(existing, "\n") inComponents := false insertIdx := -1 for i, line := range lines { if strings.HasPrefix(line, "## Components") { inComponents = true continue } if inComponents && strings.HasPrefix(line, "## ") { // End of Components section insertIdx = i break } if inComponents && strings.HasPrefix(line, "|") { insertIdx = i + 1 } } if insertIdx > 0 { // Insert the new entry newLines := make([]string, 0, len(lines)+1) newLines = append(newLines, lines[:insertIdx]...) newLines = append(newLines, entry) newLines = append(newLines, lines[insertIdx:]...) return strings.Join(newLines, "\n") } return existing } // removeProcfileEntry removes a component entry from the Procfile. func (s *ComponentService) removeProcfileEntry(procfile, componentName string) string { var lines []string for _, line := range strings.Split(procfile, "\n") { if !strings.HasPrefix(strings.TrimSpace(line), componentName+":") { lines = append(lines, line) } } return strings.Join(lines, "\n") } // removeGoWorkEntry removes a use directive from go.work. func (s *ComponentService) removeGoWorkEntry(goWork, componentPath string) string { useLine := "use ./" + componentPath var lines []string for _, line := range strings.Split(goWork, "\n") { if strings.TrimSpace(line) != useLine { lines = append(lines, line) } } return strings.Join(lines, "\n") }