From 660515a15236e9f56a56464044d6053408ad9d35 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Fri, 26 Jan 2024 16:36:23 -0300 Subject: [PATCH 01/10] ignore .ign files for app gitignore (#3912) Co-authored-by: Pantani --- ignite/templates/app/files/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/ignite/templates/app/files/.gitignore b/ignite/templates/app/files/.gitignore index c107251d56..c4ba55dc1c 100644 --- a/ignite/templates/app/files/.gitignore +++ b/ignite/templates/app/files/.gitignore @@ -6,3 +6,4 @@ release/ .DS_Store *.dot *.log +*.ign From 85bbb5dbad937d997871aa3d7bab53508105dacb Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Fri, 26 Jan 2024 17:56:47 -0300 Subject: [PATCH 02/10] chore: fix docker links (#3911) ## Description - Fix docker links; - Run `make format` --- docs/docs/02-guide/05-loan.md | 368 +++++++++--------- docs/docs/02-guide/09-docker.md | 2 +- .../version-v0.26/02-guide/09-docker.md | 2 +- .../version-v0.27/02-guide/09-docker.md | 2 +- .../version-v28/02-guide/09-docker.md | 2 +- ignite/pkg/cosmostxcollector/mocks/saver.go | 3 +- .../services/plugin/grpc/v1/client_api.pb.go | 5 +- .../services/plugin/grpc/v1/interface.pb.go | 5 +- ignite/services/plugin/grpc/v1/service.pb.go | 5 +- .../plugin/grpc/v1/service_grpc.pb.go | 1 + ignite/services/plugin/mocks/interface.go | 2 +- .../plugin/testdata/example-plugin/go.mod | 14 +- 12 files changed, 208 insertions(+), 203 deletions(-) diff --git a/docs/docs/02-guide/05-loan.md b/docs/docs/02-guide/05-loan.md index 9b58bffb1e..b2a65f5d06 100644 --- a/docs/docs/02-guide/05-loan.md +++ b/docs/docs/02-guide/05-loan.md @@ -122,44 +122,44 @@ The `ValidateBasic` function plays a crucial role in maintaining the security an ```go title="x/loan/types/message_request_loan.go" import ( - "strconv" + "strconv" - errorsmod "cosmossdk.io/errors" - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) func (msg *MsgRequestLoan) ValidateBasic() error { - _, err := sdk.AccAddressFromBech32(msg.Creator) - if err != nil { - return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid creator address (%s)", err) - } - amount, _ := sdk.ParseCoinsNormalized(msg.Amount) - if !amount.IsValid() { - return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "amount is not a valid Coins object") - } - if amount.Empty() { - return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "amount is empty") - } - fee, _ := sdk.ParseCoinsNormalized(msg.Fee) - if !fee.IsValid() { - return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "fee is not a valid Coins object") - } - deadline, err := strconv.ParseInt(msg.Deadline, 10, 64) - if err != nil { - return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "deadline is not an integer") - } - if deadline <= 0 { - return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "deadline should be a positive integer") - } - collateral, _ := sdk.ParseCoinsNormalized(msg.Collateral) - if !collateral.IsValid() { - return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "collateral is not a valid Coins object") - } - if collateral.Empty() { - return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "collateral is empty") - } - return nil + _, err := sdk.AccAddressFromBech32(msg.Creator) + if err != nil { + return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid creator address (%s)", err) + } + amount, _ := sdk.ParseCoinsNormalized(msg.Amount) + if !amount.IsValid() { + return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "amount is not a valid Coins object") + } + if amount.Empty() { + return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "amount is empty") + } + fee, _ := sdk.ParseCoinsNormalized(msg.Fee) + if !fee.IsValid() { + return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "fee is not a valid Coins object") + } + deadline, err := strconv.ParseInt(msg.Deadline, 10, 64) + if err != nil { + return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "deadline is not an integer") + } + if deadline <= 0 { + return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "deadline should be a positive integer") + } + collateral, _ := sdk.ParseCoinsNormalized(msg.Collateral) + if !collateral.IsValid() { + return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "collateral is not a valid Coins object") + } + if collateral.Empty() { + return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "collateral is empty") + } + return nil } ``` @@ -175,37 +175,37 @@ Replace your scaffolded templates with the following code. package keeper import ( - "context" + "context" - sdk "github.com/cosmos/cosmos-sdk/types" + sdk "github.com/cosmos/cosmos-sdk/types" - "loan/x/loan/types" + "loan/x/loan/types" ) func (k msgServer) RequestLoan(goCtx context.Context, msg *types.MsgRequestLoan) (*types.MsgRequestLoanResponse, error) { - ctx := sdk.UnwrapSDKContext(goCtx) - var loan = types.Loan{ - Amount: msg.Amount, - Fee: msg.Fee, - Collateral: msg.Collateral, - Deadline: msg.Deadline, - State: "requested", - Borrower: msg.Creator, - } - borrower, err := sdk.AccAddressFromBech32(msg.Creator) - if err != nil { - panic(err) - } - collateral, err := sdk.ParseCoinsNormalized(loan.Collateral) - if err != nil { - panic(err) - } - sdkError := k.bankKeeper.SendCoinsFromAccountToModule(ctx, borrower, types.ModuleName, collateral) - if sdkError != nil { - return nil, sdkError - } - k.AppendLoan(ctx, loan) - return &types.MsgRequestLoanResponse{}, nil + ctx := sdk.UnwrapSDKContext(goCtx) + var loan = types.Loan{ + Amount: msg.Amount, + Fee: msg.Fee, + Collateral: msg.Collateral, + Deadline: msg.Deadline, + State: "requested", + Borrower: msg.Creator, + } + borrower, err := sdk.AccAddressFromBech32(msg.Creator) + if err != nil { + panic(err) + } + collateral, err := sdk.ParseCoinsNormalized(loan.Collateral) + if err != nil { + panic(err) + } + sdkError := k.bankKeeper.SendCoinsFromAccountToModule(ctx, borrower, types.ModuleName, collateral) + if sdkError != nil { + return nil, sdkError + } + k.AppendLoan(ctx, loan) + return &types.MsgRequestLoanResponse{}, nil } ``` @@ -215,36 +215,36 @@ As a borrower, you have the option to cancel a loan you have created if you no l package keeper import ( - "context" + "context" - errorsmod "cosmossdk.io/errors" - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "loan/x/loan/types" + "loan/x/loan/types" ) func (k msgServer) CancelLoan(goCtx context.Context, msg *types.MsgCancelLoan) (*types.MsgCancelLoanResponse, error) { - ctx := sdk.UnwrapSDKContext(goCtx) - loan, found := k.GetLoan(ctx, msg.Id) - if !found { - return nil, errorsmod.Wrapf(sdkerrors.ErrKeyNotFound, "key %d doesn't exist", msg.Id) - } - if loan.Borrower != msg.Creator { - return nil, errorsmod.Wrap(sdkerrors.ErrUnauthorized, "Cannot cancel: not the borrower") - } - if loan.State != "requested" { - return nil, errorsmod.Wrapf(types.ErrWrongLoanState, "%v", loan.State) - } - borrower, _ := sdk.AccAddressFromBech32(loan.Borrower) - collateral, _ := sdk.ParseCoinsNormalized(loan.Collateral) - err := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, borrower, collateral) - if err != nil { - return nil, err - } - loan.State = "cancelled" - k.SetLoan(ctx, loan) - return &types.MsgCancelLoanResponse{}, nil + ctx := sdk.UnwrapSDKContext(goCtx) + loan, found := k.GetLoan(ctx, msg.Id) + if !found { + return nil, errorsmod.Wrapf(sdkerrors.ErrKeyNotFound, "key %d doesn't exist", msg.Id) + } + if loan.Borrower != msg.Creator { + return nil, errorsmod.Wrap(sdkerrors.ErrUnauthorized, "Cannot cancel: not the borrower") + } + if loan.State != "requested" { + return nil, errorsmod.Wrapf(types.ErrWrongLoanState, "%v", loan.State) + } + borrower, _ := sdk.AccAddressFromBech32(loan.Borrower) + collateral, _ := sdk.ParseCoinsNormalized(loan.Collateral) + err := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, borrower, collateral) + if err != nil { + return nil, err + } + loan.State = "cancelled" + k.SetLoan(ctx, loan) + return &types.MsgCancelLoanResponse{}, nil } ``` @@ -256,38 +256,38 @@ Approve loan requests and liquidate loans if borrowers fail to repay. package keeper import ( - "context" + "context" - errorsmod "cosmossdk.io/errors" - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "loan/x/loan/types" + "loan/x/loan/types" ) func (k msgServer) ApproveLoan(goCtx context.Context, msg *types.MsgApproveLoan) (*types.MsgApproveLoanResponse, error) { - ctx := sdk.UnwrapSDKContext(goCtx) - loan, found := k.GetLoan(ctx, msg.Id) - if !found { - return nil, errorsmod.Wrapf(sdkerrors.ErrKeyNotFound, "key %d doesn't exist", msg.Id) - } - if loan.State != "requested" { - return nil, errorsmod.Wrapf(types.ErrWrongLoanState, "%v", loan.State) - } - lender, _ := sdk.AccAddressFromBech32(msg.Creator) - borrower, _ := sdk.AccAddressFromBech32(loan.Borrower) - amount, err := sdk.ParseCoinsNormalized(loan.Amount) - if err != nil { - return nil, errorsmod.Wrap(types.ErrWrongLoanState, "Cannot parse coins in loan amount") - } - err = k.bankKeeper.SendCoins(ctx, lender, borrower, amount) - if err != nil { - return nil, err - } - loan.Lender = msg.Creator - loan.State = "approved" - k.SetLoan(ctx, loan) - return &types.MsgApproveLoanResponse{}, nil + ctx := sdk.UnwrapSDKContext(goCtx) + loan, found := k.GetLoan(ctx, msg.Id) + if !found { + return nil, errorsmod.Wrapf(sdkerrors.ErrKeyNotFound, "key %d doesn't exist", msg.Id) + } + if loan.State != "requested" { + return nil, errorsmod.Wrapf(types.ErrWrongLoanState, "%v", loan.State) + } + lender, _ := sdk.AccAddressFromBech32(msg.Creator) + borrower, _ := sdk.AccAddressFromBech32(loan.Borrower) + amount, err := sdk.ParseCoinsNormalized(loan.Amount) + if err != nil { + return nil, errorsmod.Wrap(types.ErrWrongLoanState, "Cannot parse coins in loan amount") + } + err = k.bankKeeper.SendCoins(ctx, lender, borrower, amount) + if err != nil { + return nil, err + } + loan.Lender = msg.Creator + loan.State = "approved" + k.SetLoan(ctx, loan) + return &types.MsgApproveLoanResponse{}, nil } ``` @@ -295,47 +295,47 @@ func (k msgServer) ApproveLoan(goCtx context.Context, msg *types.MsgApproveLoan) package keeper import ( - "context" + "context" - errorsmod "cosmossdk.io/errors" - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "loan/x/loan/types" + "loan/x/loan/types" ) func (k msgServer) RepayLoan(goCtx context.Context, msg *types.MsgRepayLoan) (*types.MsgRepayLoanResponse, error) { - ctx := sdk.UnwrapSDKContext(goCtx) - loan, found := k.GetLoan(ctx, msg.Id) - if !found { - return nil, errorsmod.Wrapf(sdkerrors.ErrKeyNotFound, "key %d doesn't exist", msg.Id) - } - if loan.State != "approved" { - return nil, errorsmod.Wrapf(types.ErrWrongLoanState, "%v", loan.State) - } - lender, _ := sdk.AccAddressFromBech32(loan.Lender) - borrower, _ := sdk.AccAddressFromBech32(loan.Borrower) - if msg.Creator != loan.Borrower { - return nil, errorsmod.Wrap(sdkerrors.ErrUnauthorized, "Cannot repay: not the borrower") - } - amount, _ := sdk.ParseCoinsNormalized(loan.Amount) - fee, _ := sdk.ParseCoinsNormalized(loan.Fee) - collateral, _ := sdk.ParseCoinsNormalized(loan.Collateral) - err := k.bankKeeper.SendCoins(ctx, borrower, lender, amount) - if err != nil { - return nil, err - } - err = k.bankKeeper.SendCoins(ctx, borrower, lender, fee) - if err != nil { - return nil, err - } - err = k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, borrower, collateral) - if err != nil { - return nil, err - } - loan.State = "repayed" - k.SetLoan(ctx, loan) - return &types.MsgRepayLoanResponse{}, nil + ctx := sdk.UnwrapSDKContext(goCtx) + loan, found := k.GetLoan(ctx, msg.Id) + if !found { + return nil, errorsmod.Wrapf(sdkerrors.ErrKeyNotFound, "key %d doesn't exist", msg.Id) + } + if loan.State != "approved" { + return nil, errorsmod.Wrapf(types.ErrWrongLoanState, "%v", loan.State) + } + lender, _ := sdk.AccAddressFromBech32(loan.Lender) + borrower, _ := sdk.AccAddressFromBech32(loan.Borrower) + if msg.Creator != loan.Borrower { + return nil, errorsmod.Wrap(sdkerrors.ErrUnauthorized, "Cannot repay: not the borrower") + } + amount, _ := sdk.ParseCoinsNormalized(loan.Amount) + fee, _ := sdk.ParseCoinsNormalized(loan.Fee) + collateral, _ := sdk.ParseCoinsNormalized(loan.Collateral) + err := k.bankKeeper.SendCoins(ctx, borrower, lender, amount) + if err != nil { + return nil, err + } + err = k.bankKeeper.SendCoins(ctx, borrower, lender, fee) + if err != nil { + return nil, err + } + err = k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, borrower, collateral) + if err != nil { + return nil, err + } + loan.State = "repayed" + k.SetLoan(ctx, loan) + return &types.MsgRepayLoanResponse{}, nil } ``` @@ -343,44 +343,44 @@ func (k msgServer) RepayLoan(goCtx context.Context, msg *types.MsgRepayLoan) (*t package keeper import ( - "context" - "strconv" + "context" + "strconv" - errorsmod "cosmossdk.io/errors" - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "loan/x/loan/types" + "loan/x/loan/types" ) func (k msgServer) LiquidateLoan(goCtx context.Context, msg *types.MsgLiquidateLoan) (*types.MsgLiquidateLoanResponse, error) { - ctx := sdk.UnwrapSDKContext(goCtx) - loan, found := k.GetLoan(ctx, msg.Id) - if !found { - return nil, errorsmod.Wrapf(sdkerrors.ErrKeyNotFound, "key %d doesn't exist", msg.Id) - } - if loan.Lender != msg.Creator { - return nil, errorsmod.Wrap(sdkerrors.ErrUnauthorized, "Cannot liquidate: not the lender") - } - if loan.State != "approved" { - return nil, errorsmod.Wrapf(types.ErrWrongLoanState, "%v", loan.State) - } - lender, _ := sdk.AccAddressFromBech32(loan.Lender) - collateral, _ := sdk.ParseCoinsNormalized(loan.Collateral) - deadline, err := strconv.ParseInt(loan.Deadline, 10, 64) - if err != nil { - panic(err) - } - if ctx.BlockHeight() < deadline { - return nil, errorsmod.Wrap(types.ErrDeadline, "Cannot liquidate before deadline") - } - err = k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, lender, collateral) - if err != nil { - return nil, err - } - loan.State = "liquidated" - k.SetLoan(ctx, loan) - return &types.MsgLiquidateLoanResponse{}, nil + ctx := sdk.UnwrapSDKContext(goCtx) + loan, found := k.GetLoan(ctx, msg.Id) + if !found { + return nil, errorsmod.Wrapf(sdkerrors.ErrKeyNotFound, "key %d doesn't exist", msg.Id) + } + if loan.Lender != msg.Creator { + return nil, errorsmod.Wrap(sdkerrors.ErrUnauthorized, "Cannot liquidate: not the lender") + } + if loan.State != "approved" { + return nil, errorsmod.Wrapf(types.ErrWrongLoanState, "%v", loan.State) + } + lender, _ := sdk.AccAddressFromBech32(loan.Lender) + collateral, _ := sdk.ParseCoinsNormalized(loan.Collateral) + deadline, err := strconv.ParseInt(loan.Deadline, 10, 64) + if err != nil { + panic(err) + } + if ctx.BlockHeight() < deadline { + return nil, errorsmod.Wrap(types.ErrDeadline, "Cannot liquidate before deadline") + } + err = k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, lender, collateral) + if err != nil { + return nil, err + } + loan.State = "liquidated" + k.SetLoan(ctx, loan) + return &types.MsgLiquidateLoanResponse{}, nil } ``` @@ -390,12 +390,12 @@ Add the custom errors `ErrWrongLoanState` and `ErrDeadline`: package types import ( - sdkerrors "cosmossdk.io/errors" + sdkerrors "cosmossdk.io/errors" ) var ( - ErrWrongLoanState = sdkerrors.Register(ModuleName, 2, "wrong loan state") - ErrDeadline = sdkerrors.Register(ModuleName, 3, "deadline") + ErrWrongLoanState = sdkerrors.Register(ModuleName, 2, "wrong loan state") + ErrDeadline = sdkerrors.Register(ModuleName, 3, "deadline") ) ``` diff --git a/docs/docs/02-guide/09-docker.md b/docs/docs/02-guide/09-docker.md index 77edaa31ab..f1c27d3fa6 100644 --- a/docs/docs/02-guide/09-docker.md +++ b/docs/docs/02-guide/09-docker.md @@ -125,7 +125,7 @@ points to the `0.25.2` tag. You can specify to use a specific version of Ignite CLI. All available tags are in the [ignite/cli -image](https://hub.docker.com/r/ignite/cli/tags?page=1&ordering=last_updated) on +image](https://hub.docker.com/r/ignitehq/cli/tags?page=1&ordering=last_updated) on Docker Hub. For example: diff --git a/docs/versioned_docs/version-v0.26/02-guide/09-docker.md b/docs/versioned_docs/version-v0.26/02-guide/09-docker.md index 77edaa31ab..f1c27d3fa6 100644 --- a/docs/versioned_docs/version-v0.26/02-guide/09-docker.md +++ b/docs/versioned_docs/version-v0.26/02-guide/09-docker.md @@ -125,7 +125,7 @@ points to the `0.25.2` tag. You can specify to use a specific version of Ignite CLI. All available tags are in the [ignite/cli -image](https://hub.docker.com/r/ignite/cli/tags?page=1&ordering=last_updated) on +image](https://hub.docker.com/r/ignitehq/cli/tags?page=1&ordering=last_updated) on Docker Hub. For example: diff --git a/docs/versioned_docs/version-v0.27/02-guide/09-docker.md b/docs/versioned_docs/version-v0.27/02-guide/09-docker.md index 77edaa31ab..f1c27d3fa6 100644 --- a/docs/versioned_docs/version-v0.27/02-guide/09-docker.md +++ b/docs/versioned_docs/version-v0.27/02-guide/09-docker.md @@ -125,7 +125,7 @@ points to the `0.25.2` tag. You can specify to use a specific version of Ignite CLI. All available tags are in the [ignite/cli -image](https://hub.docker.com/r/ignite/cli/tags?page=1&ordering=last_updated) on +image](https://hub.docker.com/r/ignitehq/cli/tags?page=1&ordering=last_updated) on Docker Hub. For example: diff --git a/docs/versioned_docs/version-v28/02-guide/09-docker.md b/docs/versioned_docs/version-v28/02-guide/09-docker.md index 77edaa31ab..f1c27d3fa6 100644 --- a/docs/versioned_docs/version-v28/02-guide/09-docker.md +++ b/docs/versioned_docs/version-v28/02-guide/09-docker.md @@ -125,7 +125,7 @@ points to the `0.25.2` tag. You can specify to use a specific version of Ignite CLI. All available tags are in the [ignite/cli -image](https://hub.docker.com/r/ignite/cli/tags?page=1&ordering=last_updated) on +image](https://hub.docker.com/r/ignitehq/cli/tags?page=1&ordering=last_updated) on Docker Hub. For example: diff --git a/ignite/pkg/cosmostxcollector/mocks/saver.go b/ignite/pkg/cosmostxcollector/mocks/saver.go index 2e726c3a1d..816c691e2b 100644 --- a/ignite/pkg/cosmostxcollector/mocks/saver.go +++ b/ignite/pkg/cosmostxcollector/mocks/saver.go @@ -5,8 +5,9 @@ package mocks import ( context "context" - cosmosclient "github.com/ignite/cli/v28/ignite/pkg/cosmosclient" mock "github.com/stretchr/testify/mock" + + cosmosclient "github.com/ignite/cli/v28/ignite/pkg/cosmosclient" ) // Saver is an autogenerated mock type for the Saver type diff --git a/ignite/services/plugin/grpc/v1/client_api.pb.go b/ignite/services/plugin/grpc/v1/client_api.pb.go index c721fec72a..eb5942fd13 100644 --- a/ignite/services/plugin/grpc/v1/client_api.pb.go +++ b/ignite/services/plugin/grpc/v1/client_api.pb.go @@ -7,10 +7,11 @@ package v1 import ( - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" ) const ( diff --git a/ignite/services/plugin/grpc/v1/interface.pb.go b/ignite/services/plugin/grpc/v1/interface.pb.go index b4ea08b1b8..3c42937d95 100644 --- a/ignite/services/plugin/grpc/v1/interface.pb.go +++ b/ignite/services/plugin/grpc/v1/interface.pb.go @@ -7,10 +7,11 @@ package v1 import ( - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" ) const ( diff --git a/ignite/services/plugin/grpc/v1/service.pb.go b/ignite/services/plugin/grpc/v1/service.pb.go index 54737533f0..a80f1ca676 100644 --- a/ignite/services/plugin/grpc/v1/service.pb.go +++ b/ignite/services/plugin/grpc/v1/service.pb.go @@ -7,10 +7,11 @@ package v1 import ( - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" ) const ( diff --git a/ignite/services/plugin/grpc/v1/service_grpc.pb.go b/ignite/services/plugin/grpc/v1/service_grpc.pb.go index f369c94a1e..759410d156 100644 --- a/ignite/services/plugin/grpc/v1/service_grpc.pb.go +++ b/ignite/services/plugin/grpc/v1/service_grpc.pb.go @@ -8,6 +8,7 @@ package v1 import ( context "context" + grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" diff --git a/ignite/services/plugin/mocks/interface.go b/ignite/services/plugin/mocks/interface.go index 1714bb1d48..6c632f50fc 100644 --- a/ignite/services/plugin/mocks/interface.go +++ b/ignite/services/plugin/mocks/interface.go @@ -5,9 +5,9 @@ package mocks import ( context "context" - plugin "github.com/ignite/cli/v28/ignite/services/plugin" mock "github.com/stretchr/testify/mock" + plugin "github.com/ignite/cli/v28/ignite/services/plugin" v1 "github.com/ignite/cli/v28/ignite/services/plugin/grpc/v1" ) diff --git a/integration/plugin/testdata/example-plugin/go.mod b/integration/plugin/testdata/example-plugin/go.mod index 3e6c339c94..4f000e4ab4 100644 --- a/integration/plugin/testdata/example-plugin/go.mod +++ b/integration/plugin/testdata/example-plugin/go.mod @@ -17,7 +17,7 @@ require ( github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/aymerick/douceur v0.2.0 // indirect github.com/charmbracelet/lipgloss v0.6.0 // indirect - github.com/cloudflare/circl v1.3.3 // indirect + github.com/cloudflare/circl v1.3.7 // indirect github.com/cyphar/filepath-securejoin v0.2.4 // indirect github.com/emirpasic/gods v1.18.1 // indirect github.com/fatih/color v1.15.0 // indirect @@ -25,7 +25,7 @@ require ( github.com/getsentry/sentry-go v0.25.0 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect github.com/go-git/go-billy/v5 v5.5.0 // indirect - github.com/go-git/go-git/v5 v5.10.0 // indirect + github.com/go-git/go-git/v5 v5.11.0 // indirect github.com/gobuffalo/flect v0.3.0 // indirect github.com/gobuffalo/genny/v2 v2.1.0 // indirect github.com/gobuffalo/github_flavored_markdown v1.1.4 // indirect @@ -59,7 +59,7 @@ require ( github.com/rogpeppe/go-internal v1.11.0 // indirect github.com/sergi/go-diff v1.3.1 // indirect github.com/sirupsen/logrus v1.9.3 // indirect - github.com/skeema/knownhosts v1.2.0 // indirect + github.com/skeema/knownhosts v1.2.1 // indirect github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d // indirect github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e // indirect github.com/spf13/cobra v1.8.0 // indirect @@ -69,15 +69,15 @@ require ( golang.org/x/crypto v0.17.0 // indirect golang.org/x/exp v0.0.0-20231108232855-2478ac86f678 // indirect golang.org/x/mod v0.14.0 // indirect - golang.org/x/net v0.18.0 // indirect + golang.org/x/net v0.19.0 // indirect golang.org/x/sync v0.5.0 // indirect golang.org/x/sys v0.15.0 // indirect golang.org/x/term v0.15.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/tools v0.15.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405 // indirect - google.golang.org/grpc v1.59.0 // indirect - google.golang.org/protobuf v1.31.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20231212172506-995d672761c0 // indirect + google.golang.org/grpc v1.60.1 // indirect + google.golang.org/protobuf v1.32.0 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect ) From b1fe19dc18ba1be816a8e8487c7aa403b0d7abe9 Mon Sep 17 00:00:00 2001 From: Tobias <8368497+toschdev@users.noreply.github.com> Date: Mon, 29 Jan 2024 11:58:20 +0100 Subject: [PATCH 03/10] docs: Add migration guide v0.27 to v28 (#3884) This PR aims to provide a chain migration guide from v0.27 to v0.28 Feedback on what else changed is welcome --- docs/docs/06-migration/v0.28.0.md | 17 ---- docs/docs/06-migration/v28.0.0.md | 124 ++++++++++++++++++++++++++++++ 2 files changed, 124 insertions(+), 17 deletions(-) delete mode 100644 docs/docs/06-migration/v0.28.0.md create mode 100644 docs/docs/06-migration/v28.0.0.md diff --git a/docs/docs/06-migration/v0.28.0.md b/docs/docs/06-migration/v0.28.0.md deleted file mode 100644 index 5484d9d482..0000000000 --- a/docs/docs/06-migration/v0.28.0.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -sidebar_position: 990 -title: v0.28.0 -description: For chains that were scaffolded with Ignite CLI versions lower than v0.28.0. changes are required to use Ignite CLI v0.28.0. ---- - -## Upgrading legacy plugins configuration files - -Ignite `v0.28.0` changes the plugin system which is now called Ignite Apps. This version includes changes -to the CLI command names and the plugin configuration file. - -The plugins configuration file is now called `igniteapps.yml` and the "plugins" section is now called "apps". - -The global plugins directory is now `$HOME/.ignite/apps` instead `$HOME/.ignite/plugins`. - -Updates can be automatically applied by running `ignite doctor` in your blockchain application directory. -Running the command outside your blockchain application directory will only update the global plugins. diff --git a/docs/docs/06-migration/v28.0.0.md b/docs/docs/06-migration/v28.0.0.md new file mode 100644 index 0000000000..9c618fefd8 --- /dev/null +++ b/docs/docs/06-migration/v28.0.0.md @@ -0,0 +1,124 @@ +--- +sidebar_position: 990 +title: v28.0.0 +description: For chains that were scaffolded with Ignite CLI versions lower than v28.0.0 changes are required to use Ignite CLI v28.0.0 +--- + +## **Upgrade to v28.0.0 - New Versioning Scheme in Ignite** + +With the latest update, Ignite has transitioned its versioning format from a leading-zero release system to a full number release system. This change marks a significant shift in how we communicate updates and stability in our software. Where the previous version was denoted as v0.27.0, it will now be upgraded to v28.0.0. + +This new versioning approach enhances our version control by clearly indicating major, minor, and patch releases. +From now on first number indicates a major release with breaking API changes, second number indicates minor release that might include new features while the last number is typically focused on bug fixes and minor improvements. +[Learn more about semantic versioning](https://semver.org/). + +## **Plugins are now called Apps. Upgrade Configuration Files** + +Ignite `v28.0.0` changes the plugin system which is now called Ignite Apps. This version includes changes +to the CLI command names and the plugin configuration file. + +The plugins configuration file is now called `igniteapps.yml` and "plugins" are now called "apps". + +The plugins configuration home directory is now `$HOME/.ignite/apps` instead `$HOME/.ignite/plugins`. + +Updates can be automatically applied by running `ignite doctor` in your blockchain application directory. +Running the command outside your blockchain application directory will only update the global plugins. + +## **Ignite and Cosmos SDK Upgrade Guide: From Ignite v0.27.0 to v28.0.0 and Cosmos SDK v0.47 to v0.50** + +### **Introduction** + +This guide provides a step-by-step process for developers to upgrade their applications from Ignite version 0.27.0 to 28.0.0, along with an upgrade in the Cosmos SDK from version 0.47 to v0.50. It covers essential changes, new features, and adjustments required for a smooth transition. + +### **Prerequisites** + +- Backup your current project. +- Ensure you have Ignite v0.27.0 and Cosmos SDK v0.47 installed. +- Basic familiarity with command line operations and the existing project structure. + +### **Step 1: Update Ignite CLI to Version 28.0.0** + +- **Command**: Run **`curl https://get.ignite.com/cli@v28.0.0 | bash`** in your terminal. +- **Note**: This command updates the Ignite CLI to the latest version. Ensure you have the necessary permissions to execute it. + +### **Step 2: Update Scaffold Chain Command** + +- **Old Command**: **`ignite scaffold chain github.com/alice/blog`** +- **New Command**: **`ignite scaffold chain blog`** +- **Explanation**: The command format has been simplified in the new version for ease of use. + +### **Step 3: Docker Version Upgrades** + +- **Action**: Upgrade the Ignite version for the Docker container to match the CLI version. +- **Note**: Ensure Docker compatibility with the new Ignite CLI version. + +### **Step 4: Change in Module Path** + +- **Old Path**: **`x/blog/module.go`** +- **New Path**: **`x/blog/module/module.go`** +- **Explanation**: The module path structure has been updated for better organization. + +### **Step 5: Frontend Scaffolding Options** + +- **Action**: Choose between Vue, React, Go, or TypeScript for frontend scaffolding. +- **Commands**: + - **`ignite scaffold react`** + - **`ignite scaffold vue`** +- **Note**: Vue is no longer the default option for frontend scaffolding. + +### **Step 6: Update Scaffold Message for CreatePost Command** + +- **Action**: Review and update the output for the scaffolded createPost command as per the new format. + +### **Step 7: AutoCLI Path Change** + +- **Old Path**: **`x/blog/client/cli/tx_create_post.go`** +- **New Path**: **`x/blog/module/autocli.go`** +- **Explanation**: AutoCLI is now integrated at a different path to streamline command-line interactions. + +### **Step 8: Adjustment in Stored Game** + +- **Old Code**: + + ```go + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.PostKey)) + + ``` + +- **New Code**: + + ```go + storeAdapter := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) + store := prefix.NewStore(storeAdapter, types.KeyPrefix(types.PostKey)) + + ``` + +- **Explanation**: The way the KVStore is accessed has changed, requiring an update in the code for stored games. + +### **Step 9: Chain-ID Requirements in CLI Transaction Commands** + +- **Action**: Add **`-chain-id`** flag to CLI transaction commands. +- **Example**: + - **Old Command**: **`blogd tx blog create-post 'Hello, World!' 'This is a blog post' --from alice`** + - **New Command**: **`blogd tx blog create-post 'Hello, World!' 'This is a blog post' --from alice --chain-id blog`** +- **Explanation**: The **`chain-id`** flag is now required for transaction commands for identification purposes. + +### **Troubleshooting Common Issues** + +- **Dependency Conflicts**: Ensure compatibility of all dependencies with Ignite v28.0.0 and Cosmos SDK v0.50. +- **Docker Image Compatibility**: Align Docker image versions with the CLI for seamless operations. +- **Frontend Scaffolding**: For older projects, ensure correct scaffolding as per the new commands. +- **AutoCLI Integration**: Address discrepancies due to the new AutoCLI integration path. + +### **Additional Resources** + +- [Ignite Documentation](https://docs.ignite.com/) +- [Cosmos SDK Release Notes](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.50.1) + +### **Feedback** + +We value your feedback on this guide. Please share your experiences and suggestions for improvements. + +### **Updates Log** + +- **[01/15/24]**: Guide created for Ignite v28.0.0 and Cosmos SDK v0.50.1 \ No newline at end of file From 8b76eed46311b02e985dfb6a043ed4bae37b7a73 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Mon, 29 Jan 2024 13:59:26 +0100 Subject: [PATCH 04/10] refactor(analytics): flag CI in analytics (#3918) * refactor(analytics): disable analytics in CI * flag ci instead of skipping --- ignite/internal/analytics/analytics.go | 12 ++++++++++-- ignite/pkg/gacli/gacli.go | 1 + 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/ignite/internal/analytics/analytics.go b/ignite/internal/analytics/analytics.go index ee99314693..5dfd6482ea 100644 --- a/ignite/internal/analytics/analytics.go +++ b/ignite/internal/analytics/analytics.go @@ -20,6 +20,7 @@ import ( const ( telemetryEndpoint = "https://telemetry-cli.ignite.com" envDoNotTrack = "DO_NOT_TRACK" + envCI = "CI" igniteDir = ".ignite" igniteAnonIdentity = "anon_identity.json" ) @@ -28,9 +29,9 @@ var gaclient gacli.Client // anonIdentity represents an analytics identity file. type anonIdentity struct { - // name represents the username. + // Name represents the username. Name string `json:"name" yaml:"name"` - // doNotTrack represents the user track choice. + // DoNotTrack represents the user track choice. DoNotTrack bool `json:"doNotTrack" yaml:"doNotTrack"` } @@ -59,6 +60,7 @@ func SendMetric(wg *sync.WaitGroup, cmd *cobra.Command) { SessionID: dntInfo.Name, Version: version.Version, IsGitPod: gitpod.IsOnGitpod(), + IsCI: getIsCI(), } wg.Add(1) @@ -122,3 +124,9 @@ func checkDNT() (anonIdentity, error) { return i, os.WriteFile(identityPath, data, 0o700) } + +func getIsCI() bool { + str := strings.ToLower(os.Getenv(envCI)) + + return str == "1" || str == "true" +} diff --git a/ignite/pkg/gacli/gacli.go b/ignite/pkg/gacli/gacli.go index 4449189b9d..306df37712 100644 --- a/ignite/pkg/gacli/gacli.go +++ b/ignite/pkg/gacli/gacli.go @@ -40,6 +40,7 @@ type ( SessionID string `json:"session_id,omitempty"` EngagementTimeMsec string `json:"engagement_time_msec,omitempty"` IsGitPod bool `json:"is_git_pod,omitempty"` + IsCI bool `json:"is_ci,omitempty"` } ) From b38c23098ae7962d8e702d174e51f3560836305d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 29 Jan 2024 18:09:46 -0300 Subject: [PATCH 05/10] docs(cli): update generated docs (#3906) Co-authored-by: julienrbrt --- docs/docs/08-references/01-cli.md | 179 ++---------------------------- 1 file changed, 8 insertions(+), 171 deletions(-) diff --git a/docs/docs/08-references/01-cli.md b/docs/docs/08-references/01-cli.md index 9f64410625..7e5ab3e21a 100644 --- a/docs/docs/08-references/01-cli.md +++ b/docs/docs/08-references/01-cli.md @@ -31,7 +31,7 @@ To get started, create a blockchain: * [ignite account](#ignite-account) - Create, delete, and show Ignite accounts * [ignite app](#ignite-app) - Create and manage Ignite Apps * [ignite chain](#ignite-chain) - Build, init and start a blockchain node -* [ignite completion](#ignite-completion) - Generate the autocompletion script for the specified shell +* [ignite completion](#ignite-completion) - Generates shell completion script. * [ignite docs](#ignite-docs) - Show Ignite CLI docs * [ignite generate](#ignite-generate) - Generate clients, API docs from source code * [ignite network](#ignite-network) - Launch a blockchain in production @@ -578,7 +578,7 @@ ignite chain build [flags] **Options** ``` - --build.tags strings parameters to build the chain binary (default [app_v1]) + --build.tags strings parameters to build the chain binary --check-dependencies verify that cached dependencies have not been modified since they were downloaded --clear-cache clear the build cache (advanced) --debug build a debug binary @@ -766,7 +766,7 @@ ignite chain init [flags] **Options** ``` - --build.tags strings parameters to build the chain binary (default [app_v1]) + --build.tags strings parameters to build the chain binary --check-dependencies verify that cached dependencies have not been modified since they were downloaded --clear-cache clear the build cache (advanced) --debug build a debug binary @@ -835,7 +835,7 @@ ignite chain serve [flags] **Options** ``` - --build.tags strings parameters to build the chain binary (default [app_v1]) + --build.tags strings parameters to build the chain binary --check-dependencies verify that cached dependencies have not been modified since they were downloaded --clear-cache clear the build cache (advanced) -f, --force-reset force reset of the app state on start and every source change @@ -909,184 +909,21 @@ ignite chain simulate [flags] ## ignite completion -Generate the autocompletion script for the specified shell - -**Synopsis** - -Generate the autocompletion script for ignite for the specified shell. -See each sub-command's help for details on how to use the generated script. - - -**Options** - -``` - -h, --help help for completion -``` - -**SEE ALSO** - -* [ignite](#ignite) - Ignite CLI offers everything you need to scaffold, test, build, and launch your blockchain -* [ignite completion bash](#ignite-completion-bash) - Generate the autocompletion script for bash -* [ignite completion fish](#ignite-completion-fish) - Generate the autocompletion script for fish -* [ignite completion powershell](#ignite-completion-powershell) - Generate the autocompletion script for powershell -* [ignite completion zsh](#ignite-completion-zsh) - Generate the autocompletion script for zsh - - -## ignite completion bash - -Generate the autocompletion script for bash - -**Synopsis** - -Generate the autocompletion script for the bash shell. - -This script depends on the 'bash-completion' package. -If it is not installed already, you can install it via your OS's package manager. - -To load completions in your current shell session: - - source <(ignite completion bash) - -To load completions for every new session, execute once: - -**#### Linux:** - - ignite completion bash > /etc/bash_completion.d/ignite - -**#### macOS:** - - ignite completion bash > $(brew --prefix)/etc/bash_completion.d/ignite - -You will need to start a new shell for this setup to take effect. - - -``` -ignite completion bash -``` - -**Options** - -``` - -h, --help help for bash - --no-descriptions disable completion descriptions -``` - -**SEE ALSO** - -* [ignite completion](#ignite-completion) - Generate the autocompletion script for the specified shell - - -## ignite completion fish - -Generate the autocompletion script for fish - -**Synopsis** - -Generate the autocompletion script for the fish shell. - -To load completions in your current shell session: - - ignite completion fish | source - -To load completions for every new session, execute once: - - ignite completion fish > ~/.config/fish/completions/ignite.fish - -You will need to start a new shell for this setup to take effect. - - -``` -ignite completion fish [flags] -``` - -**Options** - -``` - -h, --help help for fish - --no-descriptions disable completion descriptions -``` - -**SEE ALSO** - -* [ignite completion](#ignite-completion) - Generate the autocompletion script for the specified shell - - -## ignite completion powershell - -Generate the autocompletion script for powershell - -**Synopsis** - -Generate the autocompletion script for powershell. - -To load completions in your current shell session: - - ignite completion powershell | Out-String | Invoke-Expression - -To load completions for every new session, add the output of the above command -to your powershell profile. - - -``` -ignite completion powershell [flags] -``` - -**Options** - -``` - -h, --help help for powershell - --no-descriptions disable completion descriptions -``` - -**SEE ALSO** - -* [ignite completion](#ignite-completion) - Generate the autocompletion script for the specified shell - - -## ignite completion zsh - -Generate the autocompletion script for zsh - -**Synopsis** - -Generate the autocompletion script for the zsh shell. - -If shell completion is not already enabled in your environment you will need -to enable it. You can execute the following once: - - echo "autoload -U compinit; compinit" >> ~/.zshrc - -To load completions in your current shell session: - - source <(ignite completion zsh) - -To load completions for every new session, execute once: - -**#### Linux:** - - ignite completion zsh > "${fpath[1]}/_ignite" - -**#### macOS:** - - ignite completion zsh > $(brew --prefix)/share/zsh/site-functions/_ignite - -You will need to start a new shell for this setup to take effect. - +Generates shell completion script. ``` -ignite completion zsh [flags] +ignite completion [bash|zsh|fish|powershell] [flags] ``` **Options** ``` - -h, --help help for zsh - --no-descriptions disable completion descriptions + -h, --help help for completion ``` **SEE ALSO** -* [ignite completion](#ignite-completion) - Generate the autocompletion script for the specified shell +* [ignite](#ignite) - Ignite CLI offers everything you need to scaffold, test, build, and launch your blockchain ## ignite docs From 2900024ef0386bac9cd2c92c366d0f649ee56370 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Mon, 29 Jan 2024 22:17:26 +0100 Subject: [PATCH 06/10] docs: add release process (#3913) Add release process. --- release_process.md | 70 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) diff --git a/release_process.md b/release_process.md index 14c17106a3..2a8d82963f 100644 --- a/release_process.md +++ b/release_process.md @@ -1,3 +1,71 @@ # Release Process - \ No newline at end of file +This document outlines the release process for Ignite. It ensures consistency, quality, and clear communication with users. +Ignite uses [semantic versioning](https://semver.org/) to indicate the stability and compatibility of releases. + +## Release Branches + +Releases are tagged from release branches. The release branch is typically named after the release version, such as `release/v28.x.y` or `release/v30.x.y`. The release branch is created from the `main` branch and contains all the changes that will be included in the release. + +## Development Branch + +The `main` branch is the development branch for Ignite. All new features and bug fixes are developed on this branch. The `main` branch is typically updated daily or weekly, depending on the amount of development activity. + +## Backporting Features and Bug Fixes + +Features or bug fixes that are ready to be included in a release must be backported from the `main` branch to the release branch. This is done using Mergify, a CI/CD tool that automates the process of backporting changes. Add the `backport release/x.y.z` label to a pull request (PR) to indicate that it should be backported to the release branch. Mergify will automatically backport the PR when it is merged into the `main` branch. + +## All PRs Target Main + +All PRs should target the `main` branch. This ensures that changes are always integrated into the development branch and are ready for backporting. + +## Changelog + +The changelog lists all of the changes that have been made to Ignite since the last release. The changelog must be up-to-date before a release is made. + +## Release Preparation and Testing + +Before a release is made, it is important to prepare the release branches and perform thorough testing. +The process differs depending on whether the release is a `MAJOR`, `MINOR`, or `PATCH` release. + +### Major Release + +* Freeze the `main` branch. +* Create a release branch from the `main` branch. + * Update `.github/mergify.yml` to allow backporting changes to the release branch. + * Possibly update CI/CD configuration to support the new release. +* Running all unit tests, integration tests, and manual scenarios. +* Ensuring that the release branch is still compatible with all supported environments. +* Prepare the changelog. + +### Minor and Patch Releases + +* Verifying that all wanted changes have been backported to the release branch. +* Running all unit tests, integration tests, and manual scenarios. +* Ensuring that the release branch is still compatible with all supported environments. +* Prepare the changelog. + +## Release Publication + +Once the release is ready, it can be published to the [releases page](https://github.com/ignite/cli/releases) on GitHub. This involves tagging the release branch with the release version and creating a release announcement. The release anouncement should contain the changelog of the release. + +```bash +git checkout release/v28.x.y +git tag v28.x.y -m "Release Ignite v28.x.y" +``` + +## Post-Release Activities + +After a release has been made, it is important to monitor feedback and bug reports to inform subsequent releases. + +This includes updating the `main` branch changelog with the new release. + +In case of a new `MAJOR` release, the release author must also update the `main` branch to the next `MAJOR` version number: rename the `go.mod` and all references to the version number in the codebase. + +## Maintenance Policy + +Only the latest released version of Ignite is maintained for new features and bug fixes. Older versions may continue to function, but they will not receive any updates. This ensures that Ignite remains stable and reliable for all users. + +Users are encouraged to upgrade to the latest release as soon as possible to benefit from the latest features and security updates. +Ignite ensures compatibility for the `chain` and `app` commands between major releases. +Other commands may change between major releases and may require the user to upgrade their codebase to the Cosmos SDK version Ignite is using. From 86ebb5582fbc4d20de34b39b1714bd80c5ca57a9 Mon Sep 17 00:00:00 2001 From: Ehsan-saradar Date: Tue, 30 Jan 2024 01:27:38 +0330 Subject: [PATCH 07/10] feat: Improve app scaffolding (#3839) * Add new structure for app scaffolding * Fix some minor issues * Fix integration test plush * Add go mod tidy and fmt to scaffolding apps * Add changelog * Fix tests * Fix integration test package name * New app.ignite.yml format * Add AppYML * Add go.work.sum to app scaffold .gitignore * Upgrade app scaffold go.mod * Rename AppYML to AppsConfig * Add additional test for app scaffolding * Fix changelog * Improve app testing * Fix app_test.go * Move to cobra independent arch for app scaffolding * Fix plugin test * Fix changelog * Increase app scaffold integration test time * Update ignite/services/plugin/template/cmd/hello.go.plush Co-authored-by: Julien Robert * Update ignite/services/plugin/template/integration/app_test.go.plush Co-authored-by: Danny * Update ignite/services/plugin/template/cmd/cmd.go.plush Co-authored-by: Danny * Update ignite/services/plugin/template/app.ignite.yml.plush Co-authored-by: Danny * Update ignite/services/plugin/template/.gitignore.plush Co-authored-by: Danny --------- Co-authored-by: Danilo Pantani Co-authored-by: Julien Robert Co-authored-by: Danny --- changelog.md | 1 + ignite/pkg/gocmd/gocmd.go | 12 ++ ignite/services/plugin/apps_config.go | 14 +++ ignite/services/plugin/plugin_test.go | 2 +- ignite/services/plugin/scaffold.go | 17 +++ ignite/services/plugin/scaffold_test.go | 21 ++++ .../services/plugin/template/.gitignore.plush | 22 ++++ .../plugin/template/app.ignite.yml.plush | 6 + .../services/plugin/template/cmd/cmd.go.plush | 19 ++++ .../plugin/template/cmd/hello.go.plush | 14 +++ ignite/services/plugin/template/go.mod.plush | 1 + .../template/integration/app_test.go.plush | 70 ++++++++++++ ignite/services/plugin/template/main.go.plush | 105 +++--------------- 13 files changed, 215 insertions(+), 89 deletions(-) create mode 100644 ignite/services/plugin/apps_config.go create mode 100644 ignite/services/plugin/template/app.ignite.yml.plush create mode 100644 ignite/services/plugin/template/cmd/cmd.go.plush create mode 100644 ignite/services/plugin/template/cmd/hello.go.plush create mode 100644 ignite/services/plugin/template/integration/app_test.go.plush diff --git a/changelog.md b/changelog.md index 09b45bd136..8b7cc0e520 100644 --- a/changelog.md +++ b/changelog.md @@ -4,6 +4,7 @@ ### Features +- [#3839](https://github.com/ignite/cli/pull/3839) New structure for app scaffolding - [#3835](https://github.com/ignite/cli/pull/3835) Add `--minimal` flag to `scaffold chain` to scaffold a chain with the least amount of sdk modules ### Changes diff --git a/ignite/pkg/gocmd/gocmd.go b/ignite/pkg/gocmd/gocmd.go index 13d9560803..ef4ee23e40 100644 --- a/ignite/pkg/gocmd/gocmd.go +++ b/ignite/pkg/gocmd/gocmd.go @@ -45,6 +45,9 @@ const ( // CommandList represents go "list" command. CommandList = "list" + // CommandTest represents go "test" command. + CommandTest = "test" + // EnvGOARCH represents GOARCH variable. EnvGOARCH = "GOARCH" // EnvGOMOD represents GOMOD variable. @@ -199,6 +202,15 @@ func List(ctx context.Context, path string, flags []string, options ...exec.Opti return strings.Fields(b.String()), nil } +func Test(ctx context.Context, path string, flags []string, options ...exec.Option) error { + command := []string{ + Name(), + CommandTest, + } + command = append(command, flags...) + return exec.Exec(ctx, command, append(options, exec.StepOption(step.Workdir(path)))...) +} + // Ldflags returns a combined ldflags set from flags. func Ldflags(flags ...string) string { return strings.Join(flags, " ") diff --git a/ignite/services/plugin/apps_config.go b/ignite/services/plugin/apps_config.go new file mode 100644 index 0000000000..7333867af1 --- /dev/null +++ b/ignite/services/plugin/apps_config.go @@ -0,0 +1,14 @@ +package plugin + +// AppsConfig is the structure of app.ignite.yml file. +type AppsConfig struct { + Version uint `yaml:"version"` + Apps map[string]AppInfo `yaml:"apps"` +} + +// AppInfo is the structure of app info in app.ignite.yml file which only holds +// the description and the relative path of the app. +type AppInfo struct { + Description string `yaml:"description"` + Path string `yaml:"path"` +} diff --git a/ignite/services/plugin/plugin_test.go b/ignite/services/plugin/plugin_test.go index 7dc6b9efdd..c0a4750f7d 100644 --- a/ignite/services/plugin/plugin_test.go +++ b/ignite/services/plugin/plugin_test.go @@ -387,7 +387,7 @@ func TestPluginLoad(t *testing.T) { manifest, err := p.Interface.Manifest(ctx) require.NoError(err) assert.Equal(p.name, manifest.Name) - assert.NoError(p.Interface.Execute(ctx, &ExecutedCommand{}, clientAPI)) + assert.NoError(p.Interface.Execute(ctx, &ExecutedCommand{OsArgs: []string{"ignite", p.name, "hello"}}, clientAPI)) assert.NoError(p.Interface.ExecuteHookPre(ctx, &ExecutedHook{}, clientAPI)) assert.NoError(p.Interface.ExecuteHookPost(ctx, &ExecutedHook{}, clientAPI)) assert.NoError(p.Interface.ExecuteHookCleanUp(ctx, &ExecutedHook{}, clientAPI)) diff --git a/ignite/services/plugin/scaffold.go b/ignite/services/plugin/scaffold.go index cd82fe45ae..e3500d0597 100644 --- a/ignite/services/plugin/scaffold.go +++ b/ignite/services/plugin/scaffold.go @@ -6,11 +6,15 @@ import ( "os" "path" "path/filepath" + "strings" "github.com/gobuffalo/genny/v2" "github.com/gobuffalo/plush/v4" + "golang.org/x/text/cases" + "golang.org/x/text/language" "github.com/ignite/cli/v28/ignite/pkg/errors" + "github.com/ignite/cli/v28/ignite/pkg/gocmd" "github.com/ignite/cli/v28/ignite/pkg/xgenny" ) @@ -21,6 +25,7 @@ var fsPluginSource embed.FS func Scaffold(ctx context.Context, dir, moduleName string, sharedHost bool) (string, error) { var ( name = filepath.Base(moduleName) + title = toTitle(name) finalDir = path.Join(dir, name) g = genny.New() template = xgenny.NewEmbedWalker( @@ -42,6 +47,7 @@ func Scaffold(ctx context.Context, dir, moduleName string, sharedHost bool) (str pctx := plush.NewContextWithContext(ctx) pctx.Set("ModuleName", moduleName) pctx.Set("Name", name) + pctx.Set("Title", title) pctx.Set("SharedHost", sharedHost) g.Transformer(xgenny.Transformer(pctx)) @@ -55,5 +61,16 @@ func Scaffold(ctx context.Context, dir, moduleName string, sharedHost bool) (str return "", errors.WithStack(err) } + if err := gocmd.ModTidy(ctx, finalDir); err != nil { + return "", errors.WithStack(err) + } + if err := gocmd.Fmt(ctx, finalDir); err != nil { + return "", errors.WithStack(err) + } + return finalDir, nil } + +func toTitle(s string) string { + return strings.ReplaceAll(strings.ReplaceAll(cases.Title(language.English).String(s), "_", ""), "-", "") +} diff --git a/ignite/services/plugin/scaffold_test.go b/ignite/services/plugin/scaffold_test.go index a6b66a9db1..cf79655f99 100644 --- a/ignite/services/plugin/scaffold_test.go +++ b/ignite/services/plugin/scaffold_test.go @@ -2,10 +2,13 @@ package plugin import ( "context" + "os" "path/filepath" "testing" + "github.com/ignite/cli/v28/ignite/pkg/gocmd" "github.com/stretchr/testify/require" + "gopkg.in/yaml.v2" ) func TestScaffold(t *testing.T) { @@ -21,4 +24,22 @@ func TestScaffold(t *testing.T) { require.DirExists(t, path) require.FileExists(t, filepath.Join(path, "go.mod")) require.FileExists(t, filepath.Join(path, "main.go")) + + // app.ignite.yml check + appYML, err := os.ReadFile(filepath.Join(path, "app.ignite.yml")) + require.NoError(t, err) + var config AppsConfig + err = yaml.Unmarshal(appYML, &config) + require.NoError(t, err) + require.EqualValues(t, 1, config.Version) + require.Len(t, config.Apps, 1) + + // Integration test check + err = gocmd.Test(ctx, filepath.Join(path, "integration"), []string{ + "-timeout", + "5m", + "-run", + "^TestBar$", + }) + require.NoError(t, err) } diff --git a/ignite/services/plugin/template/.gitignore.plush b/ignite/services/plugin/template/.gitignore.plush index 1b8133ef7a..1c428025a7 100644 --- a/ignite/services/plugin/template/.gitignore.plush +++ b/ignite/services/plugin/template/.gitignore.plush @@ -1 +1,23 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib +*.ign + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ + +# Go workspace file +go.work +go.work.sum + +# App <%= Name %>* diff --git a/ignite/services/plugin/template/app.ignite.yml.plush b/ignite/services/plugin/template/app.ignite.yml.plush new file mode 100644 index 0000000000..d6156a0b80 --- /dev/null +++ b/ignite/services/plugin/template/app.ignite.yml.plush @@ -0,0 +1,6 @@ +version: 1 +apps: + <%= Name %>: + description: <%= Name %> is an awesome Ignite application! + path: ./ + \ No newline at end of file diff --git a/ignite/services/plugin/template/cmd/cmd.go.plush b/ignite/services/plugin/template/cmd/cmd.go.plush new file mode 100644 index 0000000000..d7d5cc17de --- /dev/null +++ b/ignite/services/plugin/template/cmd/cmd.go.plush @@ -0,0 +1,19 @@ +package cmd + +import "github.com/ignite/cli/v28/ignite/services/plugin" + +// GetCommands returns the list of <%= Name %> app commands. +func GetCommands() []*plugin.Command { + return []*plugin.Command{ + { + Use: "<%= Name %> [command]", + Short: "<%= Name %> is an awesome Ignite application!", + Commands: []*plugin.Command{ + { + Use: "hello", + Short: "Say hello to the world of ignite!", + }, + }, + }, + } +} diff --git a/ignite/services/plugin/template/cmd/hello.go.plush b/ignite/services/plugin/template/cmd/hello.go.plush new file mode 100644 index 0000000000..81c8116afc --- /dev/null +++ b/ignite/services/plugin/template/cmd/hello.go.plush @@ -0,0 +1,14 @@ +package cmd + +import ( + "context" + "fmt" + + "github.com/ignite/cli/v28/ignite/services/plugin" +) + +// ExecuteHello executes the hello subcommand. +func ExecuteHello(ctx context.Context, cmd *plugin.ExecutedCommand) error { + fmt.Println("Hello, world!") + return nil +} diff --git a/ignite/services/plugin/template/go.mod.plush b/ignite/services/plugin/template/go.mod.plush index 71ae3ecdf8..1ab1c690fa 100644 --- a/ignite/services/plugin/template/go.mod.plush +++ b/ignite/services/plugin/template/go.mod.plush @@ -5,4 +5,5 @@ go 1.21 require ( github.com/hashicorp/go-plugin v1.5.0 github.com/ignite/cli/v28 v28.0.0 + github.com/stretchr/testify v1.8.4 ) diff --git a/ignite/services/plugin/template/integration/app_test.go.plush b/ignite/services/plugin/template/integration/app_test.go.plush new file mode 100644 index 0000000000..0551c112c3 --- /dev/null +++ b/ignite/services/plugin/template/integration/app_test.go.plush @@ -0,0 +1,70 @@ +package integration_test + +import ( + "bytes" + "os" + "path/filepath" + "testing" + + "github.com/stretchr/testify/require" + + pluginsconfig "github.com/ignite/cli/v28/ignite/config/plugins" + "github.com/ignite/cli/v28/ignite/pkg/cmdrunner/step" + "github.com/ignite/cli/v28/ignite/services/plugin" + envtest "github.com/ignite/cli/v28/integration" +) + +func Test<%= Title %>(t *testing.T) { + var ( + require = require.New(t) + env = envtest.New(t) + app = env.Scaffold("github.com/test/test") + ) + + dir, err := os.Getwd() + require.NoError(err) + pluginPath := filepath.Join(filepath.Dir(filepath.Dir(dir)), "<%= Name %>") + + env.Must(env.Exec("install <%= Name %> app locally", + step.NewSteps(step.New( + step.Exec(envtest.IgniteApp, "app", "install", pluginPath), + step.Workdir(app.SourcePath()), + )), + )) + + // One local plugin expected + assertLocalPlugins(t, app, []pluginsconfig.Plugin{ + { + Path: pluginPath, + }, + }) + assertGlobalPlugins(t, app, nil) + + buf := &bytes.Buffer{} + env.Must(env.Exec("run <%= Name %>", + step.NewSteps(step.New( + step.Exec( + envtest.IgniteApp, + "<%= Name %>", + "hello", + ), + step.Workdir(app.SourcePath()), + step.Stdout(buf), + )), + )) + require.Equal("Hello, world!\n", buf.String()) +} + +func assertLocalPlugins(t *testing.T, app envtest.App, expectedPlugins []pluginsconfig.Plugin) { + cfg, err := pluginsconfig.ParseDir(app.SourcePath()) + require.NoError(t, err) + require.ElementsMatch(t, expectedPlugins, cfg.Apps, "unexpected local apps") +} + +func assertGlobalPlugins(t *testing.T, app envtest.App, expectedPlugins []pluginsconfig.Plugin) { + cfgPath, err := plugin.PluginsPath() + require.NoError(t, err) + cfg, err := pluginsconfig.ParseDir(cfgPath) + require.NoError(t, err) + require.ElementsMatch(t, expectedPlugins, cfg.Apps, "unexpected global apps") +} diff --git a/ignite/services/plugin/template/main.go.plush b/ignite/services/plugin/template/main.go.plush index 56d8b447c0..1224628072 100644 --- a/ignite/services/plugin/template/main.go.plush +++ b/ignite/services/plugin/template/main.go.plush @@ -3,118 +3,47 @@ package main import ( "context" "fmt" - "path/filepath" hplugin "github.com/hashicorp/go-plugin" - "github.com/ignite/cli/v28/ignite/services/chain" "github.com/ignite/cli/v28/ignite/services/plugin" + "<%= ModuleName %>/cmd" ) type app struct{} -func (app) Manifest(ctx context.Context) (*plugin.Manifest, error) { +func (app) Manifest(_ context.Context) (*plugin.Manifest, error) { return &plugin.Manifest{ - Name: "<%= Name %>", - // TODO: Add commands here - Commands: []*plugin.Command{ - // Example of a command - { - Use: "<%= Name %>", - Short: "Explain what the command is doing...", - Long: "Long description goes here...", - Flags: []*plugin.Flag{ - {Name: "my-flag", Type: plugin.FlagTypeString, Usage: "my flag description"}, - }, - PlaceCommandUnder: "ignite", - // Examples of adding subcommands: - // Commands: []*plugin.Command{ - // {Use: "add"}, - // {Use: "list"}, - // {Use: "delete"}, - // }, - }, - }, - // TODO: Add hooks here - Hooks: []*plugin.Hook{}, - SharedHost: <%= SharedHost %>, + Name: "<%= Name %>",<%= if (SharedHost) { %> + SharedHost: true,<% } %> + Commands: cmd.GetCommands(), }, nil } -func (app) Execute(ctx context.Context, cmd *plugin.ExecutedCommand, api plugin.ClientAPI) error { - // TODO: write command execution here - fmt.Printf("Hello I'm the example-plugin plugin\n") - fmt.Printf("My executed command: %q\n", cmd.Path) - fmt.Printf("My args: %v\n", cmd.Args) - - flags, err := cmd.NewFlags() - if err != nil { - return err - } - - myFlag, _ := flags.GetString("my-flag") - fmt.Printf("My flags: my-flag=%q\n", myFlag) - fmt.Printf("My config parameters: %v\n", cmd.With) - - // This is how the plugin can access the chain: - // c, err := getChain(cmd) - // if err != nil { - // return err - // } - - // According to the number of declared commands, you may need a switch: - /* - switch cmd.Use { - case "add": - fmt.Println("Adding stuff...") - case "list": - fmt.Println("Listing stuff...") - case "delete": - fmt.Println("Deleting stuff...") - } - */ +func (app) Execute(ctx context.Context, c *plugin.ExecutedCommand, _ plugin.ClientAPI) error { + // Remove the first two elements "ignite" and "<%= Name %>" from OsArgs. + args := c.OsArgs[2:] - // ClientAPI call example - fmt.Println(api.GetChainInfo(ctx)) - - return nil + switch args[0] { + case "hello": + return cmd.ExecuteHello(ctx, c) + default: + return fmt.Errorf("unknown command: %s", c.Path) + } } -func (app) ExecuteHookPre(ctx context.Context, h *plugin.ExecutedHook, api plugin.ClientAPI) error { - fmt.Printf("Executing hook pre %q\n", h.Hook.GetName()) +func (app) ExecuteHookPre(_ context.Context, _ *plugin.ExecutedHook, _ plugin.ClientAPI) error { return nil } -func (app) ExecuteHookPost(ctx context.Context, h *plugin.ExecutedHook, api plugin.ClientAPI) error { - fmt.Printf("Executing hook post %q\n", h.Hook.GetName()) +func (app) ExecuteHookPost(_ context.Context, _ *plugin.ExecutedHook, _ plugin.ClientAPI) error { return nil } -func (app) ExecuteHookCleanUp(ctx context.Context, h *plugin.ExecutedHook, api plugin.ClientAPI) error { - fmt.Printf("Executing hook cleanup %q\n", h.Hook.GetName()) +func (app) ExecuteHookCleanUp(_ context.Context, _ *plugin.ExecutedHook, _ plugin.ClientAPI) error { return nil } -func getChain(cmd *plugin.ExecutedCommand, chainOption ...chain.Option) (*chain.Chain, error) { - flags, err := cmd.NewFlags() - if err != nil { - return nil, err - } - - var ( - home, _ = flags.GetString("home") - path, _ = flags.GetString("path") - ) - if home != "" { - chainOption = append(chainOption, chain.HomePath(home)) - } - absPath, err := filepath.Abs(path) - if err != nil { - return nil, err - } - return chain.New(absPath, chainOption...) -} - func main() { hplugin.Serve(&hplugin.ServeConfig{ HandshakeConfig: plugin.HandshakeConfig(), From a74fb4689c5dda597612ed8f4a315edea2c0ee9e Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Wed, 31 Jan 2024 05:49:19 -0300 Subject: [PATCH 08/10] feat: add integration tests for IBC chains (#3820) * create a method to fill other methods * add chain methods * simplify te logic * spin up both chains * add reminder * add relayers * create configs into the code and add a helper to setup and run chains * fix chain config * fix rpc ports * fix wrong urls and missing relayer accounts * reset relayer config and avoid port conflicts * test relayer * fix config port address * draft check realyer * use hermes realyer instead ts relayer * fix the default config values * fix the config flag * add missing tx.go file by default and enable cli if autocli not exist * add changelog * fix wrong error pkg * add missing imports * only scaffold `cli/tx.go` if is a ibc module * move tx.go.plush to right place * add comment to cobra send packet command * add missing ibc interfaces to chain client * set port range * Revert "refactor(templates): add all ibc commands (#3858)" This reverts commit 3dda9b0b5a30e167e52018b3cbdd20773092b283. * fix changelog * fix ibc.go app * query channels * check balances * check ibc balance * improve test cleanup * fix chain home and config paths * fix log typo * cerate the chain path before use * remove unused const * decrease cleanup time * setup the remote hermes app url * use parser.ParseExpr instead parser.ParseExpr --------- Co-authored-by: Pantani --- changelog.md | 1 + ignite/pkg/goanalysis/goanalysis.go | 59 ++ ignite/pkg/goanalysis/goanalysis_test.go | 74 ++ ignite/pkg/goanalysis/testdata/replace.go | 16 + ignite/pkg/goenv/goenv.go | 5 + .../cmd/commands.go.plush | 3 + .../client/cli/tx_{{packetName}}.go.plush | 1 + integration/app.go | 4 + integration/ibc/cmd_relayer_test.go | 635 ++++++++++++++++++ 9 files changed, 798 insertions(+) create mode 100644 ignite/pkg/goanalysis/testdata/replace.go create mode 100644 integration/ibc/cmd_relayer_test.go diff --git a/changelog.md b/changelog.md index 8b7cc0e520..8098d8b3df 100644 --- a/changelog.md +++ b/changelog.md @@ -6,6 +6,7 @@ - [#3839](https://github.com/ignite/cli/pull/3839) New structure for app scaffolding - [#3835](https://github.com/ignite/cli/pull/3835) Add `--minimal` flag to `scaffold chain` to scaffold a chain with the least amount of sdk modules +- [#3820](https://github.com/ignite/cli/pull/3820) Add integration tests for IBC chains ### Changes diff --git a/ignite/pkg/goanalysis/goanalysis.go b/ignite/pkg/goanalysis/goanalysis.go index 6e3846c173..36f16a472f 100644 --- a/ignite/pkg/goanalysis/goanalysis.go +++ b/ignite/pkg/goanalysis/goanalysis.go @@ -279,3 +279,62 @@ func createUnderscoreImport(imp string) *ast.ImportSpec { }, } } + +// ReplaceCode replace a function implementation into a package path. The method will find +// the method signature and re-write the method implementation based in the new function. +func ReplaceCode(pkgPath, oldFunctionName, newFunction string) (err error) { + absPath, err := filepath.Abs(pkgPath) + if err != nil { + return err + } + + fileSet := token.NewFileSet() + all, err := parser.ParseDir(fileSet, absPath, func(os.FileInfo) bool { return true }, parser.ParseComments) + if err != nil { + return err + } + + for _, pkg := range all { + for _, f := range pkg.Files { + found := false + ast.Inspect(f, func(n ast.Node) bool { + if funcDecl, ok := n.(*ast.FuncDecl); ok { + // Check if the function has the name you want to replace. + if funcDecl.Name.Name == oldFunctionName { + // Replace the function body with the replacement code. + replacementExpr, err := parser.ParseExpr(newFunction) + if err != nil { + return false + } + funcDecl.Body = &ast.BlockStmt{List: []ast.Stmt{ + &ast.ExprStmt{X: replacementExpr}, + }} + found = true + return false + } + } + return true + }) + if err != nil { + return err + } + if !found { + continue + } + filePath := fileSet.Position(f.Package).Filename + outFile, err := os.Create(filePath) + if err != nil { + return err + } + + // Format and write the modified AST to the output file. + if err := format.Node(outFile, fileSet, f); err != nil { + return err + } + if err := outFile.Close(); err != nil { + return err + } + } + } + return nil +} diff --git a/ignite/pkg/goanalysis/goanalysis_test.go b/ignite/pkg/goanalysis/goanalysis_test.go index e19899b619..4d1297e3b0 100644 --- a/ignite/pkg/goanalysis/goanalysis_test.go +++ b/ignite/pkg/goanalysis/goanalysis_test.go @@ -503,3 +503,77 @@ func TestUpdateInitImports(t *testing.T) { }) } } + +func TestReplaceCode(t *testing.T) { + var ( + newFunction = `package test +func NewMethod1() { + n := "test new method" + bla := fmt.Sprintf("test new - %s", n) + fmt.Println(bla) +}` + rollback = `package test +func NewMethod1() { + foo := 100 + bar := fmt.Sprintf("test - %d", foo) + fmt.Println(bar) +}` + ) + + type args struct { + path string + oldFunctionName string + newFunction string + } + tests := []struct { + name string + args args + err error + }{ + { + name: "function fooTest", + args: args{ + path: "testdata", + oldFunctionName: "fooTest", + newFunction: newFunction, + }, + }, + { + name: "function BazTest", + args: args{ + path: "testdata", + oldFunctionName: "BazTest", + newFunction: newFunction, + }, + }, + { + name: "function invalidFunction", + args: args{ + path: "testdata", + oldFunctionName: "invalidFunction", + newFunction: newFunction, + }, + }, + { + name: "invalid path", + args: args{ + path: "invalid_path", + oldFunctionName: "invalidPath", + newFunction: newFunction, + }, + err: os.ErrNotExist, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := goanalysis.ReplaceCode(tt.args.path, tt.args.oldFunctionName, tt.args.newFunction) + if tt.err != nil { + require.Error(t, err) + require.ErrorIs(t, err, tt.err) + return + } + require.NoError(t, err) + require.NoError(t, goanalysis.ReplaceCode(tt.args.path, tt.args.oldFunctionName, rollback)) + }) + } +} diff --git a/ignite/pkg/goanalysis/testdata/replace.go b/ignite/pkg/goanalysis/testdata/replace.go new file mode 100644 index 0000000000..20c1a12c70 --- /dev/null +++ b/ignite/pkg/goanalysis/testdata/replace.go @@ -0,0 +1,16 @@ +package testdata + +import "fmt" + +func fooTest() { + n := "test new method" + bla := fmt.Sprintf("test new - %s", n) + fmt. + Println(bla) +} + +func BazTest() { + foo := 100 + bar := fmt.Sprintf("test - %d", foo) + fmt.Println(bar) +} diff --git a/ignite/pkg/goenv/goenv.go b/ignite/pkg/goenv/goenv.go index 17bc304280..954974574b 100644 --- a/ignite/pkg/goenv/goenv.go +++ b/ignite/pkg/goenv/goenv.go @@ -55,3 +55,8 @@ func GoModCache() string { } return filepath.Join(build.Default.GOPATH, modDir) } + +// GoPath returns the go path. +func GoPath() string { + return os.Getenv(GOPATH) +} diff --git a/ignite/templates/app/files/cmd/{{binaryNamePrefix}}d/cmd/commands.go.plush b/ignite/templates/app/files/cmd/{{binaryNamePrefix}}d/cmd/commands.go.plush index 8bb54e2f73..8058636f52 100644 --- a/ignite/templates/app/files/cmd/{{binaryNamePrefix}}d/cmd/commands.go.plush +++ b/ignite/templates/app/files/cmd/{{binaryNamePrefix}}d/cmd/commands.go.plush @@ -22,6 +22,7 @@ import ( authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli" "github.com/cosmos/cosmos-sdk/x/crisis" genutilcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli" + ibccmd "github.com/cosmos/ibc-go/v8/modules/core/client/cli" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -87,6 +88,7 @@ func queryCommand() *cobra.Command { server.QueryBlocksCmd(), authcmd.QueryTxCmd(), server.QueryBlockResultsCmd(), + ibccmd.GetQueryCmd(), ) cmd.PersistentFlags().String(flags.FlagChainID, "", "The network chain ID") @@ -113,6 +115,7 @@ func txCommand() *cobra.Command { authcmd.GetEncodeCommand(), authcmd.GetDecodeCommand(), authcmd.GetSimulateCmd(), + ibccmd.GetTxCmd(), ) cmd.PersistentFlags().String(flags.FlagChainID, "", "The network chain ID") diff --git a/ignite/templates/ibc/files/packet/messages/x/{{moduleName}}/client/cli/tx_{{packetName}}.go.plush b/ignite/templates/ibc/files/packet/messages/x/{{moduleName}}/client/cli/tx_{{packetName}}.go.plush index 647cfda4c8..762e279b0d 100644 --- a/ignite/templates/ibc/files/packet/messages/x/{{moduleName}}/client/cli/tx_{{packetName}}.go.plush +++ b/ignite/templates/ibc/files/packet/messages/x/{{moduleName}}/client/cli/tx_{{packetName}}.go.plush @@ -14,6 +14,7 @@ import ( var _ = strconv.Itoa(0) +// CmdSend<%= packetName.UpperCamel %>() returns the <%= packetName.UpperCamel %> send packet command. // This command does not use AutoCLI because it gives a better UX to do not. func CmdSend<%= packetName.UpperCamel %>() *cobra.Command { flagPacketTimeoutTimestamp := "packet-timeout-timestamp" diff --git a/integration/app.go b/integration/app.go index 29aceb8dbd..2af4f6a816 100644 --- a/integration/app.go +++ b/integration/app.go @@ -118,6 +118,10 @@ func (a App) SourcePath() string { return a.path } +func (a *App) SetHomePath(homePath string) { + a.homePath = homePath +} + func (a *App) SetConfigPath(path string) { a.configPath = path } diff --git a/integration/ibc/cmd_relayer_test.go b/integration/ibc/cmd_relayer_test.go new file mode 100644 index 0000000000..30fb207fd9 --- /dev/null +++ b/integration/ibc/cmd_relayer_test.go @@ -0,0 +1,635 @@ +//go:build !relayer + +package ibc_test + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "os" + "path/filepath" + "strings" + "testing" + "time" + + "github.com/cosmos/cosmos-sdk/crypto/keyring" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + "gopkg.in/yaml.v2" + + "github.com/ignite/cli/v28/ignite/config/chain" + "github.com/ignite/cli/v28/ignite/config/chain/base" + v1 "github.com/ignite/cli/v28/ignite/config/chain/v1" + "github.com/ignite/cli/v28/ignite/pkg/availableport" + "github.com/ignite/cli/v28/ignite/pkg/cmdrunner" + "github.com/ignite/cli/v28/ignite/pkg/cmdrunner/step" + "github.com/ignite/cli/v28/ignite/pkg/goanalysis" + yamlmap "github.com/ignite/cli/v28/ignite/pkg/yaml" + envtest "github.com/ignite/cli/v28/integration" +) + +const ( + relayerMnemonic = "great immense still pill defense fetch pencil slow purchase symptom speed arm shoot fence have divorce cigar rapid hen vehicle pear evolve correct nerve" +) + +var ( + bobName = "bob" + marsConfig = v1.Config{ + Config: base.Config{ + Version: 1, + Build: base.Build{ + Proto: base.Proto{ + Path: "proto", + ThirdPartyPaths: []string{"third_party/proto", "proto_vendor"}, + }, + }, + Accounts: []base.Account{ + { + Name: "alice", + Coins: []string{"100000000000token", "10000000000000000000stake"}, + Mnemonic: "slide moment original seven milk crawl help text kick fluid boring awkward doll wonder sure fragile plate grid hard next casual expire okay body", + }, + { + Name: "bob", + Coins: []string{"100000000000token", "10000000000000000000stake"}, + Mnemonic: "trap possible liquid elite embody host segment fantasy swim cable digital eager tiny broom burden diary earn hen grow engine pigeon fringe claim program", + }, + { + Name: "relayer", + Coins: []string{"100000000000token", "1000000000000000000000stake"}, + Mnemonic: relayerMnemonic, + }, + }, + Faucet: base.Faucet{ + Name: &bobName, + Coins: []string{"500token", "100000000stake"}, + Host: ":4501", + }, + Genesis: yamlmap.Map{"chain_id": "mars-1"}, + }, + Validators: []v1.Validator{ + { + Name: "alice", + Bonded: "100000000stake", + Client: yamlmap.Map{"keyring-backend": keyring.BackendTest}, + App: yamlmap.Map{ + "api": yamlmap.Map{"address": ":1318"}, + "grpc": yamlmap.Map{"address": ":9092"}, + "grpc-web": yamlmap.Map{"address": ":9093"}, + }, + Config: yamlmap.Map{ + "p2p": yamlmap.Map{"laddr": ":26658"}, + "rpc": yamlmap.Map{"laddr": ":26658", "pprof_laddr": ":6061"}, + }, + Home: "$HOME/.mars", + }, + }, + } + earthConfig = v1.Config{ + Config: base.Config{ + Version: 1, + Build: base.Build{ + Proto: base.Proto{ + Path: "proto", + ThirdPartyPaths: []string{"third_party/proto", "proto_vendor"}, + }, + }, + Accounts: []base.Account{ + { + Name: "alice", + Coins: []string{"100000000000token", "10000000000000000000stake"}, + Mnemonic: "slide moment original seven milk crawl help text kick fluid boring awkward doll wonder sure fragile plate grid hard next casual expire okay body", + }, + { + Name: "bob", + Coins: []string{"100000000000token", "10000000000000000000stake"}, + Mnemonic: "trap possible liquid elite embody host segment fantasy swim cable digital eager tiny broom burden diary earn hen grow engine pigeon fringe claim program", + }, + { + Name: "relayer", + Coins: []string{"100000000000token", "1000000000000000000000stake"}, + Mnemonic: relayerMnemonic, + }, + }, + Faucet: base.Faucet{ + Name: &bobName, + Coins: []string{"500token", "100000000stake"}, + Host: ":4500", + }, + Genesis: yamlmap.Map{"chain_id": "earth-1"}, + }, + Validators: []v1.Validator{ + { + Name: "alice", + Bonded: "100000000stake", + Client: yamlmap.Map{"keyring-backend": keyring.BackendTest}, + App: yamlmap.Map{ + "api": yamlmap.Map{"address": ":1317"}, + "grpc": yamlmap.Map{"address": ":9090"}, + "grpc-web": yamlmap.Map{"address": ":9091"}, + }, + Config: yamlmap.Map{ + "p2p": yamlmap.Map{"laddr": ":26656"}, + "rpc": yamlmap.Map{"laddr": ":26656", "pprof_laddr": ":6060"}, + }, + Home: "$HOME/.earth", + }, + }, + } + + nameSendIbcPost = "SendIbcPost" + funcSendIbcPost = `package keeper +func (k msgServer) SendIbcPost(goCtx context.Context, msg *types.MsgSendIbcPost) (*types.MsgSendIbcPostResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + // Construct the packet + var packet types.IbcPostPacketData + packet.Title = msg.Title + packet.Content = msg.Content + // Transmit the packet + _, err := k.TransmitIbcPostPacket( + ctx, + packet, + msg.Port, + msg.ChannelID, + clienttypes.ZeroHeight(), + msg.TimeoutTimestamp, + ) + return &types.MsgSendIbcPostResponse{}, err +}` + + nameOnRecvIbcPostPacket = "OnRecvIbcPostPacket" + funcOnRecvIbcPostPacket = `package keeper +func (k Keeper) OnRecvIbcPostPacket(ctx sdk.Context, packet channeltypes.Packet, data types.IbcPostPacketData) (packetAck types.IbcPostPacketAck, err error) { + // validate packet data upon receiving + if err := data.ValidateBasic(); err != nil { + return packetAck, err + } + packetAck.PostId = k.AppendPost(ctx, types.Post{Title: data.Title, Content: data.Content}) + return packetAck, nil +}` + + nameOnAcknowledgementIbcPostPacket = "OnAcknowledgementIbcPostPacket" + funcOnAcknowledgementIbcPostPacket = `package keeper +func (k Keeper) OnAcknowledgementIbcPostPacket(ctx sdk.Context, packet channeltypes.Packet, data types.IbcPostPacketData, ack channeltypes.Acknowledgement) error { + switch dispatchedAck := ack.Response.(type) { + case *channeltypes.Acknowledgement_Error: + // We will not treat acknowledgment error in this tutorial + return nil + case *channeltypes.Acknowledgement_Result: + // Decode the packet acknowledgment + var packetAck types.IbcPostPacketAck + if err := types.ModuleCdc.UnmarshalJSON(dispatchedAck.Result, &packetAck); err != nil { + // The counter-party module doesn't implement the correct acknowledgment format + return errors.New("cannot unmarshal acknowledgment") + } + + k.AppendSentPost(ctx, + types.SentPost{ + PostId: packetAck.PostId, + Title: data.Title, + Chain: packet.DestinationPort + "-" + packet.DestinationChannel, + }, + ) + return nil + default: + return errors.New("the counter-party module does not implement the correct acknowledgment format") + } +}` + + nameOnTimeoutIbcPostPacket = "OnTimeoutIbcPostPacket" + funcOnTimeoutIbcPostPacket = `package keeper +func (k Keeper) OnTimeoutIbcPostPacket(ctx sdk.Context, packet channeltypes.Packet, data types.IbcPostPacketData) error { + k.AppendTimeoutPost(ctx, + types.TimeoutPost{ + Title: data.Title, + Chain: packet.DestinationPort + "-" + packet.DestinationChannel, + }, + ) + return nil +}` +) + +type ( + QueryChannels struct { + Channels []struct { + ChannelId string `json:"channel_id"` + ConnectionHops []string `json:"connection_hops"` + Counterparty struct { + ChannelId string `json:"channel_id"` + PortId string `json:"port_id"` + } `json:"counterparty"` + Ordering string `json:"ordering"` + PortId string `json:"port_id"` + State string `json:"state"` + Version string `json:"version"` + } `json:"channels"` + } + + QueryBalances struct { + Balances sdk.Coins `json:"balances"` + } +) + +func runChain( + t *testing.T, + ctx context.Context, + env envtest.Env, + app envtest.App, + cfg v1.Config, + tmpDir string, + ports []uint, +) (api, rpc, grpc, faucet string) { + t.Helper() + if len(ports) < 7 { + t.Fatalf("invalid number of ports %d", len(ports)) + } + + var ( + chainID = cfg.Genesis["chain_id"].(string) + chainPath = filepath.Join(tmpDir, chainID) + homePath = filepath.Join(chainPath, "home") + cfgPath = filepath.Join(chainPath, chain.ConfigFilenames[0]) + ) + require.NoError(t, os.MkdirAll(chainPath, os.ModePerm)) + + genAddr := func(port uint) string { + return fmt.Sprintf(":%d", port) + } + + cfg.Validators[0].Home = homePath + + cfg.Faucet.Host = genAddr(ports[0]) + cfg.Validators[0].App["api"] = yamlmap.Map{"address": genAddr(ports[1])} + cfg.Validators[0].App["grpc"] = yamlmap.Map{"address": genAddr(ports[2])} + cfg.Validators[0].App["grpc-web"] = yamlmap.Map{"address": genAddr(ports[3])} + cfg.Validators[0].Config["p2p"] = yamlmap.Map{"laddr": genAddr(ports[4])} + cfg.Validators[0].Config["rpc"] = yamlmap.Map{ + "laddr": genAddr(ports[5]), + "pprof_laddr": genAddr(ports[6]), + } + + file, err := os.Create(cfgPath) + require.NoError(t, err) + require.NoError(t, yaml.NewEncoder(file).Encode(cfg)) + require.NoError(t, file.Close()) + + app.SetConfigPath(cfgPath) + app.SetHomePath(homePath) + go func() { + env.Must(app.Serve("should serve chain", envtest.ExecCtx(ctx))) + }() + + genHTTPAddr := func(port uint) string { + return fmt.Sprintf("http://127.0.0.1:%d", port) + } + return genHTTPAddr(ports[1]), genHTTPAddr(ports[5]), genHTTPAddr(ports[2]), genHTTPAddr(ports[0]) +} + +func TestBlogIBC(t *testing.T) { + var ( + env = envtest.New(t) + app = env.Scaffold("github.com/test/planet") + ctx = env.Ctx() + tmpDir = t.TempDir() + ) + ctx, cancel := context.WithCancel(ctx) + t.Cleanup(func() { + cancel() + time.Sleep(5 * time.Second) + require.NoError(t, os.RemoveAll(tmpDir)) + }) + + env.Must(env.Exec("create an IBC module", + step.NewSteps(step.New( + step.Exec(envtest.IgniteApp, + "s", + "module", + "blog", + "--ibc", + "--require-registration", + "--yes", + ), + step.Workdir(app.SourcePath()), + )), + )) + + env.Must(env.Exec("create a post type list in an IBC module", + step.NewSteps(step.New( + step.Exec(envtest.IgniteApp, + "s", + "list", + "post", + "title", + "content", + "--no-message", + "--module", + "blog", + "--yes", + ), + step.Workdir(app.SourcePath()), + )), + )) + + env.Must(env.Exec("create a sentPost type list in an IBC module", + step.NewSteps(step.New( + step.Exec(envtest.IgniteApp, + "s", + "list", + "sentPost", + "postID:uint", + "title", + "chain", + "--no-message", + "--module", + "blog", + "--yes", + ), + step.Workdir(app.SourcePath()), + )), + )) + + env.Must(env.Exec("create a timeoutPost type list in an IBC module", + step.NewSteps(step.New( + step.Exec(envtest.IgniteApp, + "s", + "list", + "timeoutPost", + "title", + "chain", + "--no-message", + "--module", + "blog", + "--yes", + ), + step.Workdir(app.SourcePath()), + )), + )) + + env.Must(env.Exec("create a ibcPost package in an IBC module", + step.NewSteps(step.New( + step.Exec(envtest.IgniteApp, + "s", + "packet", + "ibcPost", + "title", + "content", + "--ack", + "postID:uint", + "--module", + "blog", + "--yes", + ), + step.Workdir(app.SourcePath()), + )), + )) + + blogKeeperPath := filepath.Join(app.SourcePath(), "x/blog/keeper") + require.NoError(t, goanalysis.ReplaceCode( + blogKeeperPath, + nameSendIbcPost, + funcSendIbcPost, + )) + require.NoError(t, goanalysis.ReplaceCode( + blogKeeperPath, + nameOnRecvIbcPostPacket, + funcOnRecvIbcPostPacket, + )) + require.NoError(t, goanalysis.ReplaceCode( + blogKeeperPath, + nameOnAcknowledgementIbcPostPacket, + funcOnAcknowledgementIbcPostPacket, + )) + require.NoError(t, goanalysis.ReplaceCode( + blogKeeperPath, + nameOnTimeoutIbcPostPacket, + funcOnTimeoutIbcPostPacket, + )) + + // serve both chains. + ports, err := availableport.Find( + 14, + availableport.WithMinPort(4000), + availableport.WithMaxPort(5000), + ) + require.NoError(t, err) + earthAPI, earthRPC, earthGRPC, earthFaucet := runChain(t, ctx, env, app, earthConfig, tmpDir, ports[:7]) + earthChainID := earthConfig.Genesis["chain_id"].(string) + earthHome := earthConfig.Validators[0].Home + marsAPI, marsRPC, marsGRPC, marsFaucet := runChain(t, ctx, env, app, marsConfig, tmpDir, ports[7:]) + marsChainID := marsConfig.Genesis["chain_id"].(string) + marsHome := marsConfig.Validators[0].Home + + // check the chains is up + stepsCheckChains := step.NewSteps( + step.New( + step.Exec( + app.Binary(), + "config", + "output", "json", + ), + step.PreExec(func() error { + if err := env.IsAppServed(ctx, earthAPI); err != nil { + return err + } + return env.IsAppServed(ctx, marsAPI) + }), + ), + ) + env.Exec("waiting the chain is up", stepsCheckChains, envtest.ExecRetry()) + + // ibc relayer. + env.Must(env.Exec("install the hermes relayer app", + step.NewSteps(step.New( + step.Exec(envtest.IgniteApp, + "app", + "install", + "-g", + // filepath.Join(goenv.GoPath(), "src/github.com/ignite/apps/hermes"), // Local path for test proposals + "github.com/ignite/apps/hermes", + ), + )), + )) + + env.Must(env.Exec("configure the hermes relayer app", + step.NewSteps(step.New( + step.Exec(envtest.IgniteApp, + "relayer", + "hermes", + "configure", + earthChainID, + earthRPC, + earthGRPC, + marsChainID, + marsRPC, + marsGRPC, + "--chain-a-faucet", earthFaucet, + "--chain-b-faucet", marsFaucet, + "--generate-wallets", + "--overwrite-config", + ), + )), + )) + + go func() { + env.Must(env.Exec("run the hermes relayer", + step.NewSteps(step.New( + step.Exec(envtest.IgniteApp, "relayer", "hermes", "start", earthChainID, marsChainID), + )), + envtest.ExecCtx(ctx), + )) + }() + time.Sleep(3 * time.Second) + + var ( + queryOutput = &bytes.Buffer{} + queryResponse QueryChannels + ) + env.Must(env.Exec("verify if the channel was created", step.NewSteps( + step.New( + step.Stdout(queryOutput), + step.Exec( + app.Binary(), + "q", + "ibc", + "channel", + "channels", + "--node", earthRPC, + "--log_format", "json", + "--output", "json", + ), + step.PostExec(func(execErr error) error { + if execErr != nil { + return execErr + } + if err := json.Unmarshal(queryOutput.Bytes(), &queryResponse); err != nil { + return fmt.Errorf("unmarshling tx response: %w", err) + } + if len(queryResponse.Channels) == 0 || + len(queryResponse.Channels[0].ConnectionHops) == 0 { + return fmt.Errorf("channel not found") + } + if queryResponse.Channels[0].State != "STATE_OPEN" { + return fmt.Errorf("channel is not open") + } + return nil + }), + ), + ))) + + var ( + sender = "alice" + receiverAddr = "cosmos1nrksk5swk6lnmlq670a8kwxmsjnu0ezqts39sa" + txOutput = &bytes.Buffer{} + txResponse struct { + Code int + RawLog string `json:"raw_log"` + TxHash string `json:"txhash"` + } + ) + + stepsTx := step.NewSteps( + step.New( + step.Stdout(txOutput), + step.Exec( + app.Binary(), + "tx", + "ibc-transfer", + "transfer", + "transfer", + "channel-0", + receiverAddr, + "100000stake", + "--from", sender, + "--node", earthRPC, + "--home", earthHome, + "--chain-id", earthChainID, + "--output", "json", + "--log_format", "json", + "--keyring-backend", "test", + "--yes", + ), + step.PostExec(func(execErr error) error { + if execErr != nil { + return execErr + } + if err := json.Unmarshal(txOutput.Bytes(), &txResponse); err != nil { + return fmt.Errorf("unmarshling tx response: %w", err) + } + return cmdrunner.New().Run(ctx, step.New( + step.Exec( + app.Binary(), + "q", + "tx", + txResponse.TxHash, + "--node", earthRPC, + "--home", earthHome, + "--chain-id", earthChainID, + "--output", "json", + "--log_format", "json", + ), + step.Stdout(txOutput), + step.PreExec(func() error { + txOutput.Reset() + return nil + }), + step.PostExec(func(execErr error) error { + if execErr != nil { + return execErr + } + if err := json.Unmarshal(txOutput.Bytes(), &txResponse); err != nil { + return err + } + return nil + }), + )) + }), + ), + ) + if !env.Exec("send an IBC transfer", stepsTx, envtest.ExecRetry()) { + t.FailNow() + } + require.Equal(t, 0, txResponse.Code, + "tx failed code=%d log=%s", txResponse.Code, txResponse.RawLog) + + var ( + balanceOutput = &bytes.Buffer{} + balanceResponse QueryBalances + ) + env.Must(env.Exec("check ibc balance", step.NewSteps( + step.New( + step.Stdout(balanceOutput), + step.Exec( + app.Binary(), + "q", + "bank", + "balances", + receiverAddr, + "--node", marsRPC, + "--home", marsHome, + "--log_format", "json", + "--output", "json", + ), + step.PostExec(func(execErr error) error { + if execErr != nil { + return execErr + } + if err := json.Unmarshal(balanceOutput.Bytes(), &balanceResponse); err != nil { + return fmt.Errorf("unmarshalling tx response: %w", err) + } + if balanceResponse.Balances.Empty() { + return fmt.Errorf("empty balances") + } + if !strings.HasPrefix(balanceResponse.Balances[0].Denom, "ibc/") { + return fmt.Errorf("invalid ibc balance: %v", balanceResponse.Balances[0]) + } + return nil + }), + ), + ))) + + // TODO test ibc using the blog post methods: + // step.Exec(app.Binary(), "tx", "blog", "send-ibc-post", "transfer", "channel-0", "Hello", "Hello_Mars-Alice_from_Earth", "--chain-id", earthChainID, "--from", "alice", "--node", earthGRPC, "--output", "json", "--log_format", "json", "--yes") + // TODO test ibc using the hermes ft-transfer: + // step.Exec(envtest.IgniteApp, "relayer", "hermes", "exec", "--", "--config", earthConfig, "tx", "ft-transfer", "--timeout-seconds", "1000", "--dst-chain", earthChainID, "--src-chain", marsChainID, "--src-port", "transfer", "--src-channel", "channel-0", "--amount", "100000", "--denom", "stake", "--output", "json", "--log_format", "json", "--yes") +} From 115740f25740013e25a689502aaed9b509ec7829 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jer=C3=B3nimo=20Albi?= Date: Wed, 31 Jan 2024 13:16:13 +0100 Subject: [PATCH 09/10] chore: minor app scaffold changes (#3920) * chore: fix import grouping * chore: add test helper calls to apps integration test template * tests: refactor plugin scaffold tests to follow AAA and atomicity --- ignite/services/plugin/scaffold_test.go | 60 +++++++++++++++---- .../template/integration/app_test.go.plush | 2 + 2 files changed, 49 insertions(+), 13 deletions(-) diff --git a/ignite/services/plugin/scaffold_test.go b/ignite/services/plugin/scaffold_test.go index cf79655f99..eec89787dc 100644 --- a/ignite/services/plugin/scaffold_test.go +++ b/ignite/services/plugin/scaffold_test.go @@ -1,4 +1,4 @@ -package plugin +package plugin_test import ( "context" @@ -6,40 +6,74 @@ import ( "path/filepath" "testing" - "github.com/ignite/cli/v28/ignite/pkg/gocmd" "github.com/stretchr/testify/require" "gopkg.in/yaml.v2" + + "github.com/ignite/cli/v28/ignite/pkg/gocmd" + "github.com/ignite/cli/v28/ignite/services/plugin" ) +const fooBarAppURI = "github.com/foo/bar" + func TestScaffold(t *testing.T) { // Arrange tmp := t.TempDir() ctx := context.Background() // Act - path, err := Scaffold(ctx, tmp, "github.com/foo/bar", false) + path, err := plugin.Scaffold(ctx, tmp, fooBarAppURI, false) // Assert require.NoError(t, err) require.DirExists(t, path) require.FileExists(t, filepath.Join(path, "go.mod")) require.FileExists(t, filepath.Join(path, "main.go")) +} - // app.ignite.yml check - appYML, err := os.ReadFile(filepath.Join(path, "app.ignite.yml")) - require.NoError(t, err) - var config AppsConfig - err = yaml.Unmarshal(appYML, &config) - require.NoError(t, err) - require.EqualValues(t, 1, config.Version) - require.Len(t, config.Apps, 1) +func TestScaffoldedConfig(t *testing.T) { + // Arrange + ctx := context.Background() + path := scaffoldApp(t, ctx, fooBarAppURI) + + // Act + cfg := readConfig(t, path) + + // Assert + require.EqualValues(t, 1, cfg.Version) + require.Len(t, cfg.Apps, 1) +} - // Integration test check - err = gocmd.Test(ctx, filepath.Join(path, "integration"), []string{ +func TestScaffoldedTests(t *testing.T) { + // Arrange + ctx := context.Background() + path := scaffoldApp(t, ctx, fooBarAppURI) + path = filepath.Join(path, "integration") + + // Act + err := gocmd.Test(ctx, path, []string{ "-timeout", "5m", "-run", "^TestBar$", }) + + // Assert + require.NoError(t, err) +} + +func scaffoldApp(t *testing.T, ctx context.Context, path string) string { + t.Helper() + + path, err := plugin.Scaffold(ctx, t.TempDir(), path, false) + require.NoError(t, err) + return path +} + +func readConfig(t *testing.T, path string) (cfg plugin.AppsConfig) { + t.Helper() + + bz, err := os.ReadFile(filepath.Join(path, "app.ignite.yml")) require.NoError(t, err) + require.NoError(t, yaml.Unmarshal(bz, &cfg)) + return } diff --git a/ignite/services/plugin/template/integration/app_test.go.plush b/ignite/services/plugin/template/integration/app_test.go.plush index 0551c112c3..c6ea1f996c 100644 --- a/ignite/services/plugin/template/integration/app_test.go.plush +++ b/ignite/services/plugin/template/integration/app_test.go.plush @@ -56,12 +56,14 @@ func Test<%= Title %>(t *testing.T) { } func assertLocalPlugins(t *testing.T, app envtest.App, expectedPlugins []pluginsconfig.Plugin) { + t.Helper() cfg, err := pluginsconfig.ParseDir(app.SourcePath()) require.NoError(t, err) require.ElementsMatch(t, expectedPlugins, cfg.Apps, "unexpected local apps") } func assertGlobalPlugins(t *testing.T, app envtest.App, expectedPlugins []pluginsconfig.Plugin) { + t.Helper() cfgPath, err := plugin.PluginsPath() require.NoError(t, err) cfg, err := pluginsconfig.ParseDir(cfgPath) From 352ade7309bf6a281512c5a551ec8e7f58d07973 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Wed, 31 Jan 2024 15:43:05 +0100 Subject: [PATCH 10/10] chore(templates): revert unneeded template addition (#3921) --- .../app/files/cmd/{{binaryNamePrefix}}d/cmd/commands.go.plush | 3 --- 1 file changed, 3 deletions(-) diff --git a/ignite/templates/app/files/cmd/{{binaryNamePrefix}}d/cmd/commands.go.plush b/ignite/templates/app/files/cmd/{{binaryNamePrefix}}d/cmd/commands.go.plush index 8058636f52..8bb54e2f73 100644 --- a/ignite/templates/app/files/cmd/{{binaryNamePrefix}}d/cmd/commands.go.plush +++ b/ignite/templates/app/files/cmd/{{binaryNamePrefix}}d/cmd/commands.go.plush @@ -22,7 +22,6 @@ import ( authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli" "github.com/cosmos/cosmos-sdk/x/crisis" genutilcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli" - ibccmd "github.com/cosmos/ibc-go/v8/modules/core/client/cli" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -88,7 +87,6 @@ func queryCommand() *cobra.Command { server.QueryBlocksCmd(), authcmd.QueryTxCmd(), server.QueryBlockResultsCmd(), - ibccmd.GetQueryCmd(), ) cmd.PersistentFlags().String(flags.FlagChainID, "", "The network chain ID") @@ -115,7 +113,6 @@ func txCommand() *cobra.Command { authcmd.GetEncodeCommand(), authcmd.GetDecodeCommand(), authcmd.GetSimulateCmd(), - ibccmd.GetTxCmd(), ) cmd.PersistentFlags().String(flags.FlagChainID, "", "The network chain ID")