Expand family publish policies into concrete rules
This commit is contained in:
@@ -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]
|
||||
|
||||
@@ -297,6 +297,35 @@ func TestArtifactFamiliesRejectInvalidMemberDependenciesAndSources(t *testing.T)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFamilyPublishRulesExpandToConcreteArtifacts(t *testing.T) {
|
||||
required := true
|
||||
cfg := &PipelineConfig{
|
||||
Scriptorium: &ScriptoriumConfig{Artifacts: map[string]ScriptoriumArtifactConfig{
|
||||
"character_meta_alpha": {OutputPath: "artifacts/characters/alpha/meta.md"},
|
||||
"character_meta_zeta": {OutputPath: "artifacts/characters/zeta/meta.md"},
|
||||
}},
|
||||
Publish: &PublishConfig{},
|
||||
resolution: &pipelineResolutionMetadata{publishDeclared: true},
|
||||
}
|
||||
catalog := ArtifactFamilyCatalog{Families: map[string]ArtifactFamilyOrigin{
|
||||
"character_meta": {Members: []string{"character_meta_alpha", "character_meta_zeta"}, Publish: &ScriptoriumArtifactFamilyPublishConfig{Enabled: true, Required: required, DestPattern: "published/{character_id}.md"}},
|
||||
}, Members: map[string]ArtifactFamilyMemberOrigin{
|
||||
"character_meta_alpha": {CharacterID: "alpha"}, "character_meta_zeta": {CharacterID: "zeta"},
|
||||
}}
|
||||
if err := expandFamilyPublishRules(cfg, catalog); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got := cfg.Publish.Outputs; len(got) != 2 || got[0].Source != "narratio.artifact.character_meta_alpha" || got[0].Dest != "published/alpha.md" || got[0].Required == nil || !*got[0].Required {
|
||||
t.Fatalf("generated publish rules = %#v", got)
|
||||
}
|
||||
cfg.Publish.Outputs = nil
|
||||
catalog.Families["character_meta"] = ArtifactFamilyOrigin{Members: []string{"character_meta_alpha"}, Publish: &ScriptoriumArtifactFamilyPublishConfig{Enabled: true}}
|
||||
cfg.resolution.publishDeclared = false
|
||||
if err := expandFamilyPublishRules(cfg, catalog); err == nil || !strings.Contains(err.Error(), "requires pipeline.publish") {
|
||||
t.Fatalf("missing publish error = %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
const validFamilyYAML = `
|
||||
character_meta:
|
||||
enabled: true
|
||||
|
||||
@@ -31,6 +31,7 @@ func LoadPipelineWithOptions(path string, opts PipelineLoadOptions) (*PipelineCo
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("load pipeline config: %w", err)
|
||||
}
|
||||
cfg.resolution.publishDeclared = cfg.Publish != nil
|
||||
applyPipelineDefaults(cfg)
|
||||
if err := resolveNotariusPaths(cfg, path); err != nil {
|
||||
return nil, fmt.Errorf("load pipeline config: %w", err)
|
||||
|
||||
@@ -21,6 +21,7 @@ type pipelineResolutionMetadata struct {
|
||||
ownership []pipelineFieldOwnership
|
||||
artifactFamilies map[string]ScriptoriumArtifactFamilyConfig
|
||||
artifactFamiliesExpanded bool
|
||||
publishDeclared bool
|
||||
}
|
||||
|
||||
type pipelineProfileSelection struct {
|
||||
|
||||
Reference in New Issue
Block a user