Expand family publish policies into concrete rules

This commit is contained in:
2026-08-30 14:30:07 +00:00
parent c91599ef36
commit b5b1d22011
8 changed files with 100 additions and 3 deletions

View File

@@ -121,6 +121,9 @@ func expandPipelineArtifactFamilies(cfg *PipelineConfig, party ResolvedParty) er
catalog.Families[familyKey] = familyOrigin
}
cfg.Scriptorium.Artifacts = expanded
if err := expandFamilyPublishRules(cfg, catalog); err != nil {
return err
}
cfg.Scriptorium.ArtifactFamilies = nil
cfg.familyCatalog = catalog
cfg.resolution.artifactFamiliesExpanded = true
@@ -130,12 +133,71 @@ func expandPipelineArtifactFamilies(cfg *PipelineConfig, party ResolvedParty) er
if err := validateScriptorium(cfg.Scriptorium, cfg.Notarius); err != nil {
return err
}
if err := validatePublish(cfg.Publish, cfg.Scriptorium, cfg.Notarius); err != nil {
return err
}
if err := recomputePipelineEffectiveDigest(cfg); err != nil {
return fmt.Errorf("refresh expanded pipeline digest: %w", err)
}
return nil
}
func expandFamilyPublishRules(cfg *PipelineConfig, catalog ArtifactFamilyCatalog) error {
if cfg == nil || cfg.Scriptorium == nil {
return nil
}
if cfg.Publish == nil {
for familyKey, family := range catalog.Families {
if family.Publish != nil && family.Publish.Enabled {
return fmt.Errorf("pipeline.scriptorium.artifact_families.%s.publish requires pipeline.publish", familyKey)
}
}
return nil
}
generated := make([]PublishOutputRule, 0)
explicitSources := make(map[string]struct{}, len(cfg.Publish.Outputs))
for _, rule := range cfg.Publish.Outputs {
explicitSources[strings.TrimSpace(rule.Source)] = struct{}{}
}
for familyKey, family := range catalog.Families {
if family.Publish == nil || !family.Publish.Enabled {
continue
}
if cfg.resolution == nil || !cfg.resolution.publishDeclared {
return fmt.Errorf("pipeline.scriptorium.artifact_families.%s.publish requires pipeline.publish", familyKey)
}
pattern := strings.TrimSpace(family.Publish.DestPattern)
if pattern != "" {
if err := validateFamilyOutputPattern("pipeline.scriptorium.artifact_families."+familyKey+".publish.dest_pattern", pattern); err != nil {
return err
}
}
for _, key := range family.Members {
if _, conflict := explicitSources[artifactpolicy.ConfiguredSourceID(key)]; conflict {
return fmt.Errorf("pipeline.scriptorium.artifact_families.%s.publish conflicts with explicit publish source %q", familyKey, artifactpolicy.ConfiguredSourceID(key))
}
origin := catalog.Members[key]
dest := cfg.Scriptorium.Artifacts[key].OutputPath
if pattern != "" {
dest = strings.ReplaceAll(pattern, characterIDToken, origin.CharacterID)
}
required := family.Publish.Required
generated = append(generated, PublishOutputRule{Source: artifactpolicy.ConfiguredSourceID(key), Dest: dest, Required: &required})
}
}
if len(generated) == 0 {
return nil
}
cfg.Publish.Outputs = append(cfg.Publish.Outputs, generated...)
sort.Slice(cfg.Publish.Outputs, func(i, j int) bool {
if cfg.Publish.Outputs[i].Dest == cfg.Publish.Outputs[j].Dest {
return cfg.Publish.Outputs[i].Source < cfg.Publish.Outputs[j].Source
}
return cfg.Publish.Outputs[i].Dest < cfg.Publish.Outputs[j].Dest
})
return nil
}
func validateFamilyMemberDependencies(families map[string]ScriptoriumArtifactFamilyConfig, familyKeys []string) error {
for _, familyKey := range familyKeys {
family := families[familyKey]