diff --git a/CHANGELOG.md b/CHANGELOG.md index f1e871464d68..e66fadf6b17a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Improvements +* (x/group, x/gov) [#17220](https://github.com/cosmos/cosmos-sdk/pull/17220) Add `--skip-metadata` flag in `draft-proposal` to skip metadata prompt. * (x/group, x/gov) [#17109](https://github.com/cosmos/cosmos-sdk/pull/17109) Let proposal summary be 40x longer than metadata limit. * (all) [#16537](https://github.com/cosmos/cosmos-sdk/pull/16537) Properly propagated `fmt.Errorf` errors and using `errors.New` where appropriate. * (version) [#17096](https://github.com/cosmos/cosmos-sdk/pull/17096) Improve `getSDKVersion()` to handle module replacements diff --git a/x/gov/client/cli/prompt.go b/x/gov/client/cli/prompt.go index a75d7c9eda87..2267ddc5052f 100644 --- a/x/gov/client/cli/prompt.go +++ b/x/gov/client/cli/prompt.go @@ -76,15 +76,11 @@ func Prompt[T any](data T, namePrefix string) (T, error) { // create prompts prompt := promptui.Prompt{ - Label: fmt.Sprintf("Enter %s's %s", namePrefix, strings.ToLower(client.CamelCaseToString(v.Type().Field(i).Name))), + Label: fmt.Sprintf("Enter %s %s", namePrefix, strings.ToLower(client.CamelCaseToString(v.Type().Field(i).Name))), Validate: client.ValidatePromptNotEmpty, } fieldName := strings.ToLower(v.Type().Field(i).Name) - // validation per field name - if strings.Contains(fieldName, "url") { - prompt.Validate = client.ValidatePromptURL - } if strings.EqualFold(fieldName, "authority") { // pre-fill with gov address @@ -92,6 +88,7 @@ func Prompt[T any](data T, namePrefix string) (T, error) { prompt.Validate = client.ValidatePromptAddress } + // TODO(@julienrbrt) use scalar annotation instead of dumb string name matching if strings.Contains(fieldName, "addr") || strings.Contains(fieldName, "sender") || strings.Contains(fieldName, "voter") || @@ -150,9 +147,8 @@ type proposalType struct { } // Prompt the proposal type values and return the proposal and its metadata -func (p *proposalType) Prompt(cdc codec.Codec) (*proposal, types.ProposalMetadata, error) { - // set metadata - metadata, err := Prompt(types.ProposalMetadata{}, "proposal") +func (p *proposalType) Prompt(cdc codec.Codec, skipMetadata bool) (*proposal, types.ProposalMetadata, error) { + metadata, err := PromptMetadata(skipMetadata) if err != nil { return nil, metadata, fmt.Errorf("failed to set proposal metadata: %w", err) } @@ -201,8 +197,48 @@ func getProposalSuggestions() []string { return types } +// PromptMetadata prompts for proposal metadata or only title and summary if skip is true +func PromptMetadata(skip bool) (types.ProposalMetadata, error) { + var ( + metadata types.ProposalMetadata + err error + ) + + if !skip { + metadata, err = Prompt(types.ProposalMetadata{}, "proposal") + if err != nil { + return metadata, fmt.Errorf("failed to set proposal metadata: %w", err) + } + } else { + // prompt for title and summary + titlePrompt := promptui.Prompt{ + Label: "Enter proposal title", + Validate: client.ValidatePromptNotEmpty, + } + + metadata.Title, err = titlePrompt.Run() + if err != nil { + return metadata, fmt.Errorf("failed to set proposal title: %w", err) + } + + summaryPrompt := promptui.Prompt{ + Label: "Enter proposal summary", + Validate: client.ValidatePromptNotEmpty, + } + + metadata.Summary, err = summaryPrompt.Run() + if err != nil { + return metadata, fmt.Errorf("failed to set proposal summary: %w", err) + } + } + + return metadata, nil +} + // NewCmdDraftProposal let a user generate a draft proposal. func NewCmdDraftProposal() *cobra.Command { + flagSkipMetadata := "skip-metadata" + cmd := &cobra.Command{ Use: "draft-proposal", Short: "Generate a draft proposal json file. The generated proposal json contains only one message (skeleton).", @@ -260,7 +296,9 @@ func NewCmdDraftProposal() *cobra.Command { } } - result, metadata, err := proposal.Prompt(clientCtx.Codec) + skipMetadataPrompt, _ := cmd.Flags().GetBool(flagSkipMetadata) + + result, metadata, err := proposal.Prompt(clientCtx.Codec, skipMetadataPrompt) if err != nil { return err } @@ -269,17 +307,20 @@ func NewCmdDraftProposal() *cobra.Command { return err } - if err := writeFile(draftMetadataFileName, metadata); err != nil { - return err + if !skipMetadataPrompt { + if err := writeFile(draftMetadataFileName, metadata); err != nil { + return err + } } - fmt.Printf("The draft proposal has successfully been generated.\nProposals should contain off-chain metadata, please upload the metadata JSON to IPFS.\nThen, replace the generated metadata field with the IPFS CID.\n") + cmd.Println("The draft proposal has successfully been generated.\nProposals should contain off-chain metadata, please upload the metadata JSON to IPFS.\nThen, replace the generated metadata field with the IPFS CID.") return nil }, } flags.AddTxFlagsToCmd(cmd) + cmd.Flags().Bool(flagSkipMetadata, false, "skip metadata prompt") return cmd } diff --git a/x/group/client/cli/prompt.go b/x/group/client/cli/prompt.go index 7b4a2fc4507c..79b347f525a3 100644 --- a/x/group/client/cli/prompt.go +++ b/x/group/client/cli/prompt.go @@ -30,9 +30,9 @@ type proposalType struct { } // Prompt the proposal type values and return the proposal and its metadata. -func (p *proposalType) Prompt(cdc codec.Codec) (*Proposal, govtypes.ProposalMetadata, error) { +func (p *proposalType) Prompt(cdc codec.Codec, skipMetadata bool) (*Proposal, govtypes.ProposalMetadata, error) { // set metadata - metadata, err := govcli.Prompt(govtypes.ProposalMetadata{}, "proposal") + metadata, err := govcli.PromptMetadata(skipMetadata) if err != nil { return nil, metadata, fmt.Errorf("failed to set proposal metadata: %w", err) } @@ -86,6 +86,8 @@ func (p *proposalType) Prompt(cdc codec.Codec) (*Proposal, govtypes.ProposalMeta // NewCmdDraftProposal let a user generate a draft proposal. func NewCmdDraftProposal() *cobra.Command { + flagSkipMetadata := "skip-metadata" + cmd := &cobra.Command{ Use: "draft-proposal", Short: "Generate a draft proposal json file. The generated proposal json contains only one message (skeleton).", @@ -137,7 +139,9 @@ func NewCmdDraftProposal() *cobra.Command { panic("unexpected proposal type") } - result, metadata, err := proposal.Prompt(clientCtx.Codec) + skipMetadataPrompt, _ := cmd.Flags().GetBool(flagSkipMetadata) + + result, metadata, err := proposal.Prompt(clientCtx.Codec, skipMetadataPrompt) if err != nil { return err } @@ -146,17 +150,20 @@ func NewCmdDraftProposal() *cobra.Command { return err } - if err := writeFile(draftMetadataFileName, metadata); err != nil { - return err + if !skipMetadataPrompt { + if err := writeFile(draftMetadataFileName, metadata); err != nil { + return err + } } - fmt.Printf("The draft proposal has successfully been generated.\nProposals should contain off-chain metadata, please upload the metadata JSON to IPFS.\nThen, replace the generated metadata field with the IPFS CID.\n") + cmd.Println("The draft proposal has successfully been generated.\nProposals should contain off-chain metadata, please upload the metadata JSON to IPFS.\nThen, replace the generated metadata field with the IPFS CID.") return nil }, } flags.AddTxFlagsToCmd(cmd) + cmd.Flags().Bool(flagSkipMetadata, false, "skip metadata prompt") return cmd }