package page import ( "fmt" "strings" "github.com/kovetskiy/mark/v16/confluence" "github.com/rs/zerolog/log" ) func EnsureAncestry( dryRun bool, api *confluence.API, space string, ancestry []string, ) (*confluence.PageInfo, error) { var parent *confluence.PageInfo rest := ancestry for i, title := range ancestry { page, err := api.FindPage(space, title, "page") if err != nil { return nil, fmt.Errorf("error during finding parent page with title %q: %w", title, err) } if page == nil { break } log.Debug().Msgf("parent page %q exists: %s", title, page.Links.Full) rest = ancestry[i:] parent = page } if parent != nil { rest = rest[1:] } else { page, err := api.FindRootPage(space) if err != nil { return nil, fmt.Errorf("can't find root page for space %q: %w", space, err) } parent = page } if len(rest) == 0 { return parent, nil } log.Debug(). Msgf( "empty pages under %q to be created: %s", parent.Title, strings.Join(rest, ` > `), ) if !dryRun { for _, title := range rest { page, err := api.CreatePage(space, "page", parent, title, ``) if err != nil { return nil, fmt.Errorf("error during creating parent page with title %q: %w", title, err) } parent = page } } else { log.Info(). Msgf( "skipping page creation due to enabled dry-run mode, "+ "need to create %d pages: %v", len(rest), rest, ) } return parent, nil } func ValidateAncestry( api *confluence.API, space string, ancestry []string, ) (*confluence.PageInfo, error) { page, err := api.FindPage(space, ancestry[len(ancestry)-1], "page") if err != nil { return nil, err } if page == nil { return nil, nil } isHomepage := false if len(page.Ancestors) < 1 { homepage, err := api.FindHomePage(space) if err != nil { return nil, fmt.Errorf("can't obtain home page from space %q: %w", space, err) } if page.ID == homepage.ID { log.Debug().Msgf("page is homepage for space %q", space) isHomepage = true } else { return nil, fmt.Errorf(`page %q has no parents`, page.Title) } } if !isHomepage && len(page.Ancestors) < len(ancestry) { actual := []string{} for _, ancestor := range page.Ancestors { actual = append(actual, ancestor.Title) } valid := false if len(actual) == len(ancestry)-1 { broken := false for i := 0; i < len(actual); i++ { if actual[i] != ancestry[i] { broken = true break } } if !broken { if ancestry[len(ancestry)-1] == page.Title { valid = true } } } if !valid { return nil, fmt.Errorf( "the page has fewer parents than expected: title=%q, actual=[%s], expected=[%s]", page.Title, strings.Join(actual, " > "), strings.Join(ancestry, " > "), ) } } for _, parent := range ancestry[:len(ancestry)-1] { found := false // skipping root article title for _, ancestor := range page.Ancestors { if ancestor.Title == parent { found = true break } } if !found { list := []string{} for _, ancestor := range page.Ancestors { list = append(list, ancestor.Title) } return nil, fmt.Errorf( "unexpected ancestry tree, did not find expected parent page %q in the tree: actual=[%s]", parent, strings.Join(list, "; "), ) } } return page, nil }