Fix wiki deploy

This commit is contained in:
2026-05-20 20:28:58 +02:00
parent c37b27b720
commit 282b5d271b
6 changed files with 78 additions and 13 deletions
+6
View File
@@ -244,6 +244,7 @@ topdata:
deploy_manifest: .wiki_deploy_manifest.json
deploy_edit_summary: Auto-generated from native builder
title_prefix_min_length: 3
status_listing_scope: all
autogen:
cache:
@@ -304,6 +305,11 @@ setting remains as a module-only compatibility alias when `consume_archives` is
not set. Stale cleanup is scoped to roots actually touched by extracted
resources, so the default module-only extraction does not prune assets.
`topdata.wiki.status_listing_scope` controls the generated wiki-status detail
pages. The default `all` writes both per-namespace listings and aggregate
`meta:wikistatus:<status>` listings. Use `namespace` when aggregate status
lists would be too large for the target NodeBB post limit.
GFF JSON extraction can merge selected fields and lists from the existing source
file instead of replacing the whole extracted document. Rules are matched by
`target` relative to `paths.source`; files without a matching rule keep the
+3
View File
@@ -47,6 +47,7 @@ const (
DefaultTopDataWikiMarkerFormat = "html_comments"
DefaultTopDataWikiPageMarkerPrefix = "sow-topdata-wiki"
DefaultTopDataWikiTitlePrefixMinLength = 3
DefaultTopDataWikiStatusListingScope = "all"
DefaultWikiDeployManifest = ".wiki_deploy_manifest.json"
DefaultWikiDeployEditSummary = "Auto-generated from native builder"
DefaultTopDataPackageHAK = "sow_top.hak"
@@ -249,6 +250,7 @@ func (p *Project) EffectiveConfig() EffectiveConfig {
TemplatesDir: defaultString(p.Config.TopData.Wiki.TemplatesDir, DefaultTopDataWikiTemplatesDir),
ManualSectionsDir: defaultString(p.Config.TopData.Wiki.ManualSectionsDir, DefaultTopDataWikiManualSectionsDir),
TitlePrefixMinLength: defaultInt(p.Config.TopData.Wiki.TitlePrefixMinLength, DefaultTopDataWikiTitlePrefixMinLength),
StatusListingScope: defaultString(p.Config.TopData.Wiki.StatusListingScope, DefaultTopDataWikiStatusListingScope),
StalePages: TopDataWikiStalePagesConfig{
Default: defaultString(p.Config.TopData.Wiki.StalePages.Default, DefaultTopDataWikiStaleDefault),
LiveCleanup: defaultString(p.Config.TopData.Wiki.StalePages.LiveCleanup, DefaultTopDataWikiStaleLiveCleanup),
@@ -485,6 +487,7 @@ func markMissingDefaults(provenance ConfigProvenance) {
"topdata.wiki.templates_dir": DefaultTopDataWikiTemplatesDir,
"topdata.wiki.manual_sections_dir": DefaultTopDataWikiManualSectionsDir,
"topdata.wiki.title_prefix_min_length": "3",
"topdata.wiki.status_listing_scope": DefaultTopDataWikiStatusListingScope,
"topdata.wiki.stale_pages.default": DefaultTopDataWikiStaleDefault,
"topdata.wiki.stale_pages.live_cleanup": DefaultTopDataWikiStaleLiveCleanup,
"topdata.wiki.managed_region.marker_format": DefaultTopDataWikiMarkerFormat,
+6
View File
@@ -232,6 +232,7 @@ type TopDataWikiConfig struct {
TemplatesDir string `json:"templates_dir" yaml:"templates_dir"`
ManualSectionsDir string `json:"manual_sections_dir" yaml:"manual_sections_dir"`
TitlePrefixMinLength int `json:"title_prefix_min_length" yaml:"title_prefix_min_length"`
StatusListingScope string `json:"status_listing_scope" yaml:"status_listing_scope"`
StalePages TopDataWikiStalePagesConfig `json:"stale_pages" yaml:"stale_pages"`
ManagedRegion TopDataWikiManagedRegionConfig `json:"managed_region" yaml:"managed_region"`
}
@@ -594,6 +595,11 @@ func (p *Project) ValidateLayout() error {
if effective.TopData.Wiki.TitlePrefixMinLength < 1 {
failures = append(failures, fmt.Errorf("topdata.wiki.title_prefix_min_length must be at least 1"))
}
switch effective.TopData.Wiki.StatusListingScope {
case "all", "namespace":
default:
failures = append(failures, fmt.Errorf("topdata.wiki.status_listing_scope %q is not supported", effective.TopData.Wiki.StatusListingScope))
}
for key, policy := range map[string]string{
"topdata.wiki.stale_pages.default": effective.TopData.Wiki.StalePages.Default,
"topdata.wiki.stale_pages.live_cleanup": effective.TopData.Wiki.StalePages.LiveCleanup,
+13 -7
View File
@@ -278,6 +278,7 @@ topdata:
deploy_manifest: wiki-manifest.json
deploy_edit_summary: Custom summary
title_prefix_min_length: 4
status_listing_scope: namespace
stale_pages:
default: report
live_cleanup: archive
@@ -361,6 +362,9 @@ autogen:
if got, want := effective.TopData.Wiki.TitlePrefixMinLength, 4; got != want {
t.Fatalf("expected wiki title prefix minimum length %d, got %d", want, got)
}
if got, want := effective.TopData.Wiki.StatusListingScope, "namespace"; got != want {
t.Fatalf("expected wiki status listing scope %q, got %q", want, got)
}
if got, want := effective.Autogen.Cache.MaxAge, "30m"; got != want {
t.Fatalf("expected autogen cache max age %q, got %q", want, got)
}
@@ -866,13 +870,14 @@ func TestValidateLayoutRejectsInvalidTopDataWikiConfig(t *testing.T) {
TopData: TopDataConfig{
Source: "topdata",
Wiki: TopDataWikiConfig{
Source: "../wiki",
Renderer: "dokuwiki",
LinkStrategy: "rewrite_links",
NamespacesFile: "../namespaces.yaml",
TablesFile: "../tables.yaml",
TemplatesDir: ".",
ManualSectionsDir: "../manual",
Source: "../wiki",
Renderer: "dokuwiki",
LinkStrategy: "rewrite_links",
StatusListingScope: "global",
NamespacesFile: "../namespaces.yaml",
TablesFile: "../tables.yaml",
TemplatesDir: ".",
ManualSectionsDir: "../manual",
StalePages: TopDataWikiStalePagesConfig{
Default: "delete",
LiveCleanup: "delete",
@@ -890,6 +895,7 @@ func TestValidateLayoutRejectsInvalidTopDataWikiConfig(t *testing.T) {
"topdata.wiki.source",
"topdata.wiki.renderer",
"topdata.wiki.link_strategy",
"topdata.wiki.status_listing_scope",
"topdata.wiki.namespaces_file",
"topdata.wiki.tables_file",
"topdata.wiki.templates_dir",
+11 -6
View File
@@ -197,7 +197,7 @@ func buildWiki(p *project.Project, nativeResult BuildResult, force bool, progres
if err := generateEntityPages(outputDir, ctx, writePage); err != nil {
return wikiResult{}, err
}
if err := generateStatusPages(outputDir, pageStatuses, pageTitles, p.EffectiveConfig().TopData.Wiki.ManagedNamespaces, manualSections); err != nil {
if err := generateStatusPages(outputDir, pageStatuses, pageTitles, p.EffectiveConfig().TopData.Wiki.ManagedNamespaces, p.EffectiveConfig().TopData.Wiki.StatusListingScope, manualSections); err != nil {
return wikiResult{}, err
}
if err := indexUnregisteredWikiPages(rootDir, outputDir, p.EffectiveConfig().TopData.Wiki.StalePages.Default, &pageIndex); err != nil {
@@ -1427,7 +1427,7 @@ func wikiStatusNoun(category string) string {
}
}
func generateStatusPages(outputDir string, pageStatuses map[string]string, pageTitles map[string]string, namespaces []string, manualSections []wikiManualSection) error {
func generateStatusPages(outputDir string, pageStatuses map[string]string, pageTitles map[string]string, namespaces []string, listingScope string, manualSections []wikiManualSection) error {
summaries := buildWikiNamespaceSummaries(pageStatuses, namespaces)
if err := writeWikiFile(filepath.Join(outputDir, "meta", "wikistatus.html"), renderWikiStatusReportPage(summaries, namespaces), manualSections); err != nil {
return err
@@ -1444,10 +1444,15 @@ func generateStatusPages(outputDir string, pageStatuses map[string]string, pageT
}
}
}
for _, status := range []string{wikiStatusNew, wikiStatusModified, wikiStatusVanilla} {
pageIDs := filterWikiPageIDs(pageStatuses, "", status)
if err := writeWikiFile(filepath.Join(outputDir, "meta", "wikistatus", status+".html"), renderWikiStatusListingPage(wikiStatusLabels[status]+" Pages", pageIDs, pageTitles), manualSections); err != nil {
return err
if listingScope == "" {
listingScope = project.DefaultTopDataWikiStatusListingScope
}
if listingScope == "all" {
for _, status := range []string{wikiStatusNew, wikiStatusModified, wikiStatusVanilla} {
pageIDs := filterWikiPageIDs(pageStatuses, "", status)
if err := writeWikiFile(filepath.Join(outputDir, "meta", "wikistatus", status+".html"), renderWikiStatusListingPage(wikiStatusLabels[status]+" Pages", pageIDs, pageTitles), manualSections); err != nil {
return err
}
}
}
return nil
+39
View File
@@ -115,6 +115,45 @@ func TestBuildNativeGeneratesAndSkipsWikiPages(t *testing.T) {
}
}
func TestBuildNativeCanOmitAggregateWikiStatusListings(t *testing.T) {
root := testProjectRoot(t)
mkdirAll(t, filepath.Join(root, "topdata", "data", "skills"))
writeFile(t, filepath.Join(root, "topdata", "base_dialog.json"), "{}\n")
writeFile(t, filepath.Join(root, "topdata", "data", "skills", "base.json"), `{
"output": "skills.2da",
"columns": ["Label", "Name", "Description", "HideFromLevelUp", "Untrained", "KeyAbility", "ArmorCheckPenalty", "Constant"],
"rows": [
{
"id": 0,
"key": "skills:athletics",
"Label": "Athletics",
"Name": {"tlk": {"key": "skills:athletics.name", "text": "Athletics"}},
"Description": {"tlk": {"key": "skills:athletics.description", "text": "Ability: Strength."}},
"HideFromLevelUp": "0",
"Untrained": "1",
"KeyAbility": "STR",
"ArmorCheckPenalty": "1",
"Constant": "SKILL_ATHLETICS"
}
]
}`+"\n")
writeFile(t, filepath.Join(root, "topdata", "data", "skills", "lock.json"), `{"skills:athletics":0}`+"\n")
proj := testProject(root)
proj.Config.TopData.ReferenceBuilder = ""
proj.Config.TopData.Wiki.StatusListingScope = "namespace"
if _, err := BuildNative(proj, nil); err != nil {
t.Fatalf("BuildNative failed: %v", err)
}
if _, err := os.Stat(filepath.Join(root, ".cache", "wiki", "pages", "meta", "wikistatus", "skills", "vanilla.html")); err != nil {
t.Fatalf("expected namespace status listing to be generated: %v", err)
}
if _, err := os.Stat(filepath.Join(root, ".cache", "wiki", "pages", "meta", "wikistatus", "vanilla.html")); !os.IsNotExist(err) {
t.Fatalf("expected aggregate status listing to be omitted, got err=%v", err)
}
}
func countGeneratedWikiHTMLFiles(t *testing.T, root string) int {
t.Helper()
count := 0