From 239d92f8ada9ba285cdbb004ff6943ebd27ec05f Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Thu, 16 May 2024 16:49:57 +0200 Subject: [PATCH] feat: generate chain config documentation automatically (#4113) * add pkg to read doc struct tag and add config doc tags * create a tool to generate config files documentation * add changelog * use the ouput as a yaml * fix tests and lint --------- Co-authored-by: Pantani --- .github/workflows/gen-docs-config.yml | 38 +++ changelog.md | 1 + ignite/config/chain/base/config.go | 103 ++++--- ignite/config/chain/v0/config.go | 10 +- ignite/config/chain/v1/config.go | 2 +- ignite/config/chain/v1/validator.go | 92 +++---- .../internal/tools/gen-config-doc/cmd/root.go | 94 +++++++ ignite/internal/tools/gen-config-doc/go.mod | 71 +++++ ignite/internal/tools/gen-config-doc/go.sum | 259 ++++++++++++++++++ ignite/internal/tools/gen-config-doc/main.go | 15 + .../tools/gen-config-doc/templates/doc/doc.go | 46 ++++ .../templates/doc/files/{{Name}}.plush | 1 + .../internal/tools/gen-mig-diffs/cmd/root.go | 2 +- ignite/pkg/clidoc/struct.go | 122 +++++++++ ignite/pkg/clidoc/struct_test.go | 221 +++++++++++++++ scripts/gen-config-doc | 3 + 16 files changed, 973 insertions(+), 107 deletions(-) create mode 100644 .github/workflows/gen-docs-config.yml create mode 100644 ignite/internal/tools/gen-config-doc/cmd/root.go create mode 100644 ignite/internal/tools/gen-config-doc/go.mod create mode 100644 ignite/internal/tools/gen-config-doc/go.sum create mode 100644 ignite/internal/tools/gen-config-doc/main.go create mode 100644 ignite/internal/tools/gen-config-doc/templates/doc/doc.go create mode 100644 ignite/internal/tools/gen-config-doc/templates/doc/files/{{Name}}.plush create mode 100644 ignite/pkg/clidoc/struct.go create mode 100644 ignite/pkg/clidoc/struct_test.go create mode 100644 scripts/gen-config-doc diff --git a/.github/workflows/gen-docs-config.yml b/.github/workflows/gen-docs-config.yml new file mode 100644 index 0000000000..5ff9ccf1d1 --- /dev/null +++ b/.github/workflows/gen-docs-config.yml @@ -0,0 +1,38 @@ +name: Generate Config Doc +on: + push: + paths: + - "ignite/config/chain/base/*" + - "ignite/config/chain/v*" + branches: + - main + +jobs: + cli: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-go@v5 + with: + go-version: 'stable' + + - name: Generate Config Doc + run: ./scripts/gen-config-doc + + - name: Create Pull Request + id: cpr + uses: peter-evans/create-pull-request@v6 + with: + title: "docs(config): update config doc" + commit-message: "docs(config): update config doc" + body: "" + branch: feat/gen-config-doc + add-paths: | + docs/ + + - name: Check outputs + run: | + echo "Pull Request Number - ${{ steps.cpr.outputs.pull-request-number }}" + echo "Pull Request URL - ${{ steps.cpr.outputs.pull-request-url }}" + diff --git a/changelog.md b/changelog.md index b0d1360aef..abae9a0e15 100644 --- a/changelog.md +++ b/changelog.md @@ -16,6 +16,7 @@ - [#4077](https://github.com/ignite/cli/pull/4077) Merge the swagger files manually instead use nodetime `swagger-combine` - [#4100](https://github.com/ignite/cli/pull/4100) Set the `proto-dir` flag only for the `scaffold chain` command and use the proto path from the config - [#4111](https://github.com/ignite/cli/pull/4111) Remove vuex generation +- [#4113](https://github.com/ignite/cli/pull/4113) Generate chain config documentation automatically - [#4131](https://github.com/ignite/cli/pull/4131) Support `bytes` as data type in the `scaffold` commands ### Changes diff --git a/ignite/config/chain/base/config.go b/ignite/config/chain/base/config.go index bf8d4ce4cd..de10fa873d 100644 --- a/ignite/config/chain/base/config.go +++ b/ignite/config/chain/base/config.go @@ -10,57 +10,52 @@ import ( // Account holds the options related to setting up Cosmos wallets. type Account struct { - Name string `yaml:"name"` - Coins []string `yaml:"coins,omitempty"` - Mnemonic string `yaml:"mnemonic,omitempty"` - Address string `yaml:"address,omitempty"` - CoinType string `yaml:"cointype,omitempty"` - AccountNumber string `yaml:"account_number,omitempty"` - AddressIndex string `yaml:"address_index,omitempty"` + Name string `yaml:"name" doc:"local name of a key pair associated with an account"` + Coins []string `yaml:"coins,omitempty" doc:"list of token balances for the account"` + Mnemonic string `yaml:"mnemonic,omitempty" doc:"account mnemonic"` + Address string `yaml:"address,omitempty" doc:"account address"` + CoinType string `yaml:"cointype,omitempty" doc:"coin type number for HD derivation (default 118)"` + AccountNumber string `yaml:"account_number,omitempty" doc:"account number for HD derivation (less than equal 2147483647)"` + AddressIndex string `yaml:"address_index,omitempty" doc:"address index number for HD derivation (less than equal 2147483647)"` } // Build holds build configs. type Build struct { - Main string `yaml:"main,omitempty"` - Binary string `yaml:"binary,omitempty"` - LDFlags []string `yaml:"ldflags,omitempty"` - Proto Proto `yaml:"proto"` + Main string `yaml:"main,omitempty" doc:"build main path"` + Binary string `yaml:"binary,omitempty" doc:"binary path"` + LDFlags []string `yaml:"ldflags,omitempty" doc:"custom build ld flags"` + Proto Proto `yaml:"proto" doc:"holds proto build configs"` } // Proto holds proto build configs. type Proto struct { // Path is the relative path of where app's proto files are located at. - Path string `yaml:"path"` + Path string `yaml:"path" doc:"relative path of where app's proto files are located at"` // ThirdPartyPath is the relative path of where the third party proto files are // located that used by the app. - ThirdPartyPaths []string `yaml:"third_party_paths"` + ThirdPartyPaths []string `yaml:"third_party_paths" doc:"relative path of where the third party proto files are located that used by the app"` } // Client configures code generation for clients. type Client struct { // TSClient configures code generation for Typescript Client. - Typescript Typescript `yaml:"typescript,omitempty"` - - // Vuex configures code generation for Vuex stores. - // - // Deprecated: Will be removed eventually. - Vuex Vuex `yaml:"vuex,omitempty"` + Typescript Typescript `yaml:"typescript,omitempty" doc:"configures code generation for Typescript Client"` // Composables configures code generation for Vue 3 composables. - Composables Composables `yaml:"composables,omitempty"` + Composables Composables `yaml:"composables,omitempty" doc:"configures code generation for Vue 3 composables"` // Hooks configures code generation for React hooks. - Hooks Hooks `yaml:"hooks,omitempty"` + Hooks Hooks `yaml:"hooks,omitempty" doc:"configures code generation for React hooks"` // OpenAPI configures OpenAPI spec generation for API. - OpenAPI OpenAPI `yaml:"openapi,omitempty"` + OpenAPI OpenAPI `yaml:"openapi,omitempty" doc:"configures OpenAPI spec generation for API"` } // Typescript configures code generation for Typescript Client. type Typescript struct { // Path configures out location for generated Typescript Client code. - Path string `yaml:"path"` + Path string `yaml:"path" doc:"relative path of where app's typescript files are located at"` } // Vuex configures code generation for Vuex stores. @@ -68,70 +63,70 @@ type Typescript struct { // Deprecated: Will be removed eventually. type Vuex struct { // Path configures out location for generated Vuex stores code. - Path string `yaml:"path"` + Path string `yaml:"path" doc:"relative path of where app's vuex files are located at"` } // Composables configures code generation for vue-query hooks. type Composables struct { // Path configures out location for generated vue-query hooks. - Path string `yaml:"path"` + Path string `yaml:"path" doc:"relative path of where app's composable files are located at"` } // Hooks configures code generation for react-query hooks. type Hooks struct { // Path configures out location for generated vue-query hooks. - Path string `yaml:"path"` + Path string `yaml:"path" doc:"relative path of where app's hooks are located at"` } // OpenAPI configures OpenAPI spec generation for API. type OpenAPI struct { - Path string `yaml:"path"` + Path string `yaml:"path" doc:"relative path of where app's openapi files are located at"` } // Faucet configuration. type Faucet struct { // Name is faucet account's name. - Name *string `yaml:"name"` + Name *string `yaml:"name" doc:"faucet account's name"` // Coins holds type of coin denoms and amounts to distribute. - Coins []string `yaml:"coins"` + Coins []string `yaml:"coins" doc:"holds type of coin denoms and amounts to distribute"` // CoinsMax holds of chain denoms and their max amounts that can be transferred to single user. - CoinsMax []string `yaml:"coins_max,omitempty"` + CoinsMax []string `yaml:"coins_max,omitempty" doc:"holds of chain denoms and their max amounts that can be transferred to single user"` - // LimitRefreshTime sets the timeframe at the end of which the limit will be refreshed - RateLimitWindow string `yaml:"rate_limit_window,omitempty"` + // LimitRefreshTime sets the timeframe at the end of which the limit will be refreshed. + RateLimitWindow string `yaml:"rate_limit_window,omitempty" doc:"sets the timeframe at the end of which the limit will be refreshed"` - // Host is the host of the faucet server - Host string `yaml:"host,omitempty"` + // Host is the host of the faucet server. + Host string `yaml:"host,omitempty" doc:"the host of the faucet server"` // Port number for faucet server to listen at. - Port uint `yaml:"port,omitempty"` + Port uint `yaml:"port,omitempty" doc:"number for faucet server to listen at"` } // Init overwrites sdk configurations with given values. type Init struct { // App overwrites appd's config/app.toml configs. - App xyaml.Map `yaml:"app"` + App xyaml.Map `yaml:"app" doc:"overwrites appd's config/app.toml configs"` // Client overwrites appd's config/client.toml configs. - Client xyaml.Map `yaml:"client"` + Client xyaml.Map `yaml:"client" doc:"overwrites appd's config/client.toml configs"` // Config overwrites appd's config/config.toml configs. - Config xyaml.Map `yaml:"config"` + Config xyaml.Map `yaml:"config" doc:"overwrites appd's config/config.toml configs"` - // Home overwrites default home directory used for the app - Home string `yaml:"home"` + // Home overwrites default home directory used for the app. + Home string `yaml:"home" doc:"overwrites default home directory used for the app"` } // Host keeps configuration related to started servers. type Host struct { - RPC string `yaml:"rpc"` - P2P string `yaml:"p2p"` - Prof string `yaml:"prof"` - GRPC string `yaml:"grpc"` - GRPCWeb string `yaml:"grpc-web"` - API string `yaml:"api"` + RPC string `yaml:"rpc" doc:"RPC server address"` + P2P string `yaml:"p2p" doc:"P2P server address"` + Prof string `yaml:"prof" doc:"Profiling server address"` + GRPC string `yaml:"grpc" doc:"GRPC server address"` + GRPCWeb string `yaml:"grpc-web" doc:"GRPC Web server address"` + API string `yaml:"api" doc:"API server address"` } // Validation describes the kind of validation the chain has. @@ -149,14 +144,14 @@ const ( // Config defines a struct with the fields that are common to all config versions. type Config struct { - Validation Validation `yaml:"validation,omitempty"` - Version version.Version `yaml:"version"` - Build Build `yaml:"build,omitempty"` - Accounts []Account `yaml:"accounts"` - Faucet Faucet `yaml:"faucet,omitempty"` - Client Client `yaml:"client,omitempty"` - Genesis xyaml.Map `yaml:"genesis,omitempty"` - Minimal bool `yaml:"minimal,omitempty"` + Validation Validation `yaml:"validation,omitempty" doc:"describes the kind of validation the chain has"` + Version version.Version `yaml:"version" doc:"defines the type for the config version number"` + Build Build `yaml:"build,omitempty" doc:"holds build configs"` + Accounts []Account `yaml:"accounts" doc:"holds the options related to setting up Cosmos wallets"` + Faucet Faucet `yaml:"faucet,omitempty" doc:"faucet configuration"` + Client Client `yaml:"client,omitempty" doc:"configures code generation for clients"` + Genesis xyaml.Map `yaml:"genesis,omitempty" doc:"custom genesis modifications"` + Minimal bool `yaml:"minimal,omitempty" doc:"minimal blockchain with the minimum required Cosmos SDK modules"` } // GetVersion returns the config version. diff --git a/ignite/config/chain/v0/config.go b/ignite/config/chain/v0/config.go index 41ebc8a1c2..ffed30ee4f 100644 --- a/ignite/config/chain/v0/config.go +++ b/ignite/config/chain/v0/config.go @@ -14,9 +14,9 @@ import ( type Config struct { base.Config `yaml:",inline"` - Validator Validator `yaml:"validator"` - Init base.Init `yaml:"init"` - Host base.Host `yaml:"host"` + Validator Validator `yaml:"validator" doc:"holds info related to validator settings"` + Init base.Init `yaml:"init" doc:"overwrites sdk configurations with given values"` + Host base.Host `yaml:"host" doc:"keeps configuration related to started servers"` } // Clone returns an identical copy of the instance. @@ -32,6 +32,6 @@ func (c *Config) Decode(r io.Reader) error { // Validator holds info related to validator settings. type Validator struct { - Name string `yaml:"name"` - Staked string `yaml:"staked"` + Name string `yaml:"name" doc:"name of the validator"` + Staked string `yaml:"staked" doc:"how much the validator has staked"` } diff --git a/ignite/config/chain/v1/config.go b/ignite/config/chain/v1/config.go index cda54661b7..2afe32ec59 100644 --- a/ignite/config/chain/v1/config.go +++ b/ignite/config/chain/v1/config.go @@ -23,7 +23,7 @@ func DefaultConfig() *Config { type Config struct { base.Config `yaml:",inline"` - Validators []Validator `yaml:"validators"` + Validators []Validator `yaml:"validators" doc:"holds info related to validator list settings"` } func (c *Config) SetDefaults() error { diff --git a/ignite/config/chain/v1/validator.go b/ignite/config/chain/v1/validator.go index 7dc43e9b42..39bb3a488f 100644 --- a/ignite/config/chain/v1/validator.go +++ b/ignite/config/chain/v1/validator.go @@ -7,134 +7,134 @@ import ( // Validator holds info related to validator settings. type Validator struct { // Name is the name of the validator. - Name string `yaml:"name"` + Name string `yaml:"name" doc:"name of the validator"` // Bonded is how much the validator has staked. - Bonded string `yaml:"bonded"` + Bonded string `yaml:"bonded" doc:"how much the validator has staked"` // App overwrites appd's config/app.toml configs. - App xyaml.Map `yaml:"app,omitempty"` + App xyaml.Map `yaml:"app,omitempty" doc:"overwrites appd's config/app.toml configs"` // Config overwrites appd's config/config.toml configs. - Config xyaml.Map `yaml:"config,omitempty"` + Config xyaml.Map `yaml:"config,omitempty" doc:"overwrites appd's config/config.toml configs"` // Client overwrites appd's config/client.toml configs. - Client xyaml.Map `yaml:"client,omitempty"` + Client xyaml.Map `yaml:"client,omitempty" doc:"overwrites appd's config/client.toml configs"` - // Home overwrites default home directory used for the app - Home string `yaml:"home,omitempty"` + // Home overwrites default home directory used for the app. + Home string `yaml:"home,omitempty" doc:"overwrites default home directory used for the app"` // Gentx overwrites appd's config/gentx.toml configs. - Gentx *Gentx `yaml:"gentx,omitempty"` + Gentx *Gentx `yaml:"gentx,omitempty" doc:"overwrites appd's config/gentx.toml configs"` } // Gentx holds info related to Gentx settings. type Gentx struct { // Amount is the amount for the current Gentx. - Amount string `yaml:"amount"` + Amount string `yaml:"amount" doc:"the amount for the current Gentx"` // Moniker is the validator's (optional) moniker. - Moniker string `yaml:"moniker"` + Moniker string `yaml:"moniker" doc:"the validator's (optional) moniker"` // Home is directory for config and data. - Home string `yaml:"home"` + Home string `yaml:"home" doc:"directory for config and data"` // KeyringBackend is keyring's backend. - KeyringBackend string `yaml:"keyring-backend"` + KeyringBackend string `yaml:"keyring-backend" doc:"keyring's backend"` // ChainID is the network chain ID. - ChainID string `yaml:"chain-id"` + ChainID string `yaml:"chain-id" doc:"network chain ID"` // CommissionMaxChangeRate is the maximum commission change rate percentage (per day). - CommissionMaxChangeRate string `yaml:"commission-max-change-rate"` + CommissionMaxChangeRate string `yaml:"commission-max-change-rate" doc:"maximum commission change rate percentage (per day)"` - // CommissionMaxRate is the maximum commission rate percentage - CommissionMaxRate string `yaml:"commission-max-rate"` + // CommissionMaxRate is the maximum commission rate percentage. + CommissionMaxRate string `yaml:"commission-max-rate" doc:"maximum commission rate percentage"` // CommissionRate is the initial commission rate percentage. - CommissionRate string `yaml:"commission-rate"` + CommissionRate string `yaml:"commission-rate" doc:"initial commission rate percentage"` // Details is the validator's (optional) details. - Details string `yaml:"details"` + Details string `yaml:"details" doc:"validator's (optional) details"` // SecurityContact is the validator's (optional) security contact email. - SecurityContact string `yaml:"security-contact"` + SecurityContact string `yaml:"security-contact" doc:"validator's (optional) security contact email"` // Website is the validator's (optional) website. - Website string `yaml:"website"` + Website string `yaml:"website" doc:"validator's (optional) website"` // AccountNumber is the account number of the signing account (offline mode only). - AccountNumber int `yaml:"account-number"` + AccountNumber int `yaml:"account-number" doc:"account number of the signing account (offline mode only)"` // BroadcastMode is the transaction broadcasting mode (sync|async|block) (default "sync"). - BroadcastMode string `yaml:"broadcast-mode"` + BroadcastMode string `yaml:"broadcast-mode" doc:"transaction broadcasting mode (sync|async|block) (default 'sync')"` // DryRun is a boolean determining whether to ignore the --gas flag and perform a simulation of a transaction. - DryRun bool `yaml:"dry-run"` + DryRun bool `yaml:"dry-run" doc:"boolean determining whether to ignore the --gas flag and perform a simulation of a transaction"` - // FeeAccount is the fee account pays fees for the transaction instead of deducting from the signer - FeeAccount string `yaml:"fee-account"` + // FeeAccount is the fee account pays fees for the transaction instead of deducting from the signer. + FeeAccount string `yaml:"fee-account" doc:"fee account pays fees for the transaction instead of deducting from the signer"` // Fee is the fee to pay along with transaction; eg: 10uatom. - Fee string `yaml:"fee"` + Fee string `yaml:"fee" doc:"fee to pay along with transaction; eg: 10uatom"` // From is the name or address of private key with which to sign. - From string `yaml:"from"` + From string `yaml:"from" doc:"name or address of private key with which to sign"` // From is the gas limit to set per-transaction; set to "auto" to calculate sufficient gas automatically (default 200000). - Gas string `yaml:"gas"` + Gas string `yaml:"gas" doc:"gas limit to set per-transaction; set to 'auto' to calculate sufficient gas automatically (default 200000)"` // GasAdjustment is the adjustment factor to be multiplied against the estimate returned by the tx simulation; if the gas limit is set manually this flag is ignored (default 1). - GasAdjustment string `yaml:"gas-adjustment"` + GasAdjustment string `yaml:"gas-adjustment" doc:"adjustment factor to be multiplied against the estimate returned by the tx simulation; if the gas limit is set manually this flag is ignored (default 1)"` // GasPrices is the gas prices in decimal format to determine the transaction fee (e.g. 0.1uatom). - GasPrices string `yaml:"gas-prices"` + GasPrices string `yaml:"gas-prices" doc:"gas prices in decimal format to determine the transaction fee (e.g. 0.1uatom)"` // GenerateOnly is a boolean determining whether to build an unsigned transaction and write it to STDOUT. - GenerateOnly bool `yaml:"generate-only"` + GenerateOnly bool `yaml:"generate-only" doc:"boolean determining whether to build an unsigned transaction and write it to STDOUT"` // Identity is the (optional) identity signature (ex. UPort or Keybase). - Identity string `yaml:"identity"` + Identity string `yaml:"identity" doc:"identity signature (ex. UPort or Keybase)"` // IP is the node's public IP (default "192.168.1.64"). - IP string `yaml:"ip"` + IP string `yaml:"ip" doc:"node's public IP (default '192.168.1.64')"` // KeyringDir is the client Keyring directory; if omitted, the default 'home' directory will be used. - KeyringDir string `yaml:"keyring-dir"` + KeyringDir string `yaml:"keyring-dir" doc:"client Keyring directory; if omitted, the default 'home' directory will be used"` // Ledger is a boolean determining whether to use a connected Ledger device. - Ledger bool `yaml:"ledger"` + Ledger bool `yaml:"ledger" doc:"boolean determining whether to use a connected Ledger device"` // KeyringDir is the minimum self delegation required on the validator. - MinSelfDelegation string `yaml:"min-self-delegation"` + MinSelfDelegation string `yaml:"min-self-delegation" doc:"minimum self delegation required on the validator"` // Node is : to tendermint rpc interface for this chain (default "tcp://localhost:26657"). - Node string `yaml:"node"` + Node string `yaml:"node" doc:": to tendermint rpc interface for this chain (default 'tcp://localhost:26657')"` // NodeID is the node's NodeID. - NodeID string `yaml:"node-id"` + NodeID string `yaml:"node-id" doc:"node's NodeID"` // Note is the note to add a description to the transaction (previously --memo). - Note string `yaml:"note"` + Note string `yaml:"note" doc:"note to add a description to the transaction (previously --memo)"` // Offline is a boolean determining the offline mode (does not allow any online functionality). - Offline bool `yaml:"offline"` + Offline bool `yaml:"offline" doc:"boolean determining the offline mode (does not allow any online functionality)"` // Output is the output format (text|json) (default "json"). - Output string `yaml:"output"` + Output string `yaml:"output" doc:"output format (text|json) (default 'json')"` // OutputDocument writes the genesis transaction JSON document to the given file instead of the default location. - OutputDocument string `yaml:"output-document"` + OutputDocument string `yaml:"output-document" doc:"writes the genesis transaction JSON document to the given file instead of the default location"` // PubKey is the validator's Protobuf JSON encoded public key. - PubKey string `yaml:"pubkey"` + PubKey string `yaml:"pubkey" doc:"validator's Protobuf JSON encoded public key"` // Sequence is the sequence number of the signing account (offline mode only). - Sequence uint `yaml:"sequence"` + Sequence uint `yaml:"sequence" doc:"sequence number of the signing account (offline mode only)"` // SignMode is the choose sign mode (direct|amino-json), this is an advanced feature. - SignMode string `yaml:"sign-mode"` + SignMode string `yaml:"sign-mode" doc:"choose sign mode (direct|amino-json), this is an advanced feature"` // TimeoutHeight sets a block timeout height to prevent the tx from being committed past a certain height. - TimeoutHeight uint `yaml:"timeout-height"` + TimeoutHeight uint `yaml:"timeout-height" doc:"sets a block timeout height to prevent the tx from being committed past a certain height"` } diff --git a/ignite/internal/tools/gen-config-doc/cmd/root.go b/ignite/internal/tools/gen-config-doc/cmd/root.go new file mode 100644 index 0000000000..18f3a1648a --- /dev/null +++ b/ignite/internal/tools/gen-config-doc/cmd/root.go @@ -0,0 +1,94 @@ +package cmd + +import ( + "fmt" + "path/filepath" + + "github.com/spf13/cobra" + + v0 "github.com/ignite/cli/v29/ignite/config/chain/v0" + v1 "github.com/ignite/cli/v29/ignite/config/chain/v1" + "github.com/ignite/cli/v29/ignite/pkg/clidoc" + "github.com/ignite/cli/v29/ignite/pkg/cliui" + "github.com/ignite/cli/v29/ignite/pkg/errors" + "github.com/ignite/cli/v29/ignite/pkg/xgenny" + + "github.com/ignite/cli/ignite/internal/tools/gen-config-doc/templates/doc" +) + +const ( + flagVersion = "version" + flagOutput = "output" + flagFilename = "filename" + + defaultFilename = "sample-config.yml" + defaultDocPath = "docs/docs/08-references" +) + +// NewRootCmd creates a new root command. +func NewRootCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "gen-config-doc", + Short: "generate configuration file documentation", + Long: "This tool is used to generate the chain configuration file documentation", + RunE: func(cmd *cobra.Command, args []string) (err error) { + session := cliui.New() + defer session.End() + + var ( + version, _ = cmd.Flags().GetString(flagVersion) + output, _ = cmd.Flags().GetString(flagOutput) + fileName, _ = cmd.Flags().GetString(flagFilename) + ) + + output, err = filepath.Abs(output) + if err != nil { + return errors.Wrap(err, "failed to find the abs path") + } + + var docs clidoc.Docs + switch version { + case "v0": + docs, err = clidoc.GenDoc(v0.Config{}) + case "v1": + docs, err = clidoc.GenDoc(v1.Config{}) + default: + return errors.Errorf("unknown version: %s", version) + } + if err != nil { + return errors.Wrapf(err, "failed to generate migration doc %s", version) + } + + // Generate the docs file. + g, err := doc.NewGenerator(doc.Options{ + Path: output, + FileName: fileName, + Config: docs.String(), + }) + if err != nil { + return errors.Wrap(err, "failed to create the doc generator object") + } + + sm, err := xgenny.NewRunner(cmd.Context(), output).RunAndApply(g) + if err != nil { + return err + } + + files := append(sm.CreatedFiles(), sm.ModifiedFiles()...) + if len(files) == 0 { + return errors.Errorf("config doc not created at %s", output) + } + session.EventBus().SendInfo( + fmt.Sprintf("Config doc generated successfully at %s", files[0]), + ) + + return nil + }, + } + + cmd.Flags().StringP(flagVersion, "v", "v1", "Version of Ignite config file") + cmd.Flags().StringP(flagOutput, "o", defaultDocPath, "Output directory to save the config document") + cmd.Flags().StringP(flagFilename, "f", defaultFilename, "Document file name") + + return cmd +} diff --git a/ignite/internal/tools/gen-config-doc/go.mod b/ignite/internal/tools/gen-config-doc/go.mod new file mode 100644 index 0000000000..c09b525880 --- /dev/null +++ b/ignite/internal/tools/gen-config-doc/go.mod @@ -0,0 +1,71 @@ +module github.com/ignite/cli/ignite/internal/tools/gen-config-doc + +go 1.22.2 + +replace github.com/ignite/cli/v29 => ../../../../ + +require ( + github.com/gobuffalo/genny/v2 v2.1.0 + github.com/gobuffalo/plush/v4 v4.1.19 + github.com/ignite/cli/v29 v29.0.0-00010101000000-000000000000 + github.com/spf13/cobra v1.8.0 +) + +require ( + github.com/AlecAivazis/survey/v2 v2.3.7 // indirect + github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect + github.com/aymerick/douceur v0.2.0 // indirect + github.com/briandowns/spinner v1.23.0 // indirect + github.com/charmbracelet/lipgloss v0.10.0 // indirect + github.com/chzyer/readline v1.5.1 // indirect + github.com/cockroachdb/errors v1.11.1 // indirect + github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect + github.com/cockroachdb/redact v1.1.5 // indirect + github.com/emicklei/proto v1.12.2 // indirect + github.com/emicklei/proto-contrib v0.15.0 // indirect + github.com/fatih/color v1.16.0 // indirect + github.com/fatih/structs v1.1.0 // indirect + github.com/getsentry/sentry-go v0.27.0 // indirect + github.com/gobuffalo/flect v0.3.0 // indirect + github.com/gobuffalo/github_flavored_markdown v1.1.4 // indirect + github.com/gobuffalo/helpers v0.6.7 // indirect + github.com/gobuffalo/logger v1.0.7 // indirect + github.com/gobuffalo/packd v1.0.2 // indirect + github.com/gobuffalo/tags/v3 v3.1.4 // indirect + github.com/gobuffalo/validate/v3 v3.3.3 // indirect + github.com/goccy/go-yaml v1.11.3 // indirect + github.com/gofrs/uuid v4.4.0+incompatible // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/gorilla/css v1.0.0 // indirect + github.com/iancoleman/strcase v0.3.0 // indirect + github.com/imdario/mergo v0.3.13 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect + github.com/kr/pretty v0.3.1 // indirect + github.com/kr/text v0.2.0 // indirect + github.com/lucasb-eyer/go-colorful v1.2.0 // indirect + github.com/manifoldco/promptui v0.9.0 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-runewidth v0.0.15 // indirect + github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect + github.com/microcosm-cc/bluemonday v1.0.23 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/muesli/reflow v0.3.0 // indirect + github.com/muesli/termenv v0.15.2 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/rivo/uniseg v0.4.7 // indirect + github.com/rogpeppe/go-internal v1.12.0 // indirect + github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect + github.com/sirupsen/logrus v1.9.3 // indirect + github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d // indirect + github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e // indirect + github.com/spf13/pflag v1.0.5 // indirect + golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0 // indirect + golang.org/x/net v0.24.0 // indirect + golang.org/x/sys v0.19.0 // indirect + golang.org/x/term v0.19.0 // indirect + golang.org/x/text v0.14.0 // indirect + golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/ignite/internal/tools/gen-config-doc/go.sum b/ignite/internal/tools/gen-config-doc/go.sum new file mode 100644 index 0000000000..5f0520b88c --- /dev/null +++ b/ignite/internal/tools/gen-config-doc/go.sum @@ -0,0 +1,259 @@ +github.com/AlecAivazis/survey/v2 v2.3.7 h1:6I/u8FvytdGsgonrYsVn2t8t4QiRnh6QSTqkkhIiSjQ= +github.com/AlecAivazis/survey/v2 v2.3.7/go.mod h1:xUTIdE4KCOIjsBAE1JYsUPoCqYdZ1reCfTwbto0Fduo= +github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s= +github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w= +github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= +github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= +github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= +github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= +github.com/briandowns/spinner v1.23.0 h1:alDF2guRWqa/FOZZYWjlMIx2L6H0wyewPxo/CH4Pt2A= +github.com/briandowns/spinner v1.23.0/go.mod h1:rPG4gmXeN3wQV/TsAY4w8lPdIM6RX3yqeBQJSrbXjuE= +github.com/charmbracelet/lipgloss v0.10.0 h1:KWeXFSexGcfahHX+54URiZGkBFazf70JNMtwg/AFW3s= +github.com/charmbracelet/lipgloss v0.10.0/go.mod h1:Wig9DSfvANsxqkRsqj6x87irdy123SR4dOXlKa91ciE= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM= +github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI= +github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/chzyer/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04= +github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= +github.com/cockroachdb/errors v1.11.1 h1:xSEW75zKaKCWzR3OfxXUxgrk/NtT4G1MiOv5lWZazG8= +github.com/cockroachdb/errors v1.11.1/go.mod h1:8MUxA3Gi6b25tYlFEBGLf+D8aISL+M4MIpiWMSNRfxw= +github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= +github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= +github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30= +github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= +github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI= +github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/emicklei/proto v1.12.2 h1:ZDyDzrfMt7ncmyor/j07uoOCGLKtU5F87vTPwIzLe/o= +github.com/emicklei/proto v1.12.2/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A= +github.com/emicklei/proto-contrib v0.15.0 h1:5D8JKpV1qekMDFwEJp8NVJGY1We6t14dn9D4G05fpyo= +github.com/emicklei/proto-contrib v0.15.0/go.mod h1:p6zmoy14hFYiwUb35X7nJ4u4l1vfvjc1mWrIt8QB3kw= +github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= +github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps= +github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= +github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= +github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= +github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= +github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= +github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho= +github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= +github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ= +github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU= +github.com/gobuffalo/flect v0.3.0 h1:erfPWM+K1rFNIQeRPdeEXxo8yFr/PO17lhRnS8FUrtk= +github.com/gobuffalo/flect v0.3.0/go.mod h1:5pf3aGnsvqvCj50AVni7mJJF8ICxGZ8HomberC3pXLE= +github.com/gobuffalo/genny/v2 v2.1.0 h1:cCRBbqzo3GfNvj3UetD16zRgUvWFEyyl0qTqquuIqOM= +github.com/gobuffalo/genny/v2 v2.1.0/go.mod h1:4yoTNk4bYuP3BMM6uQKYPvtP6WsXFGm2w2EFYZdRls8= +github.com/gobuffalo/github_flavored_markdown v1.1.3/go.mod h1:IzgO5xS6hqkDmUh91BW/+Qxo/qYnvfzoz3A7uLkg77I= +github.com/gobuffalo/github_flavored_markdown v1.1.4 h1:WacrEGPXUDX+BpU1GM/Y0ADgMzESKNWls9hOTG1MHVs= +github.com/gobuffalo/github_flavored_markdown v1.1.4/go.mod h1:Vl9686qrVVQou4GrHRK/KOG3jCZOKLUqV8MMOAYtlso= +github.com/gobuffalo/helpers v0.6.7 h1:C9CedoRSfgWg2ZoIkVXgjI5kgmSpL34Z3qdnzpfNVd8= +github.com/gobuffalo/helpers v0.6.7/go.mod h1:j0u1iC1VqlCaJEEVkZN8Ia3TEzfj/zoXANqyJExTMTA= +github.com/gobuffalo/logger v1.0.7 h1:LTLwWelETXDYyqF/ASf0nxaIcdEOIJNxRokPcfI/xbU= +github.com/gobuffalo/logger v1.0.7/go.mod h1:u40u6Bq3VVvaMcy5sRBclD8SXhBYPS0Qk95ubt+1xJM= +github.com/gobuffalo/packd v1.0.2 h1:Yg523YqnOxGIWCp69W12yYBKsoChwI7mtu6ceM9Bwfw= +github.com/gobuffalo/packd v1.0.2/go.mod h1:sUc61tDqGMXON80zpKGp92lDb86Km28jfvX7IAyxFT8= +github.com/gobuffalo/plush/v4 v4.1.16/go.mod h1:6t7swVsarJ8qSLw1qyAH/KbrcSTwdun2ASEQkOznakg= +github.com/gobuffalo/plush/v4 v4.1.19 h1:o0E5gEJw+ozkAwQoCeiaWC6VOU2lEmX+GhtGkwpqZ8o= +github.com/gobuffalo/plush/v4 v4.1.19/go.mod h1:WiKHJx3qBvfaDVlrv8zT7NCd3dEMaVR/fVxW4wqV17M= +github.com/gobuffalo/tags/v3 v3.1.4 h1:X/ydLLPhgXV4h04Hp2xlbI2oc5MDaa7eub6zw8oHjsM= +github.com/gobuffalo/tags/v3 v3.1.4/go.mod h1:ArRNo3ErlHO8BtdA0REaZxijuWnWzF6PUXngmMXd2I0= +github.com/gobuffalo/validate/v3 v3.3.3 h1:o7wkIGSvZBYBd6ChQoLxkz2y1pfmhbI4jNJYh6PuNJ4= +github.com/gobuffalo/validate/v3 v3.3.3/go.mod h1:YC7FsbJ/9hW/VjQdmXPvFqvRis4vrRYFxr69WiNZw6g= +github.com/goccy/go-yaml v1.11.3 h1:B3W9IdWbvrUu2OYQGwvU1nZtvMQJPBKgBUuweJjLj6I= +github.com/goccy/go-yaml v1.11.3/go.mod h1:wKnAMd44+9JAAnGQpWVEgBzGt3YuTaQ4uXoHvE4m7WU= +github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= +github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= +github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= +github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec h1:qv2VnGeEQHchGaZ/u7lxST/RaJw+cv273q79D81Xbog= +github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68= +github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI= +github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= +github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= +github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= +github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= +github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= +github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA= +github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg= +github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= +github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= +github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= +github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI= +github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= +github.com/microcosm-cc/bluemonday v1.0.20/go.mod h1:yfBmMi8mxvaZut3Yytv+jTXRY8mxyjJ0/kQBTElld50= +github.com/microcosm-cc/bluemonday v1.0.22/go.mod h1:ytNkv4RrDrLJ2pqlsSI46O6IVXmZOBBD4SaJyDwwTkM= +github.com/microcosm-cc/bluemonday v1.0.23 h1:SMZe2IGa0NuHvnVNAZ+6B38gsTbi5e4sViiWJyDDqFY= +github.com/microcosm-cc/bluemonday v1.0.23/go.mod h1:mN70sk7UkkF8TUr2IGBpNN0jAgStuPzlK76QuruE/z4= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= +github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8= +github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo= +github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8= +github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= +github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= +github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= +github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d h1:yKm7XZV6j9Ev6lojP2XaIshpT4ymkqhMeSghO5Ps00E= +github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= +github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e h1:qpG93cPwA5f7s/ZPBJnGOYQNK/vKsaDaseuKT5Asee8= +github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA= +github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= +github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= +golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= +golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0 h1:985EYyeCOxTpcgOTJpflJUwOeEz0CQOdPt73OzpE9F8= +golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= +golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= +golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q= +golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/ignite/internal/tools/gen-config-doc/main.go b/ignite/internal/tools/gen-config-doc/main.go new file mode 100644 index 0000000000..8ef787e979 --- /dev/null +++ b/ignite/internal/tools/gen-config-doc/main.go @@ -0,0 +1,15 @@ +package main + +import ( + "fmt" + "os" + + "github.com/ignite/cli/ignite/internal/tools/gen-config-doc/cmd" +) + +func main() { + if err := cmd.NewRootCmd().Execute(); err != nil { + fmt.Println(err) + os.Exit(1) + } +} diff --git a/ignite/internal/tools/gen-config-doc/templates/doc/doc.go b/ignite/internal/tools/gen-config-doc/templates/doc/doc.go new file mode 100644 index 0000000000..20903a3fa5 --- /dev/null +++ b/ignite/internal/tools/gen-config-doc/templates/doc/doc.go @@ -0,0 +1,46 @@ +package doc + +import ( + "embed" + + "github.com/gobuffalo/genny/v2" + "github.com/gobuffalo/plush/v4" + + "github.com/ignite/cli/v29/ignite/pkg/xgenny" + "github.com/ignite/cli/v29/ignite/templates/field/plushhelpers" +) + +//go:embed files/* +var fsFiles embed.FS + +// Options represents the options to scaffold a migration document. +type Options struct { + Path string + FileName string + Config string +} + +// NewGenerator returns the generator to scaffold a migration doc. +func NewGenerator(opts Options) (*genny.Generator, error) { + var ( + g = genny.New() + docTemplate = xgenny.NewEmbedWalker( + fsFiles, + "files/", + opts.Path, + ) + ) + + if err := g.Box(docTemplate); err != nil { + return g, err + } + + ctx := plush.NewContext() + ctx.Set("Config", opts.Config) + + plushhelpers.ExtendPlushContext(ctx) + g.Transformer(xgenny.Transformer(ctx)) + g.Transformer(genny.Replace("{{Name}}", opts.FileName)) + + return g, nil +} diff --git a/ignite/internal/tools/gen-config-doc/templates/doc/files/{{Name}}.plush b/ignite/internal/tools/gen-config-doc/templates/doc/files/{{Name}}.plush new file mode 100644 index 0000000000..bd62983020 --- /dev/null +++ b/ignite/internal/tools/gen-config-doc/templates/doc/files/{{Name}}.plush @@ -0,0 +1 @@ +<%= Config %> diff --git a/ignite/internal/tools/gen-mig-diffs/cmd/root.go b/ignite/internal/tools/gen-mig-diffs/cmd/root.go index 70c9aea268..4685e2fa8f 100644 --- a/ignite/internal/tools/gen-mig-diffs/cmd/root.go +++ b/ignite/internal/tools/gen-mig-diffs/cmd/root.go @@ -34,7 +34,7 @@ const ( func NewRootCmd() *cobra.Command { cmd := &cobra.Command{ Use: "gen-mig-diffs", - Short: "GenerateBinaries migration diffs", + Short: "generate migration diffs from two different version", Long: "This tool is used to generate migration diff files for each of ignites scaffold commands", RunE: func(cmd *cobra.Command, args []string) error { session := cliui.New() diff --git a/ignite/pkg/clidoc/struct.go b/ignite/pkg/clidoc/struct.go new file mode 100644 index 0000000000..0ed2aaa03e --- /dev/null +++ b/ignite/pkg/clidoc/struct.go @@ -0,0 +1,122 @@ +package clidoc + +import ( + "fmt" + "reflect" + "strings" +) + +type ( + // Docs represents a slice of Doc. + Docs []Doc + // Doc represents the struct documentation with tag comments. + Doc struct { + Key string + Type string + Value Docs + Comment string + } +) + +// String converts Docs to a string. +func (d Docs) String() string { + var sb strings.Builder + // Initial call with a negative level to avoid unwanted dash at the top level + d.writeString(&sb, -1) + return strings.TrimSpace(sb.String()) +} + +// writeString appends the contents of Docs to sb's buffer at level. +func (d Docs) writeString(sb *strings.Builder, level int) { + indent := strings.Repeat(" ", level+1) // Two spaces per YAML indentation standard + for _, doc := range d { + sb.WriteString(indent) + if doc.Type != "" { + sb.WriteString(fmt.Sprintf("%s: [%s] # %s\n", doc.Key, doc.Type, doc.Comment)) + } else { + sb.WriteString(fmt.Sprintf("%s: # %s\n", doc.Key, doc.Comment)) + } + if len(doc.Value) > 0 { + doc.Value.writeString(sb, level+1) + } + } +} + +// GenDoc to generate documentation from a struct. +func GenDoc(v interface{}) (fields Docs, err error) { + t := reflect.TypeOf(v) + if t.Kind() != reflect.Struct && t.Kind() != reflect.Ptr { + return fields, nil + } + for i := 0; i < t.NumField(); i++ { + var ( + field = t.Field(i) + doc = field.Tag.Get("doc") + yaml = field.Tag.Get("yaml") + ) + + tags := strings.Split(yaml, ",") + name := tags[0] + if name == "" { + name = strings.ToLower(field.Name) + } + if len(tags) > 1 && strings.Contains(tags[1], "inline") { + elemFields, err := GenDoc(reflect.New(field.Type).Elem().Interface()) + if err != nil { + return nil, err + } + fields = append(fields, elemFields...) + continue + } + + var ( + elemFields Docs + elemType string + ) + switch field.Type.Kind() { //nolint:exhaustive + case reflect.Struct: + elemType = field.Type.Kind().String() + elemFields, err = GenDoc(reflect.New(field.Type).Elem().Interface()) + if err != nil { + return nil, err + } + case reflect.Ptr: + elemType = field.Type.Elem().Kind().String() + elemFields, err = GenDoc(reflect.New(field.Type.Elem()).Elem().Interface()) + if err != nil { + return nil, err + } + case reflect.Slice: + elemType = fmt.Sprintf("[]%s", field.Type.Elem().Kind().String()) + elemFields, err = GenDoc(reflect.New(field.Type.Elem()).Elem().Interface()) + if err != nil { + return nil, err + } + default: + elemType = field.Type.Kind().String() + } + fields = append(fields, Doc{ + Key: name, + Comment: doc, + Value: elemFields, + Type: mapTypes(elemType), + }) + } + + return fields, nil +} + +func mapTypes(doc string) string { + docTypes := map[string]string{ + "[]struct": "list", + "struct": "", + "[]map": "list", + "map": "", + "[]slice": "list", + "slice": "list", + } + if docType, ok := docTypes[doc]; ok { + return docType + } + return doc +} diff --git a/ignite/pkg/clidoc/struct_test.go b/ignite/pkg/clidoc/struct_test.go new file mode 100644 index 0000000000..7bd9196e05 --- /dev/null +++ b/ignite/pkg/clidoc/struct_test.go @@ -0,0 +1,221 @@ +package clidoc + +import ( + "strings" + "testing" + + "github.com/stretchr/testify/require" +) + +type ( + build struct { + Main string `yaml:"main,omitempty" doc:"doc of main"` + Binary string `yaml:"binary,omitempty" doc:""` + LDFlags []string `yaml:"ldflags,omitempty"` + Proto proto `yaml:"proto" doc:"doc of proto"` + PtrProto *proto `yaml:"ptr_proto" doc:"doc of pointer proto"` + Protos []proto `yaml:"protos" doc:"doc of protos"` + } + proto struct { + Path string `yaml:"path" doc:"path of proto file"` + ThirdPartyPaths []string `yaml:"third_party_paths" doc:"doc of third party paths"` + } +) + +func TestGenDoc(t *testing.T) { + tests := []struct { + name string + v interface{} + want Docs + err error + }{ + { + name: "build struct", + v: build{}, + want: Docs{ + { + Key: "main", + Comment: "doc of main", + Type: "string", + }, + { + Key: "binary", + Type: "string", + }, + { + Key: "ldflags", + Type: "[]string", + }, + { + Key: "proto", + Value: Docs{ + { + Key: "path", + Comment: "path of proto file", + Type: "string", + }, + { + Key: "third_party_paths", + Comment: "doc of third party paths", + Type: "[]string", + }, + }, + Comment: "doc of proto", + }, + { + Key: "ptr_proto", + Value: Docs{ + { + Key: "path", + Comment: "path of proto file", + Type: "string", + }, + { + Key: "third_party_paths", + Comment: "doc of third party paths", + Type: "[]string", + }, + }, + Comment: "doc of pointer proto", + }, + { + Key: "protos", + Type: "list", + Value: Docs{ + { + Key: "path", + Comment: "path of proto file", + Type: "string", + }, + { + Key: "third_party_paths", + Comment: "doc of third party paths", + Type: "[]string", + }, + }, + Comment: "doc of protos", + }, + }, + }, + { + name: "proto struct", + v: proto{}, + want: Docs{ + { + Key: "path", + Comment: "path of proto file", + Type: "string", + }, + { + Key: "third_party_paths", + Comment: "doc of third party paths", + Type: "[]string", + }, + }, + }, + { + name: "Invalid struct", + v: []map[string]interface{}{}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := GenDoc(tt.v) + if tt.err != nil { + require.Error(t, err) + require.Equal(t, tt.err.Error(), err.Error()) + return + } + require.NoError(t, err) + require.Equal(t, tt.want, got) + }) + } +} + +func TestDocs_String(t *testing.T) { + tests := []struct { + name string + d Docs + want string + }{ + { + name: "many entries", + d: Docs{ + { + Key: "main", + Comment: "doc of main", + }, + { + Key: "binary", + }, + { + Key: "ldflags [array]", + }, + { + Key: "proto", + Value: Docs{ + { + Key: "path", + Comment: "path of proto file", + }, + { + Key: "third_party_paths [array]", + Comment: "doc of third party paths", + }, + }, + Comment: "doc of proto", + }, + { + Key: "protos [array]", + Value: Docs{ + { + Key: "path", + Comment: "path of proto file", + }, + { + Key: "third_party_paths [array]", + Comment: "doc of third party paths", + }, + }, + Comment: "doc of protos", + }, + }, + want: ` +main: # doc of main +binary: # +ldflags [array]: # +proto: # doc of proto + path: # path of proto file + third_party_paths [array]: # doc of third party paths +protos [array]: # doc of protos + path: # path of proto file + third_party_paths [array]: # doc of third party paths`, + }, + { + name: "no entries", + d: Docs{}, + }, + { + name: "two entries", + d: Docs{ + { + Key: "path", + Comment: "path of proto file", + }, + { + Key: "third_party_paths [array]", + Comment: "doc of third party paths", + }, + }, + want: ` +path: # path of proto file +third_party_paths [array]: # doc of third party paths`, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := tt.d.String() + require.Equal(t, strings.TrimSpace(tt.want), strings.TrimSpace(got)) + }) + } +} diff --git a/scripts/gen-config-doc b/scripts/gen-config-doc new file mode 100644 index 0000000000..84056fa0c6 --- /dev/null +++ b/scripts/gen-config-doc @@ -0,0 +1,3 @@ +#!/bin/bash + +go run ignite/internal/tools/gen-config-doc/*.go