Skip to content

Supply a Cobra command tree

docscheck takes a docscheck.Command tree and imports no CLI framework of its own; TestDependencyFootprint enforces that. Converting from Cobra is a short recursive function.

The conversion

func tree(c *cobra.Command) docscheck.Command {
    n := docscheck.Command{Name: c.Name()}
    for _, sub := range c.Commands() {
        n.Sub = append(n.Sub, tree(sub))
    }

    return n
}

c.Commands() returns the child commands, so this walks the whole tree. Call it on your root:

root, _ := root.NewCmdRoot(version.Info{})
checker, err := docscheck.New(tree(root.Command))

Get the root's name right

The root's Name is what a reader types, and docscheck looks for exactly that word in your documentation. Cobra derives Name() from the first word of Use, so a root with Use: "krites" gives krites. A root whose Use is empty gives "", which New rejects with ErrNoTool; one whose Use is something other than what your docs say (krites-cli, say) is accepted and then matches nothing. Check it:

if root.Name() != "krites" {
    t.Fatalf("unexpected root name %q", root.Name())
}

Hidden and generated commands

Cobra's Commands() includes hidden commands, so the function above keeps them. A command being hidden does not stop someone documenting it, and dropping a hidden subcommand of a visible group makes every documented use of it a finding.

help and completion are different. Cobra adds them when the root executes (ExecuteC), so a root you have only constructed does not have them, and documentation that mentions completion is ignored rather than flagged, because the word matches nothing in the tree. If you want those pages checked, append them to the root's Sub yourself.

Other frameworks

Nothing here is Cobra-specific. Any framework that can enumerate a command and its children converts the same way. Build docscheck.Command values and hand the root to New.