Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add DocGen command #1688

Merged
merged 13 commits into from
Sep 27, 2023
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
Management of holds is internal, but there are queries for looking up holds on accounts.
Holds are also reflected in the `x/bank` module's `SpendableBalances` query.
* Add new MaxSupply param to marker module and deprecate MaxTotalSupply. [#1292](https://github.com/provenance-io/provenance/issues/1292).
* Add hidden docgen command to output documentation in different formats. [#1468](https://github.com/provenance-io/provenance/issues/1468).

### Improvements

Expand Down
103 changes: 103 additions & 0 deletions cmd/provenanced/cmd/docgen.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package cmd

import (
"fmt"
"os"

"github.com/spf13/cobra"
"github.com/spf13/cobra/doc"

"github.com/cosmos/cosmos-sdk/version"
)

var docGenCmdStart = fmt.Sprintf("%s docgen", version.AppName)

const (
FlagMarkdown = "markdown"
FlagYaml = "yaml"
FlagRst = "rst"
FlagManpage = "manpage"
)

func GetDocGenCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "docgen <target directory> (--markdown) (--yaml) (--rst) (--manpages) [flags]",
Short: "Generates cli documentation for the Provenance Blockchain.",
Long: `Generates cli documentation for the Provenance Blockchain.
Various documentation formats can be generated, including markdown, YAML, RST, and man pages.
To ensure the command's success, you must specify at least one format.
A successful command will not only generate files in the selected formats but also create the target directory if it doesn't already exist.`,
Example: fmt.Sprintf("%s '/tmp' --yaml --markdown", docGenCmdStart),
Hidden: true,
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
markdown, err := cmd.Flags().GetBool(FlagMarkdown)
if err != nil {
return err
}

Check warning on line 37 in cmd/provenanced/cmd/docgen.go

View check run for this annotation

Codecov / codecov/patch

cmd/provenanced/cmd/docgen.go#L36-L37

Added lines #L36 - L37 were not covered by tests
yaml, err := cmd.Flags().GetBool(FlagYaml)
if err != nil {
return err
}

Check warning on line 41 in cmd/provenanced/cmd/docgen.go

View check run for this annotation

Codecov / codecov/patch

cmd/provenanced/cmd/docgen.go#L40-L41

Added lines #L40 - L41 were not covered by tests
rst, err := cmd.Flags().GetBool(FlagRst)
if err != nil {
return err
}

Check warning on line 45 in cmd/provenanced/cmd/docgen.go

View check run for this annotation

Codecov / codecov/patch

cmd/provenanced/cmd/docgen.go#L44-L45

Added lines #L44 - L45 were not covered by tests
manpage, err := cmd.Flags().GetBool(FlagManpage)
if err != nil {
return err
}

Check warning on line 49 in cmd/provenanced/cmd/docgen.go

View check run for this annotation

Codecov / codecov/patch

cmd/provenanced/cmd/docgen.go#L48-L49

Added lines #L48 - L49 were not covered by tests

if !markdown && !yaml && !rst && !manpage {
return fmt.Errorf("at least one doc type must be specified")
}

dir := args[0]
if !exists(dir) {
err = os.Mkdir(dir, 0755)
if err != nil {
return err
}
}

if markdown {
err = doc.GenMarkdownTree(cmd.Root(), dir)
if err != nil {
return err
}

Check warning on line 67 in cmd/provenanced/cmd/docgen.go

View check run for this annotation

Codecov / codecov/patch

cmd/provenanced/cmd/docgen.go#L66-L67

Added lines #L66 - L67 were not covered by tests
}
if yaml {
err = doc.GenYamlTree(cmd.Root(), dir)
if err != nil {
return err
}

Check warning on line 73 in cmd/provenanced/cmd/docgen.go

View check run for this annotation

Codecov / codecov/patch

cmd/provenanced/cmd/docgen.go#L72-L73

Added lines #L72 - L73 were not covered by tests
}
if rst {
err = doc.GenReSTTree(cmd.Root(), dir)
if err != nil {
return err
}

Check warning on line 79 in cmd/provenanced/cmd/docgen.go

View check run for this annotation

Codecov / codecov/patch

cmd/provenanced/cmd/docgen.go#L78-L79

Added lines #L78 - L79 were not covered by tests
}
if manpage {
err = doc.GenManTree(cmd.Root(), nil, dir)
if err != nil {
return err
}

Check warning on line 85 in cmd/provenanced/cmd/docgen.go

View check run for this annotation

Codecov / codecov/patch

cmd/provenanced/cmd/docgen.go#L84-L85

Added lines #L84 - L85 were not covered by tests
}

return nil
},
}

