Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
## Template Version Alignment
- Go: 1.23 → 1.25 across all templates (go.work, go.mod, Dockerfiles, CI)
- Alpine: latest → 3.19 (explicit version pinning)
- Woodpecker: failure:retry → failure:ignore (invalid syntax fix)
## SDLC Tree Fixes (slackpath-5-full-lifecycle)
Fixed merge failures by correcting lifecycle flow:
1. **Branch Creation**: Added missing create-branch step (planned → ready)
- Bug: Merge command requires feature.Branch field to be set
- Fix: POST /projects/{id}/sdlc/features/{slug}/branch
2. **Artifact Status**: Changed approval to pass for execution artifacts
- Bug: Review/audit/QA need status="passed" not "approved"
- Fix: /artifacts/{type}/approve → /artifacts/{type}/pass
- Added: pass-qa step after wait-qa
3. **Phase Transition Order**: Reordered merge phase transition
- Bug: Merge command checks if phase == "merge" first
- Fix: transition-to-merge BEFORE merge-feature (not after)
## GCS Provisioner Fix
- Replaced deprecated option.WithCredentialsFile with env var approach
- Now uses GOOGLE_APPLICATION_CREDENTIALS for ADC (Application Default Credentials)
- Avoids security risk from deprecated credential options
- Fixed test: Added ComponentTypeGCS to ValidComponentTypes test
## Critical Rules Added
- Version alignment: All template versions must stay in sync
- When updating versions, grep entire templates/ tree
## Files Changed
- 27 template files: Go version + Woodpecker syntax
- 1 tree file: SDLC lifecycle flow corrections
- 1 CLAUDE.md: Version alignment rule
- 1 GCS provisioner: Deprecated API fix
- 1 test file: Added missing component type
Root cause: Skeleton templates lagged behind Go 1.25 release and had
invalid Woodpecker syntax. SDLC tree skipped required branch creation
and used wrong artifact approval endpoints.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
124 lines
4.1 KiB
Go
124 lines
4.1 KiB
Go
// Package domain contains pure domain models with no external dependencies.
|
|
package domain
|
|
|
|
import "regexp"
|
|
|
|
// ComponentType represents the type of component in a monorepo.
|
|
type ComponentType string
|
|
|
|
const (
|
|
ComponentTypeService ComponentType = "service"
|
|
ComponentTypeWorker ComponentType = "worker"
|
|
ComponentTypeAppAstro ComponentType = "app-astro"
|
|
ComponentTypeAppReact ComponentType = "app-react"
|
|
ComponentTypeAppNextJS ComponentType = "app-nextjs"
|
|
ComponentTypeCLI ComponentType = "cli"
|
|
// Infrastructure component types - these trigger provisioning, not scaffolding.
|
|
ComponentTypePostgres ComponentType = "postgres"
|
|
ComponentTypeRedis ComponentType = "redis"
|
|
ComponentTypeGCS ComponentType = "gcs"
|
|
)
|
|
|
|
// ValidComponentTypes lists all valid component types.
|
|
var ValidComponentTypes = []ComponentType{
|
|
ComponentTypeService,
|
|
ComponentTypeWorker,
|
|
ComponentTypeAppAstro,
|
|
ComponentTypeAppReact,
|
|
ComponentTypeAppNextJS,
|
|
ComponentTypeCLI,
|
|
ComponentTypePostgres,
|
|
ComponentTypeRedis,
|
|
ComponentTypeGCS,
|
|
}
|
|
|
|
// IsValidComponentType checks if a string is a valid component type.
|
|
func IsValidComponentType(t string) bool {
|
|
for _, valid := range ValidComponentTypes {
|
|
if string(valid) == t {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// Component represents a component in a monorepo project.
|
|
type Component struct {
|
|
Type ComponentType `json:"type"`
|
|
Name string `json:"name"`
|
|
Path string `json:"path"` // e.g., "services/auth-api"
|
|
Port int `json:"port"` // 0 if not applicable
|
|
Template string `json:"template"` // template used
|
|
Dependencies []string `json:"dependencies"` // e.g., ["postgres", "redis"]
|
|
}
|
|
|
|
// DestDir returns the destination directory for this component type.
|
|
func (c ComponentType) DestDir() string {
|
|
switch c {
|
|
case ComponentTypeService:
|
|
return "services"
|
|
case ComponentTypeWorker:
|
|
return "workers"
|
|
case ComponentTypeAppAstro, ComponentTypeAppReact, ComponentTypeAppNextJS:
|
|
return "apps"
|
|
case ComponentTypeCLI:
|
|
return "cli"
|
|
default:
|
|
return ""
|
|
}
|
|
}
|
|
|
|
// StartingPort returns the starting port number for this component type.
|
|
// Workers and CLIs don't expose ports (return 0).
|
|
func (c ComponentType) StartingPort() int {
|
|
switch c {
|
|
case ComponentTypeService:
|
|
return 8001
|
|
case ComponentTypeAppAstro, ComponentTypeAppReact, ComponentTypeAppNextJS:
|
|
return 3001
|
|
case ComponentTypeWorker, ComponentTypeCLI:
|
|
return 0
|
|
default:
|
|
return 0
|
|
}
|
|
}
|
|
|
|
// NeedsPort returns true if this component type requires a port assignment.
|
|
func (c ComponentType) NeedsPort() bool {
|
|
return c == ComponentTypeService || c == ComponentTypeAppAstro || c == ComponentTypeAppReact || c == ComponentTypeAppNextJS
|
|
}
|
|
|
|
// IsGoComponent returns true if this component type uses Go (and needs go.work entry).
|
|
func (c ComponentType) IsGoComponent() bool {
|
|
return c == ComponentTypeService || c == ComponentTypeWorker || c == ComponentTypeCLI
|
|
}
|
|
|
|
// IsAppComponent returns true if this component type is a frontend app (and gets "/" path).
|
|
func (c ComponentType) IsAppComponent() bool {
|
|
return c == ComponentTypeAppAstro || c == ComponentTypeAppReact || c == ComponentTypeAppNextJS
|
|
}
|
|
|
|
// IsInfraComponent returns true if this component type is infrastructure (database, cache, storage).
|
|
// Infrastructure components trigger provisioning instead of template scaffolding.
|
|
func (c ComponentType) IsInfraComponent() bool {
|
|
return c == ComponentTypePostgres || c == ComponentTypeRedis || c == ComponentTypeGCS
|
|
}
|
|
|
|
// componentNameRegex validates component names (slug format: lowercase, alphanumeric, dashes).
|
|
var componentNameRegex = regexp.MustCompile(`^[a-z][a-z0-9-]*$`)
|
|
|
|
// ValidateComponentName validates that a component name is in slug format.
|
|
// Must be lowercase, start with a letter, and contain only letters, numbers, and dashes.
|
|
func ValidateComponentName(name string) error {
|
|
if name == "" {
|
|
return ErrInvalidComponentName
|
|
}
|
|
if len(name) > MaxProjectNameLen { // Reuse the 63-char limit from K8s
|
|
return ErrInvalidComponentName
|
|
}
|
|
if !componentNameRegex.MatchString(name) {
|
|
return ErrInvalidComponentName
|
|
}
|
|
return nil
|
|
}
|