Derive family member publish destinations
This commit is contained in:
@@ -124,6 +124,7 @@ func expandPipelineArtifactFamilies(cfg *PipelineConfig, party ResolvedParty) er
|
||||
if err := expandFamilyPublishRules(cfg, catalog); err != nil {
|
||||
return err
|
||||
}
|
||||
applyMissingPublishDestinations(cfg.Publish, cfg.Scriptorium, cfg.Notarius)
|
||||
cfg.Scriptorium.ArtifactFamilies = nil
|
||||
cfg.familyCatalog = catalog
|
||||
cfg.resolution.artifactFamiliesExpanded = true
|
||||
|
||||
@@ -334,6 +334,82 @@ func TestFamilyPublishRulesExpandToConcreteArtifacts(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestExplicitFamilyMemberPublishDestinationResolution(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
writePartyResolutionFile(t, filepath.Join(dir, "party.yml"), `schema_version: narratio.party.v1
|
||||
characters:
|
||||
alice:
|
||||
player: {name: Alice Player}
|
||||
character:
|
||||
name: Alice
|
||||
classes: [{name: wizard}]
|
||||
`)
|
||||
|
||||
for _, test := range []struct {
|
||||
name string
|
||||
source string
|
||||
dest string
|
||||
wantDest string
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "derive generated member output",
|
||||
source: "narratio.artifact.meta_alice",
|
||||
wantDest: "artifacts/alice.md",
|
||||
},
|
||||
{
|
||||
name: "preserve explicit override",
|
||||
source: "narratio.artifact.meta_alice",
|
||||
dest: "published/alice-summary.md",
|
||||
wantDest: "published/alice-summary.md",
|
||||
},
|
||||
{
|
||||
name: "reject unknown source",
|
||||
source: "narratio.artifact.missing",
|
||||
wantErr: "is unsupported",
|
||||
},
|
||||
} {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
publishDestination := ""
|
||||
if test.dest != "" {
|
||||
publishDestination = " dest: " + test.dest + "\n"
|
||||
}
|
||||
pipeline := artifactFamilyPipelineYAML(`
|
||||
meta:
|
||||
enabled: true
|
||||
for_each: party.characters
|
||||
prompt_id: dnd.meta
|
||||
profile_id: production
|
||||
output_path_pattern: artifacts/{character_id}.md
|
||||
`) + `
|
||||
publish:
|
||||
outputs:
|
||||
- source: ` + test.source + "\n" + publishDestination
|
||||
pipelinePath, campaignPath, sessionPath := writeArtifactFamilyConfig(t, dir, pipeline)
|
||||
cfg, err := LoadWithSessionOptions(pipelinePath, campaignPath, sessionPath, SessionLoadOptions{})
|
||||
if test.wantErr != "" {
|
||||
if err == nil || !strings.Contains(err.Error(), test.wantErr) {
|
||||
t.Fatalf("LoadWithSessionOptions() error = %v, want %q", err, test.wantErr)
|
||||
}
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("LoadWithSessionOptions() error = %v", err)
|
||||
}
|
||||
if got := cfg.Pipeline.Publish.Outputs[0].Dest; got != test.wantDest {
|
||||
t.Fatalf("resolved runtime destination = %q, want %q", got, test.wantDest)
|
||||
}
|
||||
effective, err := MarshalEffectivePipeline(cfg.Pipeline)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !strings.Contains(string(effective), "dest: "+test.wantDest+"\n") {
|
||||
t.Fatalf("effective pipeline omitted resolved destination:\n%s", effective)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const validFamilyYAML = `
|
||||
character_meta:
|
||||
enabled: true
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
"strings"
|
||||
|
||||
configkit "gitea.maximumdirect.net/eric/ConfigKit"
|
||||
"gitea.maximumdirect.net/eric/narratio/internal/artifactpolicy"
|
||||
)
|
||||
|
||||
type pipelineResolutionMetadata struct {
|
||||
@@ -206,19 +205,10 @@ func resolvePipelineConfig(cfg *PipelineConfig, resolution *configkit.Resolution
|
||||
resolution.Record(configkit.Keys("notarius"), configkit.ChangeNormalization, "canonical Notarius configuration")
|
||||
}
|
||||
if cfg.Publish != nil {
|
||||
configuredOutputs := scriptoriumOutputPathMap(cfg.Scriptorium)
|
||||
extractionOutputs := notariusOutputKeySet(cfg.Notarius)
|
||||
for index := range cfg.Publish.Outputs {
|
||||
output := cfg.Publish.Outputs[index]
|
||||
if strings.TrimSpace(output.Dest) != "" {
|
||||
continue
|
||||
}
|
||||
destination, err := artifactpolicy.ResolvePublishedDestinationWithExtractions(strings.TrimSpace(output.Source), "", configuredOutputs, extractionOutputs)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
configkit.Normalize(resolution, configkit.Keys("publish", "outputs").Index(index).Key("dest"), &output.Dest, destination, "derived from publish source")
|
||||
cfg.Publish.Outputs[index] = output
|
||||
for _, derived := range deriveMissingPublishDestinations(cfg.Publish, cfg.Scriptorium, cfg.Notarius) {
|
||||
output := cfg.Publish.Outputs[derived.index]
|
||||
configkit.Normalize(resolution, configkit.Keys("publish", "outputs").Index(derived.index).Key("dest"), &output.Dest, derived.dest, "derived from publish source")
|
||||
cfg.Publish.Outputs[derived.index] = output
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -9,6 +9,36 @@ import (
|
||||
"gitea.maximumdirect.net/eric/narratio/internal/pathsafe"
|
||||
)
|
||||
|
||||
type derivedPublishDestination struct {
|
||||
index int
|
||||
dest string
|
||||
}
|
||||
|
||||
func deriveMissingPublishDestinations(cfg *PublishConfig, scriptorium *ScriptoriumConfig, notarius *NotariusConfig) []derivedPublishDestination {
|
||||
if cfg == nil {
|
||||
return nil
|
||||
}
|
||||
configuredOutputs := scriptoriumOutputPathMap(scriptorium)
|
||||
extractionOutputs := notariusOutputKeySet(notarius)
|
||||
derived := make([]derivedPublishDestination, 0)
|
||||
for index, output := range cfg.Outputs {
|
||||
if strings.TrimSpace(output.Dest) != "" {
|
||||
continue
|
||||
}
|
||||
dest, err := artifactpolicy.ResolvePublishedDestinationWithExtractions(strings.TrimSpace(output.Source), "", configuredOutputs, extractionOutputs)
|
||||
if err == nil {
|
||||
derived = append(derived, derivedPublishDestination{index: index, dest: dest})
|
||||
}
|
||||
}
|
||||
return derived
|
||||
}
|
||||
|
||||
func applyMissingPublishDestinations(cfg *PublishConfig, scriptorium *ScriptoriumConfig, notarius *NotariusConfig) {
|
||||
for _, derived := range deriveMissingPublishDestinations(cfg, scriptorium, notarius) {
|
||||
cfg.Outputs[derived.index].Dest = derived.dest
|
||||
}
|
||||
}
|
||||
|
||||
func validateStorage(cfg StorageConfig) error {
|
||||
backend := strings.ToLower(strings.TrimSpace(cfg.Backend))
|
||||
switch backend {
|
||||
|
||||
Reference in New Issue
Block a user