cmd.Flags().Bool(FlagMarkdown, false, "Generate documentation in the format of markdown pages.")
cmd.Flags().Bool(FlagYaml, false, "Generate documentation in the format of yaml.")
cmd.Flags().Bool(FlagRst, false, "Generate documentation in the format of rst.")
cmd.Flags().Bool(FlagManpage, false, "Generate documentation in the format of manpages.")

return cmd
}

func exists(dir string) bool {
_, err := os.Stat(dir)
return err == nil
}
186 changes: 186 additions & 0 deletions cmd/provenanced/cmd/docgen_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
package cmd_test

import (
"context"
"fmt"
"os"
"path/filepath"
"strings"
"testing"

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/server"
sdksim "github.com/cosmos/cosmos-sdk/simapp"
genutiltest "github.com/cosmos/cosmos-sdk/x/genutil/client/testutil"
provenancecmd "github.com/provenance-io/provenance/cmd/provenanced/cmd"
"github.com/spf13/viper"
"github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/libs/log"
)

func TestDocGen(t *testing.T) {
tests := []struct {
name string
target string
createTarget bool
flags []string
err string
extensions []string
}{
{
name: "failure - no flags specified",
target: "tmp",
createTarget: true,
err: "at least one doc type must be specified",
},
{
name: "failure - unsupported flag format",
target: "tmp",
flags: []string{"--bad"},
createTarget: true,
err: "unknown flag: --bad",
},
{
name: "failure - invalid target directory",
target: "/tmp/tmp2/tmp3",
flags: []string{"--yaml"},
createTarget: false,
err: "mkdir %s: no such file or directory",
},
{
name: "failure - bad yaml value",
target: "tmp",
createTarget: true,
flags: []string{"--yaml=xyz"},
err: "invalid argument \"xyz\" for \"--yaml\" flag: strconv.ParseBool: parsing \"xyz\": invalid syntax",
},
{
name: "failure - bad rst value",
target: "tmp",
createTarget: true,
flags: []string{"--rst=xyz"},
err: "invalid argument \"xyz\" for \"--rst\" flag: strconv.ParseBool: parsing \"xyz\": invalid syntax",
},
{
name: "failure - bad markdown value",
target: "tmp",
createTarget: true,
flags: []string{"--markdown=xyz"},
err: "invalid argument \"xyz\" for \"--markdown\" flag: strconv.ParseBool: parsing \"xyz\": invalid syntax",
},
{
name: "failure - bad manpage value",
target: "tmp",
createTarget: true,
flags: []string{"--manpage=xyz"},
err: "invalid argument \"xyz\" for \"--manpage\" flag: strconv.ParseBool: parsing \"xyz\": invalid syntax",
},
{
name: "success - yaml is generated",
target: "tmp",
createTarget: true,
flags: []string{"--yaml"},
extensions: []string{".yaml"},
},
{
name: "success - rst is generated",
target: "tmp",
createTarget: true,
flags: []string{"--rst"},
extensions: []string{".rst"},
},
{
name: "success - manpage is generated",
target: "tmp",
createTarget: true,
flags: []string{"--manpage"},
extensions: []string{".1"},
},
{
name: "success - markdown is generated",
target: "tmp",
createTarget: true,
flags: []string{"--markdown"},
extensions: []string{".md"},
},
{
name: "success - multiple types supported",
target: "tmp",
createTarget: true,
flags: []string{"--markdown", "--yaml"},
extensions: []string{".md", ".yaml"},
},
{
name: "success - generates a new directory",
target: "tmp2",
createTarget: false,
flags: []string{"--yaml"},
extensions: []string{".md", ".yaml"},
},
}

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
home := t.TempDir()

targetPath := filepath.Join(home, tc.target)
if tc.createTarget {
require.NoError(t, os.Mkdir(targetPath, 0755), "Mkdir successfully created directory")
}

logger := log.NewNopLogger()
cfg, err := genutiltest.CreateDefaultTendermintConfig(home)
require.NoError(t, err, "Created default tendermint config")

appCodec := sdksim.MakeTestEncodingConfig().Codec
err = genutiltest.ExecInitCmd(testMbm, home, appCodec)
require.NoError(t, err, "Executed init command")

serverCtx := server.NewContext(viper.New(), cfg, logger)
clientCtx := client.Context{}.WithCodec(appCodec).WithHomeDir(home)

ctx := context.Background()
ctx = context.WithValue(ctx, client.ClientContextKey, &clientCtx)
ctx = context.WithValue(ctx, server.ServerContextKey, serverCtx)

cmd := provenancecmd.GetDocGenCmd()
args := append([]string{targetPath}, tc.flags...)
cmd.SetArgs(args)

if len(tc.err) > 0 {
err := cmd.ExecuteContext(ctx)
require.Error(t, err, "should throw an error")
expected := tc.err
if strings.Contains(expected, "%s") {
expected = fmt.Sprintf(expected, targetPath)
}
require.Equal(t, expected, err.Error(), "should return the correct error")
files, err := os.ReadDir(targetPath)
if err != nil {
require.Equal(t, 0, len(files), "should not generate files when failed")
}
} else {
err := cmd.ExecuteContext(ctx)
require.NoError(t, err, "should not return an error")

files, err := os.ReadDir(targetPath)
require.NoError(t, err, "ReadDir should not return an error")
require.NotZero(t, len(files), "should generate files when successful")

for _, file := range files {
ext := filepath.Ext(file.Name())

contains := false
for _, extension := range tc.extensions {
contains = contains || ext == extension
}
require.True(t, contains, "should generate files with correct extension")
}
}

if _, err := os.Stat(targetPath); err != nil {
require.NoError(t, os.RemoveAll(targetPath), "RemoveAll should be able to remove the temporary target directory")
}
})
}
}
1 change: 1 addition & 0 deletions cmd/provenanced/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ func initRootCmd(rootCmd *cobra.Command, encodingConfig params.EncodingConfig) {
AddMetaAddressCmd(),
snapshot.Cmd(newApp),
GetPreUpgradeCmd(),
GetDocGenCmd(),
)

