Skip to content

Commit

Permalink
imp(cli): convert to using Cobra CLI package (#28)
Browse files Browse the repository at this point in the history
* convert to using Cobra CLI package

* add changelog entry
  • Loading branch information
MalteHerrmann committed Dec 18, 2023
1 parent 220ae8d commit 6f5699a
Show file tree
Hide file tree
Showing 12 changed files with 247 additions and 124 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
### Improvements

- [#27](https://github.com/MalteHerrmann/upgrade-local-node-go/pull/27) Add MIT license
- [#28](https://github.com/MalteHerrmann/upgrade-local-node-go/pull/28) Use [Cobra CLI](https://github.com/spf13/cobra) package

## [v0.3.0](https://github.com/MalteHerrmann/upgrade-local-node-go/releases/tag/v0.3.0) - 2023-08-30

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

import (
"log"

"github.com/MalteHerrmann/upgrade-local-node-go/gov"
"github.com/MalteHerrmann/upgrade-local-node-go/utils"
"github.com/spf13/cobra"
)

//nolint:gochecknoglobals // required by cobra
var depositCmd = &cobra.Command{
Use: "deposit",
Short: "Deposit for a governance proposal",
Long: `Deposit the minimum needed deposit for a given governance proposal.
If no proposal ID is given by the user, the latest proposal is queried and deposited for.`,
Args: cobra.RangeArgs(0, 1),
Run: func(cmd *cobra.Command, args []string) {
bin, err := utils.NewEvmosTestingBinary()
if err != nil {
log.Fatalf("error creating binary: %v", err)
}

if err = bin.GetAccounts(); err != nil {
log.Fatalf("error getting accounts: %v", err)
}

err = gov.Deposit(bin, args)
if err != nil {
log.Fatalf("error depositing: %v", err)
}
},
}

//nolint:gochecknoinits // required by cobra
func init() {
rootCmd.AddCommand(depositCmd)
}
26 changes: 26 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package cmd

import (
"os"

"github.com/spf13/cobra"
)

// rootCmd represents the base command when called without any subcommands.
//
//nolint:gochecknoglobals // required by cobra
var rootCmd = &cobra.Command{
Use: "evmos-utils",
Short: "A collection of utilities to interact with an Evmos node during development.",
Long: `The evmos-utils collection offers helpers to interact with an Evmos node during development.
It can be used to test upgrades, deposit or vote for specific or the latest proposals, etc.`,
}

// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
err := rootCmd.Execute()
if err != nil {
os.Exit(1)
}
}
70 changes: 70 additions & 0 deletions cmd/upgrade.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package cmd

import (
"log"
"regexp"

"github.com/MalteHerrmann/upgrade-local-node-go/gov"
"github.com/MalteHerrmann/upgrade-local-node-go/utils"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)

//nolint:gochecknoglobals // required by cobra
var upgradeCmd = &cobra.Command{
Use: "upgrade",
Short: "Prepare an upgrade of a node",
Long: `Prepare an upgrade of a node by submitting a governance proposal,
voting for it using all keys of in the keyring and having it pass.`,
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
bin, err := utils.NewEvmosTestingBinary()
if err != nil {
log.Fatalf("error creating binary: %v", err)
}

if err = bin.GetAccounts(); err != nil {
log.Fatalf("error getting accounts: %v", err)
}

targetVersion := args[0]
if matched, _ := regexp.MatchString(`v\d+\.\d+\.\d(-rc\d+)?`, targetVersion); !matched {
log.Fatalf("invalid target version: %s; please use the format vX.Y.Z(-rc*).\n", targetVersion)
}

if err := upgradeLocalNode(bin, targetVersion); err != nil {
log.Fatalf("error upgrading local node: %v", err)
}
},
}

//nolint:gochecknoinits // required by cobra
func init() {
rootCmd.AddCommand(upgradeCmd)
}

// upgradeLocalNode prepares upgrading the local node to the target version
// by submitting the upgrade proposal and voting on it using all testing accounts.
func upgradeLocalNode(bin *utils.Binary, targetVersion string) error {
currentHeight, err := utils.GetCurrentHeight(bin)
if err != nil {
return errors.Wrap(err, "error getting current height")
}

upgradeHeight := currentHeight + utils.DeltaHeight

log.Println("Submitting upgrade proposal...")

proposalID, err := gov.SubmitUpgradeProposal(bin, targetVersion, upgradeHeight)
if err != nil {
return errors.Wrap(err, "error executing upgrade proposal")
}

log.Printf("Scheduled upgrade to %s at height %d.\n", targetVersion, upgradeHeight)

if err = gov.SubmitAllVotesForProposal(bin, proposalID); err != nil {
return errors.Wrapf(err, "error submitting votes for proposal %d", proposalID)
}

return nil
}
37 changes: 37 additions & 0 deletions cmd/vote.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package cmd

import (
"log"

"github.com/MalteHerrmann/upgrade-local-node-go/gov"
"github.com/MalteHerrmann/upgrade-local-node-go/utils"
"github.com/spf13/cobra"
)

//nolint:gochecknoglobals // required by cobra
var voteCmd = &cobra.Command{
Use: "vote",
Short: "Vote for a governance proposal",
Long: `Vote for a governance proposal with all keys in the keyring.
If no proposal ID is passed, the latest proposal on chain is queried and used.`,
Args: cobra.RangeArgs(0, 1),
Run: func(cmd *cobra.Command, args []string) {
bin, err := utils.NewEvmosTestingBinary()
if err != nil {
log.Fatalf("error creating binary: %v", err)
}

if err = bin.GetAccounts(); err != nil {
log.Fatalf("error getting accounts: %v", err)
}

if err = gov.SubmitAllVotes(bin, args); err != nil {
log.Fatal(err)
}
},
}

//nolint:gochecknoinits // required by cobra
func init() {
rootCmd.AddCommand(voteCmd)
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ require (
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect
github.com/spf13/afero v1.9.5 // indirect
github.com/spf13/cast v1.5.1 // indirect
github.com/spf13/cobra v1.7.0 // indirect
github.com/spf13/cobra v1.8.0 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.16.0 // indirect
Expand Down
3 changes: 3 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,7 @@ github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwc
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/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creachadair/taskgroup v0.4.2 h1:jsBLdAJE42asreGss2xZGZ8fJra7WtwnHWeJFxv2Li8=
github.com/creachadair/taskgroup v0.4.2/go.mod h1:qiXUOSrbwAY3u0JPGTzObbE3yf9hcXHDKBZ2ZjpCbgM=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
Expand Down Expand Up @@ -1031,6 +1032,8 @@ github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
Expand Down
27 changes: 22 additions & 5 deletions gov/deposit.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package gov

import (
"fmt"
"log"
"regexp"
"strconv"

Expand All @@ -10,10 +11,27 @@ import (
"github.com/pkg/errors"
)

// Deposit deposits the minimum needed deposit for a given governance proposal.
func Deposit(bin *utils.Binary, args []string) error {
deposit, err := GetMinDeposit(bin)
if err != nil {
log.Fatalf("error getting minimum deposit: %v", err)
}

proposalID, err := GetProposalIDFromInput(bin, args)
if err != nil {
log.Fatalf("error getting proposal ID: %v", err)
}

return DepositForProposal(
bin, proposalID, bin.Accounts[0].Name, deposit.String(),
)
}

// DepositForProposal deposits the given amount for the proposal with the given proposalID
// from the given account.
func DepositForProposal(bin *utils.Binary, proposalID int, sender, deposit string) (string, error) {
out, err := utils.ExecuteBinaryCmd(bin, utils.BinaryCmdArgs{
func DepositForProposal(bin *utils.Binary, proposalID int, sender, deposit string) error {
_, err := utils.ExecuteBinaryCmd(bin, utils.BinaryCmdArgs{
Subcommand: []string{
"tx", "gov", "deposit", strconv.Itoa(proposalID), deposit,
},
Expand All @@ -22,10 +40,10 @@ func DepositForProposal(bin *utils.Binary, proposalID int, sender, deposit strin
Quiet: true,
})
if err != nil {
return out, errors.Wrap(err, fmt.Sprintf("failed to deposit for proposal %d", proposalID))
return errors.Wrap(err, fmt.Sprintf("failed to deposit for proposal %d", proposalID))
}

return out, nil
return nil
}

// GetMinDeposit returns the minimum deposit necessary for a proposal from the governance parameters of
Expand All @@ -48,7 +66,6 @@ func GetMinDeposit(bin *utils.Binary) (sdk.Coins, error) {
// FIXME: It wasn't possible to unmarshal the JSON output of the query because of a missing unit in the max_deposit_period
// parameter. This should rather be done using GRPC.
func ParseMinDepositFromResponse(out string) (sdk.Coins, error) {
// FIXME: This is a workaround for the missing unit in the max_deposit_period parameter. Should be done with gRPC.
depositPatternRaw := `min_deposit":\[{"denom":"(\w+)","amount":"(\d+)`
depositPattern := regexp.MustCompile(depositPatternRaw)

Expand Down
34 changes: 34 additions & 0 deletions gov/utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package gov

import (
"fmt"
"strconv"

"github.com/MalteHerrmann/upgrade-local-node-go/utils"
"github.com/pkg/errors"
)

// GetProposalIDFromInput gets the proposal ID from the command line arguments.
func GetProposalIDFromInput(bin *utils.Binary, args []string) (int, error) {
var (
err error
proposalID int
)

switch len(args) {
case 0:
proposalID, err = QueryLatestProposalID(bin)
if err != nil {
return 0, errors.Wrap(err, "error querying latest proposal ID")
}
case 1:
proposalID, err = strconv.Atoi(args[2])
if err != nil {
return 0, errors.Wrapf(err, "error converting proposal ID %s to integer", args[2])
}
default:
return 0, fmt.Errorf("invalid number of arguments; expected 0 or 1; got %d", len(args))
}

return proposalID, nil
}
10 changes: 10 additions & 0 deletions gov/vote.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,16 @@ import (
"github.com/pkg/errors"
)

// SubmitAllVotes submits a vote for the given proposal ID using all testing accounts.
func SubmitAllVotes(bin *utils.Binary, args []string) error {
proposalID, err := GetProposalIDFromInput(bin, args)
if err != nil {
return err
}

return SubmitAllVotesForProposal(bin, proposalID)
}

// SubmitAllVotesForProposal submits a vote for the given proposal ID using all testing accounts.
func SubmitAllVotesForProposal(bin *utils.Binary, proposalID int) error {
accsWithDelegations, err := utils.FilterAccountsWithDelegations(bin)
Expand Down
Loading

0 comments on commit 6f5699a

Please sign in to comment.