From 698b10175343a2bc7a91c8ce30a2ab49a78dcfc9 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Fri, 27 Jun 2025 09:50:59 +0200 Subject: [PATCH 01/15] refactor!: remove react frontend + re-enable disabled integration tests --- docs/docs/04-clients/04-react.md | 135 ---------------- .../version-v29/04-clients/04-react.md | 135 ---------------- ignite/cmd/generate.go | 11 +- ignite/cmd/generate_hooks.go | 58 ------- ignite/cmd/scaffold.go | 1 - ignite/cmd/scaffold_react.go | 41 ----- ignite/config/chain/base/config.go | 3 - ignite/config/chain/config.go | 18 --- ignite/pkg/cosmosgen/cosmosgen.go | 22 --- ignite/pkg/cosmosgen/generate_composables.go | 15 +- ignite/pkg/cosmosgen/webtemplates.go | 5 - ignite/services/chain/generate.go | 51 +----- ignite/templates/app/files/readme.md.plush | 7 +- integration/cosmosgen/bank_module_test.go | 2 - .../cosmosgen/cosmosgen_composables_test.go | 2 - integration/cosmosgen/cosmosgen_hooks_test.go | 151 ------------------ integration/cosmosgen/custom_module_test.go | 2 - 17 files changed, 13 insertions(+), 646 deletions(-) delete mode 100644 docs/docs/04-clients/04-react.md delete mode 100644 docs/versioned_docs/version-v29/04-clients/04-react.md delete mode 100644 ignite/cmd/generate_hooks.go delete mode 100644 ignite/cmd/scaffold_react.go delete mode 100644 integration/cosmosgen/cosmosgen_hooks_test.go diff --git a/docs/docs/04-clients/04-react.md b/docs/docs/04-clients/04-react.md deleted file mode 100644 index e915b3121e..0000000000 --- a/docs/docs/04-clients/04-react.md +++ /dev/null @@ -1,135 +0,0 @@ -# React frontend - -:::warning -The React frontend is being reworked and is not yet stable. -In the meantime, refer to the [Ignite CCA App](https://ignite.com/marketplace/cca). -::: - -Welcome to this tutorial on using Ignite to develop a web application for your -blockchain with React. Ignite is a tool that simplifies the process of building -a blockchain application by providing a set of templates and generators that can -be used to get up and running quickly. - -One of the features of Ignite is its support for [React](https://reactjs.org/), a -popular JavaScript framework for building user interfaces. In this tutorial, you -will learn how to use Ignite to create a new blockchain and scaffold a React -frontend template. This will give you a basic foundation for your web -application and make it easier to get started building out the rest of your -application. - -Once you have your blockchain and React template set up, the next step is to -generate an API client. This will allow you to easily interact with your -blockchain from your web application, enabling you to retrieve data and make -transactions. By the end of this tutorial, you will have a fully functional web -application that is connected to your own blockchain. - -Prerequisites: - -* [Node.js](https://nodejs.org/en/) -* [Keplr](https://www.keplr.app/) Chrome extension - -## Create a blockchain and a React app - -Create a new blockchain project: - -``` -ignite scaffold chain example -``` - -To create a React frontend template, go to the `example` directory and run the -following command: - -``` -ignite scaffold react -``` - -This will create a new React project in the `react` directory. This project can be -used with any blockchain, but it depends on an API client to interact with the -blockchain. To generate an API client, run the following command in the -`example` directory: - -``` -ignite generate hooks -``` - -This command generates two directories: - -* `ts-client`: a framework-agnostic TypeScript client that can be used to - interact with your blockchain. You can learn more about how to use this client - in the [TypeScript client tutorial](/clients/typescript). -* `react/src/hooks`: a collection of - [React Hooks](https://reactjs.org/docs/hooks-intro.html) that wrap - the TypeScript client and make it easier to interact with your blockchain from - your React application. - -## Set up Keplr and an account - -Open your browser with the Keplr wallet extension installed. Follow [the -instructions](https://keplr.crunch.help/en/getting-started/creating-a-new-keplr-account) -to create a new account or use an existing one. Make sure to save the mnemonic -phrase as you will need it in the next step. - -Do not use a mnemonic phrase that is associated with an account that holds -assets you care about. If you do, you risk losing those assets. It's a good -practice to create a new account for development purposes. - -Add the account you're using in Keplr to your blockchain's `config.yml` file: - -```yml -accounts: - - name: alice - coins: [20000token, 200000000stake] - - name: bob - coins: [10000token, 100000000stake] - # highlight-start - - name: frank - coins: [10000token, 100000000stake] - mnemonic: struggle since inmate safe logic kite tag web win stay security wonder - # highlight-end -``` - -Replace the `struggle since...` mnemonic with the one you saved in the previous -step. - -Adding an account with a mnemonic to the config file will tell Ignite CLI to add -the account to the blockchain when you start it. This is useful for development -purposes, but you should not do this in production. - -## Start a blockchain and a React app - -In the `example` directory run the following command to start your blockchain: - -``` -ignite chain serve -``` - -To start your React application, go to the `react` directory and run the following -command in a separate terminal window: - -``` -npm install && npm run dev -``` - -It is recommended to run `npm install` before starting your app with `npm run -dev` to ensure that all dependencies are installed (including the ones that the -API client has, see `react/postinstall.js`). - -Open your browser and navigate to -[http://localhost:5173/](http://localhost:5173/). - -![Web app](/img/web-1.png) - -Press "Connect wallet", enter your password into Keplr and press "Approve" to -add your blockchain to Keplr. - - - -Make sure to select the account you're using for development purposes and the -"Example Network" in Keplr's blockchain dropdown. You should see a list of -assets in your React app. - -![Web app](/img/web-5.png) - -Congratulations! You have successfully created a client-side React application and -connected it to your blockchain. You can modify the source code of your React -application to build out the rest of your project. \ No newline at end of file diff --git a/docs/versioned_docs/version-v29/04-clients/04-react.md b/docs/versioned_docs/version-v29/04-clients/04-react.md deleted file mode 100644 index e915b3121e..0000000000 --- a/docs/versioned_docs/version-v29/04-clients/04-react.md +++ /dev/null @@ -1,135 +0,0 @@ -# React frontend - -:::warning -The React frontend is being reworked and is not yet stable. -In the meantime, refer to the [Ignite CCA App](https://ignite.com/marketplace/cca). -::: - -Welcome to this tutorial on using Ignite to develop a web application for your -blockchain with React. Ignite is a tool that simplifies the process of building -a blockchain application by providing a set of templates and generators that can -be used to get up and running quickly. - -One of the features of Ignite is its support for [React](https://reactjs.org/), a -popular JavaScript framework for building user interfaces. In this tutorial, you -will learn how to use Ignite to create a new blockchain and scaffold a React -frontend template. This will give you a basic foundation for your web -application and make it easier to get started building out the rest of your -application. - -Once you have your blockchain and React template set up, the next step is to -generate an API client. This will allow you to easily interact with your -blockchain from your web application, enabling you to retrieve data and make -transactions. By the end of this tutorial, you will have a fully functional web -application that is connected to your own blockchain. - -Prerequisites: - -* [Node.js](https://nodejs.org/en/) -* [Keplr](https://www.keplr.app/) Chrome extension - -## Create a blockchain and a React app - -Create a new blockchain project: - -``` -ignite scaffold chain example -``` - -To create a React frontend template, go to the `example` directory and run the -following command: - -``` -ignite scaffold react -``` - -This will create a new React project in the `react` directory. This project can be -used with any blockchain, but it depends on an API client to interact with the -blockchain. To generate an API client, run the following command in the -`example` directory: - -``` -ignite generate hooks -``` - -This command generates two directories: - -* `ts-client`: a framework-agnostic TypeScript client that can be used to - interact with your blockchain. You can learn more about how to use this client - in the [TypeScript client tutorial](/clients/typescript). -* `react/src/hooks`: a collection of - [React Hooks](https://reactjs.org/docs/hooks-intro.html) that wrap - the TypeScript client and make it easier to interact with your blockchain from - your React application. - -## Set up Keplr and an account - -Open your browser with the Keplr wallet extension installed. Follow [the -instructions](https://keplr.crunch.help/en/getting-started/creating-a-new-keplr-account) -to create a new account or use an existing one. Make sure to save the mnemonic -phrase as you will need it in the next step. - -Do not use a mnemonic phrase that is associated with an account that holds -assets you care about. If you do, you risk losing those assets. It's a good -practice to create a new account for development purposes. - -Add the account you're using in Keplr to your blockchain's `config.yml` file: - -```yml -accounts: - - name: alice - coins: [20000token, 200000000stake] - - name: bob - coins: [10000token, 100000000stake] - # highlight-start - - name: frank - coins: [10000token, 100000000stake] - mnemonic: struggle since inmate safe logic kite tag web win stay security wonder - # highlight-end -``` - -Replace the `struggle since...` mnemonic with the one you saved in the previous -step. - -Adding an account with a mnemonic to the config file will tell Ignite CLI to add -the account to the blockchain when you start it. This is useful for development -purposes, but you should not do this in production. - -## Start a blockchain and a React app - -In the `example` directory run the following command to start your blockchain: - -``` -ignite chain serve -``` - -To start your React application, go to the `react` directory and run the following -command in a separate terminal window: - -``` -npm install && npm run dev -``` - -It is recommended to run `npm install` before starting your app with `npm run -dev` to ensure that all dependencies are installed (including the ones that the -API client has, see `react/postinstall.js`). - -Open your browser and navigate to -[http://localhost:5173/](http://localhost:5173/). - -![Web app](/img/web-1.png) - -Press "Connect wallet", enter your password into Keplr and press "Approve" to -add your blockchain to Keplr. - - - -Make sure to select the account you're using for development purposes and the -"Example Network" in Keplr's blockchain dropdown. You should see a list of -assets in your React app. - -![Web app](/img/web-5.png) - -Congratulations! You have successfully created a client-side React application and -connected it to your blockchain. You can modify the source code of your React -application to build out the rest of your project. \ No newline at end of file diff --git a/ignite/cmd/generate.go b/ignite/cmd/generate.go index 16ca7065e9..1fec283aa3 100644 --- a/ignite/cmd/generate.go +++ b/ignite/cmd/generate.go @@ -33,11 +33,12 @@ meant to be edited by hand. flagSetPath(c) flagSetClearCache(c) - c.AddCommand(NewGenerateGo()) - c.AddCommand(NewGenerateTSClient()) - c.AddCommand(NewGenerateComposables()) - c.AddCommand(NewGenerateHooks()) - c.AddCommand(NewGenerateOpenAPI()) + c.AddCommand( + NewGenerateGo(), + NewGenerateTSClient(), + NewGenerateComposables(), + NewGenerateOpenAPI(), + ) return c } diff --git a/ignite/cmd/generate_hooks.go b/ignite/cmd/generate_hooks.go deleted file mode 100644 index 91975278f5..0000000000 --- a/ignite/cmd/generate_hooks.go +++ /dev/null @@ -1,58 +0,0 @@ -package ignitecmd - -import ( - "github.com/spf13/cobra" - - "github.com/ignite/cli/v29/ignite/pkg/cliui" - "github.com/ignite/cli/v29/ignite/pkg/cliui/icons" - "github.com/ignite/cli/v29/ignite/services/chain" -) - -func NewGenerateHooks() *cobra.Command { - c := &cobra.Command{ - Use: "hooks", - Short: "TypeScript frontend client and React hooks", - RunE: generateHooksHandler, - } - - c.Flags().AddFlagSet(flagSetYes()) - c.Flags().StringP(flagOutput, "o", "", "React hooks output path") - - return c -} - -func generateHooksHandler(cmd *cobra.Command, _ []string) error { - session := cliui.New( - cliui.StartSpinnerWithText(statusGenerating), - cliui.WithoutUserInteraction(getYes(cmd)), - ) - defer session.End() - - c, err := chain.NewWithHomeFlags( - cmd, - chain.WithOutputer(session), - chain.CollectEvents(session.EventBus()), - chain.PrintGeneratedPaths()) - if err != nil { - return err - } - - cacheStorage, err := newCache(cmd) - if err != nil { - return err - } - - output, _ := cmd.Flags().GetString(flagOutput) - - var opts []chain.GenerateTarget - if flagGetEnableProtoVendor(cmd) { - opts = append(opts, chain.GenerateProtoVendor()) - } - - err = c.Generate(cmd.Context(), cacheStorage, chain.GenerateHooks(output), opts...) - if err != nil { - return err - } - - return session.Println(icons.OK, "Generated Typescript Client and React hooks") -} diff --git a/ignite/cmd/scaffold.go b/ignite/cmd/scaffold.go index 03dc931346..e5c034ec88 100644 --- a/ignite/cmd/scaffold.go +++ b/ignite/cmd/scaffold.go @@ -128,7 +128,6 @@ with an "--ibc" flag. Note that the default module is not IBC-enabled. NewScaffoldQuery(), NewScaffoldPacket(), NewScaffoldVue(), - NewScaffoldReact(), NewScaffoldChainRegistry(), ) diff --git a/ignite/cmd/scaffold_react.go b/ignite/cmd/scaffold_react.go deleted file mode 100644 index dc26c49c1f..0000000000 --- a/ignite/cmd/scaffold_react.go +++ /dev/null @@ -1,41 +0,0 @@ -package ignitecmd - -import ( - "github.com/spf13/cobra" - - chainconfig "github.com/ignite/cli/v29/ignite/config/chain" - "github.com/ignite/cli/v29/ignite/pkg/cliui" - "github.com/ignite/cli/v29/ignite/pkg/cosmosgen" -) - -// NewScaffoldReact scaffolds a React app for a chain. -func NewScaffoldReact() *cobra.Command { - c := &cobra.Command{ - Hidden: true, // hidden util we have a better ts-client. - Use: "react", - Short: "React web app template", - Args: cobra.NoArgs, - PreRunE: migrationPreRunHandler, - RunE: scaffoldReactHandler, - } - - c.Flags().AddFlagSet(flagSetYes()) - c.Flags().StringP(flagPath, "p", "./"+chainconfig.DefaultReactPath, "path to scaffold content of the React app") - - return c -} - -func scaffoldReactHandler(cmd *cobra.Command, _ []string) error { - session := cliui.New( - cliui.StartSpinnerWithText(statusScaffolding), - cliui.WithoutUserInteraction(getYes(cmd)), - ) - defer session.End() - - path := flagGetPath(cmd) - if err := cosmosgen.React(path); err != nil { - return err - } - - return session.Printf("\nšŸŽ‰ Scaffolded a React app in %s.\n\n", path) -} diff --git a/ignite/config/chain/base/config.go b/ignite/config/chain/base/config.go index c2772f73f3..b462a53cee 100644 --- a/ignite/config/chain/base/config.go +++ b/ignite/config/chain/base/config.go @@ -41,9 +41,6 @@ type Client struct { // Composables configures code generation for Vue 3 composables. Composables Composables `yaml:"composables,omitempty" doc:"Configures Vue 3 composables code generation."` - // Hooks configures code generation for React hooks. - Hooks Hooks `yaml:"hooks,omitempty" doc:"Configures React hooks code generation."` - // OpenAPI configures OpenAPI spec generation for API. OpenAPI OpenAPI `yaml:"openapi,omitempty" doc:"Configures OpenAPI spec generation for the API."` } diff --git a/ignite/config/chain/config.go b/ignite/config/chain/config.go index 13c215a2e7..e1e60564b8 100644 --- a/ignite/config/chain/config.go +++ b/ignite/config/chain/config.go @@ -26,10 +26,6 @@ var ( // The path is relative to the app's directory. DefaultVuePath = "vue" - // DefaultReactPath defines the default relative path to use when scaffolding a React app. - // The path is relative to the app's directory. - DefaultReactPath = "react" - // DefaultComposablesPath defines the default relative path to use when generating useQuery composables for a Vue app. // The path is relative to the app's directory. DefaultComposablesPath = "vue/src/composables" @@ -37,10 +33,6 @@ var ( // DefaultVueTypesPath defines the default vue types path. DefaultVueTypesPath = "vue/src/views/Types.vue" - // DefaultHooksPath defines the default relative path to use when generating useQuery hooks for a React app. - // The path is relative to the app's directory. - DefaultHooksPath = "react/src/hooks" - // DefaultOpenAPIPath defines the default relative path to use when generating an OpenAPI schema. // The path is relative to the app's directory. DefaultOpenAPIPath = "docs/static/openapi.yml" @@ -100,16 +92,6 @@ func ComposablesPath(conf *Config) string { return DefaultComposablesPath } -// HooksPath returns the relative path to the React useQuery hooks directory. -// Path is relative to the app's directory. -func HooksPath(conf *Config) string { - if path := strings.TrimSpace(conf.Client.Hooks.Path); path != "" { - return filepath.Clean(path) - } - - return DefaultHooksPath -} - // LocateDefault locates the default path for the config file. // Returns ErrConfigNotFound when no config file found. func LocateDefault(root string) (path string, err error) { diff --git a/ignite/pkg/cosmosgen/cosmosgen.go b/ignite/pkg/cosmosgen/cosmosgen.go index 15f9093136..fa048254b1 100644 --- a/ignite/pkg/cosmosgen/cosmosgen.go +++ b/ignite/pkg/cosmosgen/cosmosgen.go @@ -29,9 +29,6 @@ type generateOptions struct { composablesOut func(module.Module) string composablesRootPath string - hooksOut func(module.Module) string - hooksRootPath string - specOut string } @@ -58,13 +55,6 @@ func WithComposablesGeneration(out ModulePathFunc, composablesRootPath string) O } } -func WithHooksGeneration(out ModulePathFunc, hooksRootPath string) Option { - return func(o *generateOptions) { - o.hooksOut = out - o.hooksRootPath = hooksRootPath - } -} - // WithGoGeneration adds protobuf (gogoproto) code generation. func WithGoGeneration() Option { return func(o *generateOptions) { @@ -191,18 +181,6 @@ func Generate(ctx context.Context, cacheStorage cache.Storage, appPath, protoDir return err } } - if g.opts.hooksRootPath != "" { - if err := g.generateComposables("react"); err != nil { - return err - } - - // Update React app dependencies when React hooks are generated. - // This update is required to link the "ts-client" folder so the - // package is available during development before publishing it. - if err := g.updateComposableDependencies("react"); err != nil { - return err - } - } return nil } diff --git a/ignite/pkg/cosmosgen/generate_composables.go b/ignite/pkg/cosmosgen/generate_composables.go index 864dcd94af..e6f5666c5f 100644 --- a/ignite/pkg/cosmosgen/generate_composables.go +++ b/ignite/pkg/cosmosgen/generate_composables.go @@ -127,13 +127,7 @@ func (g *composablesGenerator) generateComposableTemplates(p generatePayload) er } func (g *composablesGenerator) generateComposableTemplate(m module.Module, p generatePayload) error { - var outDir string - if g.frontendType == "vue" { - outDir = g.g.opts.composablesOut(m) - } else { - outDir = g.g.opts.hooksOut(m) - } - + outDir := g.g.opts.composablesRootPath if err := os.MkdirAll(outDir, 0o766); err != nil { return err } @@ -150,12 +144,7 @@ func (g *composablesGenerator) generateComposableTemplate(m module.Module, p gen } func (g *composablesGenerator) generateRootTemplates(p generatePayload) error { - var outDir string - if g.frontendType == "vue" { - outDir = g.g.opts.composablesRootPath - } else { - outDir = g.g.opts.hooksRootPath - } + outDir := g.g.opts.composablesRootPath if err := os.MkdirAll(outDir, 0o766); err != nil { return err } diff --git a/ignite/pkg/cosmosgen/webtemplates.go b/ignite/pkg/cosmosgen/webtemplates.go index 3c3c2f3ea5..000e70096a 100644 --- a/ignite/pkg/cosmosgen/webtemplates.go +++ b/ignite/pkg/cosmosgen/webtemplates.go @@ -6,11 +6,6 @@ import ( "github.com/ignite/cli/v29/ignite/pkg/localfs" ) -// React scaffolds a React app for a chain. -func React(path string) error { - return localfs.Save(webtemplates.ReactBoilerplate(), path) -} - // Vue scaffolds a Vue.js app for a chain. func Vue(path string) error { return localfs.Save(webtemplates.VueBoilerplate(), path) diff --git a/ignite/services/chain/generate.go b/ignite/services/chain/generate.go index b9d68728d8..45e8957118 100644 --- a/ignite/services/chain/generate.go +++ b/ignite/services/chain/generate.go @@ -21,7 +21,6 @@ type generateOptions struct { isGoEnabled bool isTSClientEnabled bool isComposablesEnabled bool - isHooksEnabled bool isOpenAPIEnabled bool tsClientPath string composablesPath string @@ -60,16 +59,6 @@ func GenerateComposables(path string) GenerateTarget { } } -// GenerateHooks enables generating proto based Typescript Client and React composables. -func GenerateHooks(path string) GenerateTarget { - return func(o *generateOptions) { - o.isOpenAPIEnabled = true - o.isTSClientEnabled = true - o.isHooksEnabled = true - o.hooksPath = path - } -} - // GenerateOpenAPI enables generating OpenAPI spec for your chain. func GenerateOpenAPI() GenerateTarget { return func(o *generateOptions) { @@ -111,10 +100,6 @@ func (c *Chain) generateFromConfig(ctx context.Context, cacheStorage cache.Stora if p := conf.Client.Composables.Path; p != "" { targets = append(targets, GenerateComposables(p)) } - - if p := conf.Client.Hooks.Path; p != "" { - targets = append(targets, GenerateHooks(p)) - } } // Generate proto based code for Go and optionally for any optional targets @@ -152,8 +137,8 @@ func (c *Chain) Generate( } var ( - openAPIPath, tsClientPath, composablesPath, hooksPath string - updateConfig bool + openAPIPath, tsClientPath, composablesPath string + updateConfig bool ) if targetOptions.isOpenAPIEnabled { @@ -222,30 +207,6 @@ func (c *Chain) Generate( ) } - if targetOptions.isHooksEnabled { - hooksPath = targetOptions.hooksPath - if hooksPath == "" { - hooksPath = chainconfig.HooksPath(conf) - - if conf.Client.Hooks.Path == "" { - conf.Client.Hooks.Path = hooksPath - updateConfig = true - } - } - - // Non-absolute Hooks output paths must be treated as relative to the app directory - if !filepath.IsAbs(hooksPath) { - hooksPath = filepath.Join(c.app.Path, hooksPath) - } - - options = append(options, - cosmosgen.WithHooksGeneration( - cosmosgen.ComposableModulePath(hooksPath), - hooksPath, - ), - ) - } - if err := cosmosgen.Generate( ctx, cacheStorage, @@ -281,14 +242,6 @@ func (c *Chain) Generate( ) } - if targetOptions.isHooksEnabled { - c.ev.Send( - fmt.Sprintf("React hooks path: %s", hooksPath), - events.Icon(icons.Bullet), - events.ProgressFinish(), - ) - } - if targetOptions.isOpenAPIEnabled { c.ev.Send( fmt.Sprintf("OpenAPI path: %s", openAPIPath), diff --git a/ignite/templates/app/files/readme.md.plush b/ignite/templates/app/files/readme.md.plush index c480ea2870..c0e2c15248 100644 --- a/ignite/templates/app/files/readme.md.plush +++ b/ignite/templates/app/files/readme.md.plush @@ -15,11 +15,10 @@ Your blockchain in development can be configured with `config.yml`. To learn mor ### Web Frontend -Additionally, Ignite CLI offers both Vue and React options for frontend scaffolding: +Additionally, Ignite CLI offers a frontend scaffolding feature (based on Vue) to help you quickly build a web frontend for your blockchain: -For a Vue frontend, use: `ignite scaffold vue` -For a React frontend, use: `ignite scaffold react` -These commands can be run within your scaffolded blockchain project. +Use: `ignite scaffold vue` +This command can be run within your scaffolded blockchain project. For more information see the [monorepo for Ignite front-end development](https://github.com/ignite/web). diff --git a/integration/cosmosgen/bank_module_test.go b/integration/cosmosgen/bank_module_test.go index 53875f2211..a307c238e6 100644 --- a/integration/cosmosgen/bank_module_test.go +++ b/integration/cosmosgen/bank_module_test.go @@ -16,8 +16,6 @@ import ( // TestBankModule tests the bank module by creating accounts, transferring tokens between them, and querying the account balances. func TestBankModule(t *testing.T) { - t.Skip() - var ( env = envtest.New(t) app = env.ScaffoldApp("chain", "--no-module") diff --git a/integration/cosmosgen/cosmosgen_composables_test.go b/integration/cosmosgen/cosmosgen_composables_test.go index 37e62e2982..a9c877ea66 100644 --- a/integration/cosmosgen/cosmosgen_composables_test.go +++ b/integration/cosmosgen/cosmosgen_composables_test.go @@ -12,8 +12,6 @@ import ( ) func TestCosmosGenScaffoldComposables(t *testing.T) { - t.Skip() - var ( env = envtest.New(t) app = env.ScaffoldApp("github.com/test/blog") diff --git a/integration/cosmosgen/cosmosgen_hooks_test.go b/integration/cosmosgen/cosmosgen_hooks_test.go deleted file mode 100644 index 352af6a4bf..0000000000 --- a/integration/cosmosgen/cosmosgen_hooks_test.go +++ /dev/null @@ -1,151 +0,0 @@ -package cosmosgen_test - -import ( - "os" - "path/filepath" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/ignite/cli/v29/ignite/pkg/cmdrunner/step" - envtest "github.com/ignite/cli/v29/integration" -) - -func TestCosmosGenScaffoldHooks(t *testing.T) { - t.Skip() - - var ( - env = envtest.New(t) - app = env.ScaffoldApp("github.com/test/blog") - ) - - const ( - withMsgModuleName = "withmsg" - withoutMsgModuleName = "withoutmsg" - ) - - env.Must(env.Exec("add custom module with message", - step.NewSteps(step.New( - step.Exec( - envtest.IgniteApp, - "s", - "module", - "--yes", - withMsgModuleName, - ), - step.Workdir(app.SourcePath()), - )), - )) - - env.Must(env.Exec("create a message", - step.NewSteps(step.New( - step.Exec( - envtest.IgniteApp, - "s", - "message", - "--yes", - "mymessage", - "myfield1", - "myfield2:bool", - "--module", - withMsgModuleName, - ), - step.Workdir(app.SourcePath()), - )), - )) - - env.Must(env.Exec("add custom module without message", - step.NewSteps(step.New( - step.Exec( - envtest.IgniteApp, - "s", - "module", - "--yes", - withoutMsgModuleName, - ), - step.Workdir(app.SourcePath()), - )), - )) - - env.Must(env.Exec("create a type", - step.NewSteps(step.New( - step.Exec( - envtest.IgniteApp, - "s", - "type", - "--yes", - "mytype", - "mytypefield", - "--module", - withoutMsgModuleName, - ), - step.Workdir(app.SourcePath()), - )), - )) - - env.Must(env.Exec("create a query", - step.NewSteps(step.New( - step.Exec( - envtest.IgniteApp, - "s", - "query", - "--yes", - "myQuery", - "mytypefield", - "--module", - withoutMsgModuleName, - ), - step.Workdir(app.SourcePath()), - )), - )) - - hooksDireGenerated := filepath.Join(app.SourcePath(), "react/src/hooks") - require.NoError(t, os.RemoveAll(hooksDireGenerated)) - - env.Must(env.Exec("generate hooks", - step.NewSteps(step.New( - step.Exec( - envtest.IgniteApp, - "g", - "hooks", - "--yes", - "--clear-cache", - ), - step.Workdir(app.SourcePath()), - )), - )) - - expectedQueryModules := []string{ - "useCosmosAuthV1Beta1", - "useCosmosAuthzV1Beta1", - "useCosmosBankV1Beta1", - "useCosmosBaseTendermintV1Beta1", - "useCosmosDistributionV1Beta1", - "useCosmosEvidenceV1Beta1", - "useCosmosFeegrantV1Beta1", - "useCosmosGovV1Beta1", - "useCosmosGovV1", - "useCosmosGroupV1", - "useCosmosMintV1Beta1", - "useCosmosNftV1Beta1", - "useCosmosParamsV1Beta1", - "useCosmosSlashingV1Beta1", - "useCosmosStakingV1Beta1", - "useCosmosTxV1Beta1", - "useCosmosUpgradeV1Beta1", - "useCosmosVestingV1Beta1", - // custom modules - "useTestBlogBlog", - "useTestBlogWithmsg", - "useTestBlogWithoutmsg", - } - - for _, mod := range expectedQueryModules { - - _, err := os.Stat(filepath.Join(hooksDireGenerated, mod)) - if assert.False(t, os.IsNotExist(err), "missing hook %q in %s", mod, hooksDireGenerated) { - assert.NoError(t, err) - } - } -} diff --git a/integration/cosmosgen/custom_module_test.go b/integration/cosmosgen/custom_module_test.go index e740c5dd84..501d58cb26 100644 --- a/integration/cosmosgen/custom_module_test.go +++ b/integration/cosmosgen/custom_module_test.go @@ -16,8 +16,6 @@ import ( ) func TestCustomModule(t *testing.T) { - t.Skip() - var ( env = envtest.New(t) app = env.ScaffoldApp("chain", "--no-module") From e9923523c6eac5ccb471ff57cf1523fe78496e29 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Fri, 27 Jun 2025 10:08:11 +0200 Subject: [PATCH 02/15] deprecate command and no-op it --- changelog.md | 1 + ignite/cmd/scaffold.go | 1 + ignite/cmd/scaffold_react.go | 15 +++++++++++++++ ignite/cmd/scaffold_vue.go | 1 - 4 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 ignite/cmd/scaffold_react.go diff --git a/changelog.md b/changelog.md index e57f55de62..1855d9c879 100644 --- a/changelog.md +++ b/changelog.md @@ -19,6 +19,7 @@ - [#4691](https://github.com/ignite/cli/pull/4691), [#4706](https://github.com/ignite/cli/pull/4706), [#4725](https://github.com/ignite/cli/pull/4725), [#4737](https://github.com/ignite/cli/pull/4737) Fix ts-client query template and solely Go template for `ts-client` generation. - [#4742](https://github.com/ignite/cli/pull/4742) Updates Vue composables template for new ts-client and tanstack/vue-query v5 +- [#4744](https://github.com/ignite/cli/pull/4744) Remove `react` frontend generation via `s react` command. Use the [Ignite CCA App](https://github.com/ignite/apps) instead. ## [`v29.0.0`](https://github.com/ignite/cli/releases/tag/v29.0.0) diff --git a/ignite/cmd/scaffold.go b/ignite/cmd/scaffold.go index e5c034ec88..03dc931346 100644 --- a/ignite/cmd/scaffold.go +++ b/ignite/cmd/scaffold.go @@ -128,6 +128,7 @@ with an "--ibc" flag. Note that the default module is not IBC-enabled. NewScaffoldQuery(), NewScaffoldPacket(), NewScaffoldVue(), + NewScaffoldReact(), NewScaffoldChainRegistry(), ) diff --git a/ignite/cmd/scaffold_react.go b/ignite/cmd/scaffold_react.go new file mode 100644 index 0000000000..60a9dfd47d --- /dev/null +++ b/ignite/cmd/scaffold_react.go @@ -0,0 +1,15 @@ +package ignitecmd + +import ( + "github.com/spf13/cobra" +) + +// NewScaffoldReact scaffolds a React app for a chain. +func NewScaffoldReact() *cobra.Command { + c := &cobra.Command{ + Use: "react", + Deprecated: "the React scaffolding feature is removed from Ignite CLI.\nPlease use the Ignite CCA app to create a React app.\nFor more information, visit: https://ignite.com/marketplace/CCA", + } + + return c +} diff --git a/ignite/cmd/scaffold_vue.go b/ignite/cmd/scaffold_vue.go index 2228979414..ad05fe68d2 100644 --- a/ignite/cmd/scaffold_vue.go +++ b/ignite/cmd/scaffold_vue.go @@ -11,7 +11,6 @@ import ( // NewScaffoldVue scaffolds a Vue.js app for a chain. func NewScaffoldVue() *cobra.Command { c := &cobra.Command{ - Hidden: true, // hidden util we have a better ts-client. Use: "vue", Short: "Vue 3 web app template", Args: cobra.NoArgs, From 1de350a317742ff40128b3b9442efe22b1d2a171 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Fri, 27 Jun 2025 10:10:03 +0200 Subject: [PATCH 03/15] lint --- ignite/services/chain/generate.go | 1 - 1 file changed, 1 deletion(-) diff --git a/ignite/services/chain/generate.go b/ignite/services/chain/generate.go index 45e8957118..9dd8b9feb8 100644 --- a/ignite/services/chain/generate.go +++ b/ignite/services/chain/generate.go @@ -24,7 +24,6 @@ type generateOptions struct { isOpenAPIEnabled bool tsClientPath string composablesPath string - hooksPath string } // GenerateTarget is a target to generate code for from proto files. From f306c74311d12bd73722072f21228e13289bd4d8 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Fri, 27 Jun 2025 11:45:49 +0200 Subject: [PATCH 04/15] bump web to v1.0.8 --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 7c83f02c6c..8d7c8327d7 100644 --- a/go.mod +++ b/go.mod @@ -39,7 +39,7 @@ require ( github.com/hashicorp/go-hclog v1.6.3 github.com/hashicorp/go-plugin v1.6.3 github.com/iancoleman/strcase v0.3.0 - github.com/ignite/web v0.6.1 + github.com/ignite/web v1.0.8 github.com/lib/pq v1.10.9 github.com/mitchellh/mapstructure v1.5.0 github.com/muesli/reflow v0.3.0 diff --git a/go.sum b/go.sum index bbc383393e..078483d421 100644 --- a/go.sum +++ b/go.sum @@ -1101,8 +1101,8 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1: github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= github.com/ianlancetaylor/demangle v0.0.0-20230524184225-eabc099b10ab/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw= -github.com/ignite/web v0.6.1 h1:kHG+T7NnR8cCPjAGxEFQD+njVYM08toeG57iYRXzpwo= -github.com/ignite/web v0.6.1/go.mod h1:WZWBaBYF8RazN7dE462BLpvXDY8ScacxcJ07BKwX/jY= +github.com/ignite/web v1.0.8 h1:St3L6UJj70+h16+No5em8Vn2Hx93tS2G1MyWO/Kt1cc= +github.com/ignite/web v1.0.8/go.mod h1:WZWBaBYF8RazN7dE462BLpvXDY8ScacxcJ07BKwX/jY= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM= github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= From b14e60fb7c6e39db2fe0c98624fc8163834e694b Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Mon, 30 Jun 2025 21:08:34 +0200 Subject: [PATCH 05/15] remove hooks --- ignite/config/chain/base/config.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/ignite/config/chain/base/config.go b/ignite/config/chain/base/config.go index b462a53cee..5b1cfdce4f 100644 --- a/ignite/config/chain/base/config.go +++ b/ignite/config/chain/base/config.go @@ -57,12 +57,6 @@ type Composables struct { Path string `yaml:"path" doc:"Relative path where the application's composable files are located."` } -// Hooks configures code generation for react-query hooks. -type Hooks struct { - // Path configures out location for generated vue-query hooks. - Path string `yaml:"path" doc:"Relative path where the application's hooks files are located."` -} - // OpenAPI configures OpenAPI spec generation for API. type OpenAPI struct { Path string `yaml:"path" doc:"Relative path where the application's OpenAPI files are located."` From ec28c03080052565ff9aceb335ca1be27746d4d3 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Mon, 30 Jun 2025 21:25:47 +0200 Subject: [PATCH 06/15] improvements --- go.mod | 2 +- ignite/cmd/scaffold_vue.go | 5 +-- ignite/pkg/cosmosgen/cosmosgen.go | 7 ++-- ignite/pkg/cosmosgen/generate_composables.go | 35 +++++++++----------- ignite/services/chain/generate.go | 1 + ignite/services/scaffolder/scaffolder.go | 10 +++++- 6 files changed, 34 insertions(+), 26 deletions(-) diff --git a/go.mod b/go.mod index bc3f2f58c2..1919e5d365 100644 --- a/go.mod +++ b/go.mod @@ -17,6 +17,7 @@ require ( github.com/charmbracelet/fang v0.2.0 github.com/charmbracelet/glow v1.5.1 github.com/charmbracelet/lipgloss v1.1.0 + github.com/charmbracelet/lipgloss/v2 v2.0.0-beta.1 github.com/cockroachdb/errors v1.12.0 github.com/cometbft/cometbft v0.38.17 github.com/cosmos/cosmos-sdk v0.53.2 @@ -143,7 +144,6 @@ require ( github.com/charmbracelet/charm v0.8.7 // indirect github.com/charmbracelet/colorprofile v0.3.0 // indirect github.com/charmbracelet/glamour v0.6.0 // indirect - github.com/charmbracelet/lipgloss/v2 v2.0.0-beta.1 // indirect github.com/charmbracelet/x/ansi v0.8.0 // indirect github.com/charmbracelet/x/cellbuf v0.0.13 // indirect github.com/charmbracelet/x/exp/charmtone v0.0.0-20250603201427-c31516f43444 // indirect diff --git a/ignite/cmd/scaffold_vue.go b/ignite/cmd/scaffold_vue.go index ad05fe68d2..541b1e001e 100644 --- a/ignite/cmd/scaffold_vue.go +++ b/ignite/cmd/scaffold_vue.go @@ -1,6 +1,8 @@ package ignitecmd import ( + "path/filepath" + "github.com/spf13/cobra" chainconfig "github.com/ignite/cli/v29/ignite/config/chain" @@ -19,7 +21,6 @@ func NewScaffoldVue() *cobra.Command { } c.Flags().AddFlagSet(flagSetYes()) - c.Flags().StringP(flagPath, "p", "./"+chainconfig.DefaultVuePath, "path to scaffold content of the Vue.js app") return c } @@ -31,7 +32,7 @@ func scaffoldVueHandler(cmd *cobra.Command, _ []string) error { ) defer session.End() - path := flagGetPath(cmd) + path := filepath.Join(".", chainconfig.DefaultVuePath) if err := cosmosgen.Vue(path); err != nil { return err } diff --git a/ignite/pkg/cosmosgen/cosmosgen.go b/ignite/pkg/cosmosgen/cosmosgen.go index fa048254b1..a55f201792 100644 --- a/ignite/pkg/cosmosgen/cosmosgen.go +++ b/ignite/pkg/cosmosgen/cosmosgen.go @@ -92,6 +92,7 @@ type generator struct { appPath string protoDir string goModPath string + frontendPath string opts *generateOptions sdkImport string sdkDir string @@ -112,7 +113,7 @@ func (g *generator) cleanup() { // Generate generates code from protoDir of an SDK app residing at appPath with given options. // protoDir must be relative to the projectPath. -func Generate(ctx context.Context, cacheStorage cache.Storage, appPath, protoDir, goModPath string, options ...Option) error { +func Generate(ctx context.Context, cacheStorage cache.Storage, appPath, protoDir, goModPath string, frontendPath string, options ...Option) error { buf, err := cosmosbuf.New(cacheStorage, goModPath) if err != nil { return err @@ -170,14 +171,14 @@ func Generate(ctx context.Context, cacheStorage cache.Storage, appPath, protoDir } if g.opts.composablesRootPath != "" { - if err := g.generateComposables("vue"); err != nil { + if err := g.generateComposables(); err != nil { return err } // Update Vue app dependencies when Vue composables are generated. // This update is required to link the "ts-client" folder so the // package is available during development before publishing it. - if err := g.updateComposableDependencies("vue"); err != nil { + if err := g.updateComposableDependencies(); err != nil { return err } } diff --git a/ignite/pkg/cosmosgen/generate_composables.go b/ignite/pkg/cosmosgen/generate_composables.go index e6f5666c5f..fd7f82cc85 100644 --- a/ignite/pkg/cosmosgen/generate_composables.go +++ b/ignite/pkg/cosmosgen/generate_composables.go @@ -15,18 +15,9 @@ import ( "github.com/ignite/cli/v29/ignite/pkg/gomodulepath" ) -type composablesGenerator struct { - g *generator - frontendType string -} - -func newComposablesGenerator(g *generator, frontendType string) *composablesGenerator { - return &composablesGenerator{g, frontendType} -} - -func (g *generator) updateComposableDependencies(frontendType string) error { +func (g *generator) updateComposableDependencies() error { // Init the path to the appropriate frontend folder inside the app - frontendPath := filepath.Join(g.appPath, frontendType) + frontendPath := filepath.Join(g.appPath, g.frontendPath) packagesPath := filepath.Join(frontendPath, "package.json") if _, err := os.Stat(packagesPath); errors.Is(err, os.ErrNotExist) { return nil @@ -90,7 +81,7 @@ func (g *generator) updateComposableDependencies(frontendType string) error { return nil } -func (g *generator) generateComposables(frontendType string) error { +func (g *generator) generateComposables() error { chainPath, _, err := gomodulepath.Find(g.appPath) if err != nil { return err @@ -106,7 +97,7 @@ func (g *generator) generateComposables(frontendType string) error { data.Modules = append(data.Modules, modules...) } - vsg := newComposablesGenerator(g, frontendType) + vsg := newComposablesGenerator(g) if err := vsg.generateComposableTemplates(data); err != nil { return err } @@ -114,6 +105,14 @@ func (g *generator) generateComposables(frontendType string) error { return vsg.generateRootTemplates(data) } +type composablesGenerator struct { + g *generator +} + +func newComposablesGenerator(g *generator) *composablesGenerator { + return &composablesGenerator{g} +} + func (g *composablesGenerator) generateComposableTemplates(p generatePayload) error { gg := &errgroup.Group{} @@ -133,13 +132,11 @@ func (g *composablesGenerator) generateComposableTemplate(m module.Module, p gen } return templateTSClientComposable.Write(outDir, "", struct { - Module module.Module - PackageNS string - FrontendType string + Module module.Module + PackageNS string }{ - Module: m, - PackageNS: p.PackageNS, - FrontendType: g.frontendType, + Module: m, + PackageNS: p.PackageNS, }) } diff --git a/ignite/services/chain/generate.go b/ignite/services/chain/generate.go index 9dd8b9feb8..97c8f05cef 100644 --- a/ignite/services/chain/generate.go +++ b/ignite/services/chain/generate.go @@ -212,6 +212,7 @@ func (c *Chain) Generate( c.app.Path, conf.Build.Proto.Path, c.app.ImportPath, + chainconfig.DefaultVuePath, options..., ); err != nil { return &CannotBuildAppError{err} diff --git a/ignite/services/scaffolder/scaffolder.go b/ignite/services/scaffolder/scaffolder.go index a54d95639c..723a77b6bc 100644 --- a/ignite/services/scaffolder/scaffolder.go +++ b/ignite/services/scaffolder/scaffolder.go @@ -176,7 +176,15 @@ func protoc(ctx context.Context, cacheStorage cache.Storage, projectPath, protoD options = append(options, cosmosgen.WithOpenAPIGeneration(openAPIPath)) } - if err := cosmosgen.Generate(ctx, cacheStorage, projectPath, protoDir, goModPath, options...); err != nil { + if err := cosmosgen.Generate( + ctx, + cacheStorage, + projectPath, + protoDir, + goModPath, + chainconfig.DefaultVuePath, + options..., + ); err != nil { return err } From 9d5dd430c1d7f9801e2cb1617b1a122cc451094d Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Mon, 30 Jun 2025 21:26:14 +0200 Subject: [PATCH 07/15] update index.ts.tpl --- ignite/pkg/cosmosgen/templates/composable/index.ts.tpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ignite/pkg/cosmosgen/templates/composable/index.ts.tpl b/ignite/pkg/cosmosgen/templates/composable/index.ts.tpl index 352f128f56..4f3a97eb5a 100644 --- a/ignite/pkg/cosmosgen/templates/composable/index.ts.tpl +++ b/ignite/pkg/cosmosgen/templates/composable/index.ts.tpl @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ -import { useQuery, type UseQueryOptions, useInfiniteQuery, type UseInfiniteQueryOptions, type InfiniteData } from "@tanstack/{{- .FrontendType -}}-query"; +import { useQuery, type UseQueryOptions, useInfiniteQuery, type UseInfiniteQueryOptions, type InfiniteData } from "@tanstack/vue-query"; import { useClient } from '../useClient'; export default function use{{ camelCaseUpperSta $.Module.Pkg.Name }}() { From d9edac9049af269bb9e2bd084119123544f2d3c9 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Mon, 30 Jun 2025 21:31:10 +0200 Subject: [PATCH 08/15] fix --- ignite/pkg/cosmosgen/cosmosgen.go | 1 + 1 file changed, 1 insertion(+) diff --git a/ignite/pkg/cosmosgen/cosmosgen.go b/ignite/pkg/cosmosgen/cosmosgen.go index a55f201792..6152fe16e9 100644 --- a/ignite/pkg/cosmosgen/cosmosgen.go +++ b/ignite/pkg/cosmosgen/cosmosgen.go @@ -124,6 +124,7 @@ func Generate(ctx context.Context, cacheStorage cache.Storage, appPath, protoDir appPath: appPath, protoDir: protoDir, goModPath: goModPath, + frontendPath: frontendPath, opts: &generateOptions{}, thirdModules: make(map[string][]module.Module), thirdModuleIncludes: make(map[string]protoIncludes), From affeecd6d89cdadd378e3842b4c72de0cda0c927 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Tue, 1 Jul 2025 12:33:02 +0200 Subject: [PATCH 09/15] improve ux --- ignite/pkg/cosmosgen/generate_composables.go | 26 ++++++++++++++----- .../cosmosgen/cosmosgen_composables_test.go | 1 - 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/ignite/pkg/cosmosgen/generate_composables.go b/ignite/pkg/cosmosgen/generate_composables.go index fd7f82cc85..ebb01cb4da 100644 --- a/ignite/pkg/cosmosgen/generate_composables.go +++ b/ignite/pkg/cosmosgen/generate_composables.go @@ -15,22 +15,30 @@ import ( "github.com/ignite/cli/v29/ignite/pkg/gomodulepath" ) +func (g *generator) checkVueExists() error { + _, err := os.Stat(filepath.Join(g.appPath, g.frontendPath)) + if errors.Is(err, os.ErrNotExist) { + return errors.New("frontend does not exist, please run `ignite scaffold vue` first") + } + + return err +} + func (g *generator) updateComposableDependencies() error { + if err := g.checkVueExists(); err != nil { + return err + } + // Init the path to the appropriate frontend folder inside the app frontendPath := filepath.Join(g.appPath, g.frontendPath) - packagesPath := filepath.Join(frontendPath, "package.json") - if _, err := os.Stat(packagesPath); errors.Is(err, os.ErrNotExist) { - return nil - } + packagesPath := filepath.Join(g.appPath, g.frontendPath, "package.json") - // Read the Vue app package file b, err := os.ReadFile(packagesPath) if err != nil { return err } - var pkg map[string]interface{} - + var pkg map[string]any if err := json.Unmarshal(b, &pkg); err != nil { return errors.Errorf("error parsing %s: %w", packagesPath, err) } @@ -82,6 +90,10 @@ func (g *generator) updateComposableDependencies() error { } func (g *generator) generateComposables() error { + if err := g.checkVueExists(); err != nil { + return err + } + chainPath, _, err := gomodulepath.Find(g.appPath) if err != nil { return err diff --git a/integration/cosmosgen/cosmosgen_composables_test.go b/integration/cosmosgen/cosmosgen_composables_test.go index a9c877ea66..30885b3db1 100644 --- a/integration/cosmosgen/cosmosgen_composables_test.go +++ b/integration/cosmosgen/cosmosgen_composables_test.go @@ -98,7 +98,6 @@ func TestCosmosGenScaffoldComposables(t *testing.T) { } for _, mod := range expectedQueryModules { - _, err := os.Stat(filepath.Join(composablesDirGenerated, mod)) if assert.False(t, os.IsNotExist(err), "missing composable %q in %s", mod, composablesDirGenerated) { assert.NoError(t, err) From e20c3e3bcd6a7c3f1f76d9b9a7324c423219072b Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Tue, 1 Jul 2025 12:43:02 +0200 Subject: [PATCH 10/15] add pnpm instructions --- docs/docs/04-clients/03-vue.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/docs/docs/04-clients/03-vue.md b/docs/docs/04-clients/03-vue.md index f62f1f4e55..66f8d8fd9f 100644 --- a/docs/docs/04-clients/03-vue.md +++ b/docs/docs/04-clients/03-vue.md @@ -99,20 +99,22 @@ purposes, but you should not do this in production. In the `example` directory run the following command to start your blockchain: -``` +```bash ignite chain serve ``` To start your Vue application, go to the `vue` directory and run the following command in a separate terminal window: -``` -npm install && npm run dev +:::note +Make sure you have [pnpm](https://pnpm.io/) installed. +::: + +```bash +pnpm install && pnpm dev ``` -It is recommended to run `npm install` before starting your app with `npm run -dev` to ensure that all dependencies are installed (including the ones that the -API client has, see `vue/postinstall.js`). +It is recommended to run `pnpm install` before starting your app with `pnpm dev` to ensure that all dependencies are installed (including the ones that the API client has, see `vue/postinstall.js`). Open your browser and navigate to [http://localhost:5173/](http://localhost:5173/). From fa4b4882ab8b975cd778193480c84864be269b13 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Tue, 1 Jul 2025 16:33:33 +0200 Subject: [PATCH 11/15] fixes --- ignite/pkg/cosmosgen/generate_composables.go | 2 +- integration/client.go | 156 ------------------- integration/cosmosgen/bank_module_test.go | 89 ----------- integration/cosmosgen/bank_module_test.ts | 61 -------- integration/cosmosgen/custom_module_test.go | 87 ----------- integration/cosmosgen/custom_module_test.ts | 41 ----- 6 files changed, 1 insertion(+), 435 deletions(-) delete mode 100644 integration/client.go delete mode 100644 integration/cosmosgen/bank_module_test.go delete mode 100644 integration/cosmosgen/bank_module_test.ts delete mode 100644 integration/cosmosgen/custom_module_test.go delete mode 100644 integration/cosmosgen/custom_module_test.ts diff --git a/ignite/pkg/cosmosgen/generate_composables.go b/ignite/pkg/cosmosgen/generate_composables.go index ebb01cb4da..98a642a815 100644 --- a/ignite/pkg/cosmosgen/generate_composables.go +++ b/ignite/pkg/cosmosgen/generate_composables.go @@ -138,7 +138,7 @@ func (g *composablesGenerator) generateComposableTemplates(p generatePayload) er } func (g *composablesGenerator) generateComposableTemplate(m module.Module, p generatePayload) error { - outDir := g.g.opts.composablesRootPath + outDir := g.g.opts.composablesOut(m) if err := os.MkdirAll(outDir, 0o766); err != nil { return err } diff --git a/integration/client.go b/integration/client.go deleted file mode 100644 index c48df283f2..0000000000 --- a/integration/client.go +++ /dev/null @@ -1,156 +0,0 @@ -package envtest - -import ( - "bytes" - "maps" - "os" - "os/exec" - "path/filepath" - "runtime" - - "github.com/stretchr/testify/require" - - chainconfig "github.com/ignite/cli/v29/ignite/config/chain" - "github.com/ignite/cli/v29/ignite/pkg/cmdrunner" - "github.com/ignite/cli/v29/ignite/pkg/cmdrunner/step" -) - -type clientOptions struct { - env map[string]string - testName, testFilePath string -} - -// ClientOption defines options for the TS client test runner. -type ClientOption func(*clientOptions) - -// ClientEnv option defines environment values for the tests. -func ClientEnv(env map[string]string) ClientOption { - return func(o *clientOptions) { - maps.Copy(o.env, env) - } -} - -// ClientTestName option defines a pattern to match the test names that should be run. -func ClientTestName(pattern string) ClientOption { - return func(o *clientOptions) { - o.testName = pattern - } -} - -// ClientTestFile option defines the name of the file where to look for tests. -func ClientTestFile(filePath string) ClientOption { - return func(o *clientOptions) { - o.testFilePath = filePath - } -} - -// RunClientTests runs the Typescript client tests. -func (a App) RunClientTests(options ...ClientOption) bool { - npm, err := exec.LookPath("npm") - require.NoError(a.env.t, err, "npm binary not found") - - // The root dir for the tests must be an absolute path. - // It is used as the start search point to find test files. - rootDir, err := os.Getwd() - require.NoError(a.env.t, err) - - // The filename of this module is required to be able to define the location - // of the TS client test runner package to be used as working directory when - // running the tests. - _, filename, _, ok := runtime.Caller(0) - if !ok { - a.env.t.Fatal("failed to read file name") - } - - opts := clientOptions{ - env: map[string]string{ - // Absolute path to the blockchain app directory - "TEST_CHAIN_PATH": a.path, - // Absolute path to the TS client directory - "TEST_TSCLIENT_DIR": filepath.Join(a.path, chainconfig.DefaultTSClientPath), - }, - } - for _, o := range options { - o(&opts) - } - - var ( - output bytes.Buffer - env []string - ) - - // Install the dependencies needed to run TS client tests - ok = a.env.Exec("install client dependencies", step.NewSteps( - step.New( - step.Workdir(filepath.Join(a.path, chainconfig.DefaultTSClientPath)), - step.Stdout(&output), - step.Exec(npm, "install"), - step.PostExec(func(err error) error { - // Print the npm output when there is an error - if err != nil { - a.env.t.Log("\n", output.String()) - } - - return err - }), - ), - )) - if !ok { - return false - } - - output.Reset() - - args := []string{"run", "test", "--", "--dir", rootDir} - if opts.testName != "" { - args = append(args, "-t", opts.testName) - } - - if opts.testFilePath != "" { - args = append(args, opts.testFilePath) - } - - for k, v := range opts.env { - env = append(env, cmdrunner.Env(k, v)) - } - - // The tests are run from the TS client test runner package directory - runnerDir := filepath.Join(filepath.Dir(filename), "testdata/tstestrunner") - - // TODO: Ignore stderr ? Errors are already displayed with traceback in the stdout - return a.env.Exec("run client tests", step.NewSteps( - // Make sure the test runner dependencies are installed - step.New( - step.Workdir(runnerDir), - step.Stdout(&output), - step.Exec(npm, "install"), - step.PostExec(func(err error) error { - // Print the npm output when there is an error - if err != nil { - a.env.t.Log("\n", output.String()) - } - - return err - }), - ), - // Run the TS client tests - step.New( - step.Workdir(runnerDir), - step.Stdout(&output), - step.Env(env...), - step.PreExec(func() error { - // Clear the output from the previous step - output.Reset() - - return nil - }), - step.Exec(npm, args...), - step.PostExec(func(err error) error { - // Always print tests output to be available on errors or when verbose is enabled - a.env.t.Log("\n", output.String()) - - return err - }), - ), - )) -} diff --git a/integration/cosmosgen/bank_module_test.go b/integration/cosmosgen/bank_module_test.go deleted file mode 100644 index a307c238e6..0000000000 --- a/integration/cosmosgen/bank_module_test.go +++ /dev/null @@ -1,89 +0,0 @@ -package cosmosgen_test - -import ( - "context" - "encoding/json" - "fmt" - "testing" - - "github.com/stretchr/testify/require" - - chainconfig "github.com/ignite/cli/v29/ignite/config/chain" - "github.com/ignite/cli/v29/ignite/config/chain/base" - "github.com/ignite/cli/v29/ignite/pkg/xurl" - envtest "github.com/ignite/cli/v29/integration" -) - -// TestBankModule tests the bank module by creating accounts, transferring tokens between them, and querying the account balances. -func TestBankModule(t *testing.T) { - var ( - env = envtest.New(t) - app = env.ScaffoldApp("chain", "--no-module") - servers = app.RandomizeServerPorts() - ) - - queryAPI, err := xurl.HTTP(servers.API) - require.NoError(t, err) - - txAPI, err := xurl.HTTP(servers.RPC) - require.NoError(t, err) - - // Accounts to be included in the genesis - accounts := []base.Account{ - { - Name: "account1", - Address: "cosmos1j8hw8283hj80hhq8urxaj40syrzqp77dt8qwhm", - Mnemonic: fmt.Sprint( - "toe mail light plug pact length excess predict real artwork laundry when steel ", - "online adapt clutch debate vehicle dash alter rifle virtual season almost", - ), - Coins: []string{"10000token", "10000stake"}, - }, - { - Name: "account2", - Address: "cosmos19yy9sf00k00cjcwh532haeq8s63uhdy7qs5m2n", - Mnemonic: fmt.Sprint( - "someone major rule wrestle forget want job record coil table enter gold bracket ", - "zone tent music grow shiver width index radio matter asset when", - ), - Coins: []string{"100token", "100stake"}, - }, - { - Name: "account3", - Address: "cosmos10957ee377t2xpwyt4mlpedjldp592h0ylt8uz7", - Mnemonic: fmt.Sprint( - "edit effort own cat chuckle rookie mechanic side tool sausage other fade math ", - "joy midnight cabin act plastic spawn loud chest invest budget rebel", - ), - Coins: []string{"100token", "100stake"}, - }, - } - - app.EditConfig(func(cfg *chainconfig.Config) { - cfg.Accounts = append(cfg.Accounts, accounts...) - }) - - env.Must(app.GenerateTSClient()) - - ctx, cancel := context.WithTimeout(env.Ctx(), envtest.ServeTimeout) - defer cancel() - - go func() { - app.Serve("should serve app", envtest.ExecCtx(ctx)) - }() - - // Wait for the server to be up before running the client tests - app.WaitChainUp(ctx, servers.API) - - testAccounts, err := json.Marshal(accounts) - require.NoError(t, err) - - env.Must(app.RunClientTests( - envtest.ClientTestFile("bank_module_test.ts"), - envtest.ClientEnv(map[string]string{ - "TEST_QUERY_API": queryAPI, - "TEST_TX_API": txAPI, - "TEST_ACCOUNTS": string(testAccounts), - }), - )) -} diff --git a/integration/cosmosgen/bank_module_test.ts b/integration/cosmosgen/bank_module_test.ts deleted file mode 100644 index 8a6090ac97..0000000000 --- a/integration/cosmosgen/bank_module_test.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { describe, expect, it } from "vitest"; -import { DirectSecp256k1HdWallet } from "@cosmjs/proto-signing"; -import { isDeliverTxSuccess } from "@cosmjs/stargate"; - -describe("bank module", async () => { - const { Client } = await import("client"); - - it("should transfer to two different addresses", async () => { - const { account1, account2, account3 } = globalThis.accounts; - - const mnemonic = account1["Mnemonic"]; - const wallet = await DirectSecp256k1HdWallet.fromMnemonic(mnemonic); - const [account] = await wallet.getAccounts(); - - const denom = "token"; - const env = { - denom, - rpcURL: globalThis.txApi, - apiURL: globalThis.queryApi, - }; - const client = new Client(env, wallet); - - const toAddresses = [account2["Address"], account3["Address"]]; - - // Both accounts start with 100token before the transfer - const result = await client.signAndBroadcast([ - client.CosmosBankV1Beta1.tx.msgSend({ - value: { - fromAddress: account.address, - toAddress: toAddresses[0], - amount: [{ denom, amount: "100" }], - }, - }), - client.CosmosBankV1Beta1.tx.msgSend({ - value: { - fromAddress: account.address, - toAddress: toAddresses[1], - amount: [{ denom, amount: "200" }], - }, - }), - ]); - - expect(isDeliverTxSuccess(result)).toEqual(true); - - // Check that the transfers were successful - const cases = [ - { address: toAddresses[0], wantAmount: "200" }, - { address: toAddresses[1], wantAmount: "300" }, - ]; - - for (let tc of cases) { - let response = await client.CosmosBankV1Beta1.query.queryBalance( - tc.address, - { denom } - ); - - expect(response.statusText).toEqual("OK"); - expect(response.data.balance.amount).toEqual(tc.wantAmount); - } - }); -}); diff --git a/integration/cosmosgen/custom_module_test.go b/integration/cosmosgen/custom_module_test.go deleted file mode 100644 index 501d58cb26..0000000000 --- a/integration/cosmosgen/custom_module_test.go +++ /dev/null @@ -1,87 +0,0 @@ -package cosmosgen_test - -import ( - "context" - "encoding/json" - "fmt" - "testing" - - "github.com/stretchr/testify/require" - - chainconfig "github.com/ignite/cli/v29/ignite/config/chain" - "github.com/ignite/cli/v29/ignite/config/chain/base" - "github.com/ignite/cli/v29/ignite/pkg/cmdrunner/step" - "github.com/ignite/cli/v29/ignite/pkg/xurl" - envtest "github.com/ignite/cli/v29/integration" -) - -func TestCustomModule(t *testing.T) { - var ( - env = envtest.New(t) - app = env.ScaffoldApp("chain", "--no-module") - servers = app.RandomizeServerPorts() - ) - - queryAPI, err := xurl.HTTP(servers.API) - require.NoError(t, err) - - txAPI, err := xurl.HTTP(servers.RPC) - require.NoError(t, err) - - // Accounts to be included in the genesis - accounts := []base.Account{ - { - Name: "account1", - Address: "cosmos1j8hw8283hj80hhq8urxaj40syrzqp77dt8qwhm", - Mnemonic: fmt.Sprint( - "toe mail light plug pact length excess predict real artwork laundry when ", - "steel online adapt clutch debate vehicle dash alter rifle virtual season almost", - ), - Coins: []string{"10000token", "10000stake"}, - }, - } - - app.EditConfig(func(cfg *chainconfig.Config) { - cfg.Accounts = append(cfg.Accounts, accounts...) - }) - - path := app.SourcePath() - - env.Must(env.Exec("create a module", - step.NewSteps(step.New( - step.Exec(envtest.IgniteApp, "s", "module", "disco", "--require-registration", "--yes"), - step.Workdir(path), - )), - )) - - env.Must(env.Exec("create a list type", - step.NewSteps(step.New( - step.Exec(envtest.IgniteApp, "s", "list", "entry", "name", "--module", "disco", "--yes"), - step.Workdir(path), - )), - )) - - env.Must(app.GenerateTSClient()) - - ctx, cancel := context.WithTimeout(env.Ctx(), envtest.ServeTimeout) - defer cancel() - - go func() { - app.Serve("serve app", envtest.ExecCtx(ctx)) - }() - - // Wait for the server to be up before running the client tests - app.WaitChainUp(ctx, servers.API) - - testAccounts, err := json.Marshal(accounts) - require.NoError(t, err) - - env.Must(app.RunClientTests( - envtest.ClientTestFile("custom_module_test.ts"), - envtest.ClientEnv(map[string]string{ - "TEST_QUERY_API": queryAPI, - "TEST_TX_API": txAPI, - "TEST_ACCOUNTS": string(testAccounts), - }), - )) -} diff --git a/integration/cosmosgen/custom_module_test.ts b/integration/cosmosgen/custom_module_test.ts deleted file mode 100644 index 4d51795238..0000000000 --- a/integration/cosmosgen/custom_module_test.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { DirectSecp256k1HdWallet } from '@cosmjs/proto-signing' -import { isDeliverTxSuccess } from '@cosmjs/stargate' - -describe('custom module', async () => { - const { Client } = await import('client') - - it('should create a list entry', async () => { - const { account1 } = globalThis.accounts - - const mnemonic = account1['Mnemonic'] - const wallet = await DirectSecp256k1HdWallet.fromMnemonic(mnemonic) - const [account] = await wallet.getAccounts(); - - const denom = 'token' - const env = { - denom, - rpcURL: globalThis.txApi, - apiURL: globalThis.queryApi, - } - const client = new Client(env, wallet) - - const entry = { - id: '0', - creator: account.address, - name: "test", - } - - // Create a new list entry - const result = await client.ChainDisco.tx.sendMsgCreateEntry({ value: entry }) - - expect(isDeliverTxSuccess(result)).toEqual(true) - - // Check that the list entry is created - const response = await client.ChainDisco.query.queryEntryAll() - - expect(response.statusText).toEqual('OK') - expect(response.data['Entry']).toHaveLength(1) - expect(response.data['Entry'][0]).toEqual(entry) - }) -}) From 2718df3f16c4018d4e5769686bf87e4cde760b80 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Tue, 1 Jul 2025 16:58:29 +0200 Subject: [PATCH 12/15] fix integration test --- integration/app.go | 11 +++++++++-- integration/cosmosgen/cosmosgen_composables_test.go | 12 +++++++++--- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/integration/app.go b/integration/app.go index dc3aee6994..6de6125627 100644 --- a/integration/app.go +++ b/integration/app.go @@ -376,8 +376,15 @@ func (a *App) addScaffoldCmd(typeName string, args ...string) { index := "" response := "" params := "" - name := args[0] - args = args[1:] + name := typeName + + // in the case of scaffolding commands that do no take arguments + // we can skip the argument parsing + if len(args) > 0 { + name = args[0] + args = args[1:] + } + filteredArgs := make([]string, 0) // remove the flags from the args diff --git a/integration/cosmosgen/cosmosgen_composables_test.go b/integration/cosmosgen/cosmosgen_composables_test.go index 30885b3db1..ebb1bc9a02 100644 --- a/integration/cosmosgen/cosmosgen_composables_test.go +++ b/integration/cosmosgen/cosmosgen_composables_test.go @@ -65,6 +65,12 @@ func TestCosmosGenScaffoldComposables(t *testing.T) { composablesDirGenerated := filepath.Join(app.SourcePath(), "vue/src/composables") require.NoError(t, os.RemoveAll(composablesDirGenerated)) + app.Scaffold( + "scaffold vue", + false, + "vue", + ) + app.Generate( "generate composables", false, @@ -92,9 +98,9 @@ func TestCosmosGenScaffoldComposables(t *testing.T) { "useCosmosUpgradeV1Beta1", "useCosmosVestingV1Beta1", // custom modules - "useTestBlogBlog", - "useTestBlogWithmsg", - "useTestBlogWithoutmsg", + "useTestBlogBlogv1", + "useTestBlogWithmsgv1", + "useTestBlogWithoutmsgv1", } for _, mod := range expectedQueryModules { From b844ad99b9f97da7c2114fdb5de966669c9caebe Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Tue, 1 Jul 2025 17:10:48 +0200 Subject: [PATCH 13/15] rename --- .../cosmosgen/cosmosgen_composables_test.go | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/integration/cosmosgen/cosmosgen_composables_test.go b/integration/cosmosgen/cosmosgen_composables_test.go index ebb1bc9a02..63b64c8b82 100644 --- a/integration/cosmosgen/cosmosgen_composables_test.go +++ b/integration/cosmosgen/cosmosgen_composables_test.go @@ -98,9 +98,9 @@ func TestCosmosGenScaffoldComposables(t *testing.T) { "useCosmosUpgradeV1Beta1", "useCosmosVestingV1Beta1", // custom modules - "useTestBlogBlogv1", - "useTestBlogWithmsgv1", - "useTestBlogWithoutmsgv1", + "useBlogBlogV1", + "useBlogWithmsgV1", + "useBlogWithoutmsgV1", } for _, mod := range expectedQueryModules { @@ -109,4 +109,14 @@ func TestCosmosGenScaffoldComposables(t *testing.T) { assert.NoError(t, err) } } + + if t.Failed() { + // list composables files + composablesFiles, err := os.ReadDir(composablesDirGenerated) + require.NoError(t, err) + t.Log("Composables files:", len(composablesFiles)) + for _, file := range composablesFiles { + t.Logf(" - %s", file.Name()) + } + } } From 5341edcb7674cdc505e321c290bba5b21dd7961c Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Tue, 1 Jul 2025 17:58:29 +0200 Subject: [PATCH 14/15] uncomment other test --- integration/cosmosgen/cosmosgen_test.go | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/integration/cosmosgen/cosmosgen_test.go b/integration/cosmosgen/cosmosgen_test.go index af1473e651..01580878c6 100644 --- a/integration/cosmosgen/cosmosgen_test.go +++ b/integration/cosmosgen/cosmosgen_test.go @@ -13,8 +13,6 @@ import ( ) func TestCosmosGenScaffold(t *testing.T) { - t.Skip("skip till we add a buf token into the CI") - var ( env = envtest.New(t) app = env.ScaffoldApp("github.com/test/blog") @@ -147,4 +145,14 @@ func TestCosmosGenScaffold(t *testing.T) { assert.NoError(t, err) } } + + if t.Failed() { + // list ts-client files + tsFiles, err := os.ReadDir(tsDirGenerated) + require.NoError(t, err) + t.Log("TS files:", len(tsFiles)) + for _, file := range tsFiles { + t.Logf(" - %s", file.Name()) + } + } } From 0c77a8537d9768f874843dba3ebd3634e3dd6151 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Tue, 1 Jul 2025 18:14:16 +0200 Subject: [PATCH 15/15] updates --- integration/cosmosgen/cosmosgen_composables_test.go | 4 ++++ integration/cosmosgen/cosmosgen_test.go | 4 ++++ integration/env.go | 2 +- integration/exec.go | 2 +- 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/integration/cosmosgen/cosmosgen_composables_test.go b/integration/cosmosgen/cosmosgen_composables_test.go index 63b64c8b82..d7ecdb9fd5 100644 --- a/integration/cosmosgen/cosmosgen_composables_test.go +++ b/integration/cosmosgen/cosmosgen_composables_test.go @@ -12,6 +12,10 @@ import ( ) func TestCosmosGenScaffoldComposables(t *testing.T) { + if envtest.IsCI { + t.Skip("Skipping TestCosmosGenScaffoldComposables test in CI environment") + } + var ( env = envtest.New(t) app = env.ScaffoldApp("github.com/test/blog") diff --git a/integration/cosmosgen/cosmosgen_test.go b/integration/cosmosgen/cosmosgen_test.go index 01580878c6..22f289432a 100644 --- a/integration/cosmosgen/cosmosgen_test.go +++ b/integration/cosmosgen/cosmosgen_test.go @@ -13,6 +13,10 @@ import ( ) func TestCosmosGenScaffold(t *testing.T) { + if envtest.IsCI { + t.Skip("Skipping CosmosGenScaffold test in CI environment") + } + var ( env = envtest.New(t) app = env.ScaffoldApp("github.com/test/blog") diff --git a/integration/env.go b/integration/env.go index 00406147e9..72767c4377 100644 --- a/integration/env.go +++ b/integration/env.go @@ -33,7 +33,7 @@ var ( // invoked. IgniteApp = path.Join(os.TempDir(), "ignite-tests", "ignite") - isCI, _ = strconv.ParseBool(os.Getenv("CI")) + IsCI, _ = strconv.ParseBool(os.Getenv("CI")) compileBinaryOnce sync.Once ) diff --git a/integration/exec.go b/integration/exec.go index 0e4d48869b..02d1fd11f3 100644 --- a/integration/exec.go +++ b/integration/exec.go @@ -81,7 +81,7 @@ func (e Env) Exec(msg string, steps step.Steps, options ...ExecOption) (ok bool) fmt.Printf("Executing %d step(s) for %q\n", len(steps), msg) copts = append(copts, cmdrunner.EnableDebug()) } - if isCI { + if IsCI { copts = append(copts, cmdrunner.EndSignal(os.Kill)) } err := cmdrunner.