fixDebugPubkeyRawTypeFlag(rootCmd)
Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ require (
github.com/cosmos/gorocksdb v1.2.0 // indirect
github.com/cosmos/iavl v0.19.6 // indirect
github.com/cosmos/ledger-cosmos-go v0.12.2 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/creachadair/taskgroup v0.3.2 // indirect
github.com/danieljoos/wincred v1.1.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
Expand Down Expand Up @@ -144,6 +145,7 @@ require (
github.com/prometheus/procfs v0.9.0 // indirect
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
github.com/rs/cors v1.8.2 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sasha-s/go-deadlock v0.3.1 // indirect
github.com/spf13/afero v1.9.5 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,7 @@ github.com/cosmos/ledger-cosmos-go v0.12.2 h1:/XYaBlE2BJxtvpkHiBm97gFGSGmYGKunKy
github.com/cosmos/ledger-cosmos-go v0.12.2/go.mod h1:ZcqYgnfNJ6lAXe4HPtWgarNEY+B74i+2/8MhZw4ziiI=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creachadair/taskgroup v0.3.2 h1:zlfutDS+5XG40AOxcHDSThxKzns8Tnr9jnr6VqkYlkM=
github.com/creachadair/taskgroup v0.3.2/go.mod h1:wieWwecHVzsidg2CsUnFinW1faVN4+kq+TDlRJQ0Wbk=
Expand Down Expand Up @@ -1031,6 +1032,7 @@ github.com/rs/zerolog v1.31.0 h1:FcTR3NnLWW+NnTwwhFWiJSZr4ECLpqCm6QsEnyvbV4A=
github.com/rs/zerolog v1.31.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
Expand Down
Loading