package deployer import ( "fmt" "github.com/alexei/tinyforge/internal/store" ) // validatePromoteFrom checks that a tag is running in the promote_from stage // before allowing it to be deployed to the target stage. // Returns nil if no promote_from is configured or if the tag is eligible. func (d *Deployer) validatePromoteFrom(stage store.Stage, imageTag string) error { if stage.PromoteFrom == "" { return nil } // Look up the source stage by name within the same project. stages, err := d.store.GetStagesByProjectID(stage.ProjectID) if err != nil { return fmt.Errorf("get stages for project: %w", err) } var sourceStage *store.Stage for _, s := range stages { if s.Name == stage.PromoteFrom { sCopy := s sourceStage = &sCopy break } } if sourceStage == nil { return fmt.Errorf("promote_from stage %q not found in project", stage.PromoteFrom) } // Check if the tag is running in the source stage. containers, err := d.store.ListContainersByStageID(sourceStage.ID) if err != nil { return fmt.Errorf("get containers for source stage: %w", err) } for _, c := range containers { if c.ImageTag == imageTag && (c.State == "running" || c.State == "stopped") { return nil // Tag found in source stage, promotion is allowed. } } return fmt.Errorf("tag %q is not running in stage %q; promotion denied", imageTag, stage.PromoteFrom) }