-
Notifications
You must be signed in to change notification settings - Fork 41
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Added all needed pieces to build feature. * Added additional logic. * Update usage and long help for command. * Add tests for docgen, but still need to verify generated contents. * Finish tests for docgen command. * Lint code. * Changelog entry. * Fix typo in test. * Add test for invalid target directory. * Add tests for invalid flag values. * Rename rest to rst to improve clarity. --------- Co-authored-by: Ira Miller <[email protected]>
- Loading branch information
Showing
6 changed files
with
295 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} | ||
yaml, err := cmd.Flags().GetBool(FlagYaml) | ||
if err != nil { | ||
return err | ||
} | ||
rst, err := cmd.Flags().GetBool(FlagRst) | ||
if err != nil { | ||
return err | ||
} | ||
manpage, err := cmd.Flags().GetBool(FlagManpage) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
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 | ||
} | ||
} | ||
if yaml { | ||
err = doc.GenYamlTree(cmd.Root(), dir) | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
if rst { | ||
err = doc.GenReSTTree(cmd.Root(), dir) | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
if manpage { | ||
err = doc.GenManTree(cmd.Root(), nil, dir) | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
|
||
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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") | ||
} | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters