From 8946d2c8f5c637a6afe2cfa77c296baff9d40953 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Fri, 15 Dec 2023 09:41:23 -0800 Subject: [PATCH 001/101] Switch package name --- add.go | 49 ++++++++ contractinstaller.go | 262 +++++++++++++++++++++++++++++++++++++++++++ dependencies.go | 18 +++ fileutils.go | 23 ++++ install.go | 44 ++++++++ 5 files changed, 396 insertions(+) create mode 100644 add.go create mode 100644 contractinstaller.go create mode 100644 dependencies.go create mode 100644 fileutils.go create mode 100644 install.go diff --git a/add.go b/add.go new file mode 100644 index 000000000..2145642cf --- /dev/null +++ b/add.go @@ -0,0 +1,49 @@ +package dependencymanager + +import ( + "fmt" + + "github.com/onflow/flow-cli/flowkit" + "github.com/onflow/flow-cli/flowkit/output" + "github.com/onflow/flow-cli/internal/command" + "github.com/spf13/cobra" +) + +type addFlagsCollection struct { + name string `default:"" flag:"name" info:"Name of the dependency"` +} + +var addFlags = addFlagsCollection{} + +var addCommand = &command.Command{ + Cmd: &cobra.Command{ + Use: "add", + Short: "Add a single contract and its dependencies.", + Args: cobra.ExactArgs(1), + }, + Flags: &addFlags, + RunS: add, +} + +func add( + args []string, + _ command.GlobalFlags, + logger output.Logger, + flow flowkit.Services, + state *flowkit.State, +) (result command.Result, err error) { + logger.StartProgress(fmt.Sprintf("Installing dependencies for %s...", args[0])) + defer logger.StopProgress() + + dep := args[0] + + installer := NewContractInstaller(logger, state) + if err := installer.add(dep, addFlags.name); err != nil { + logger.Error(fmt.Sprintf("Error: %v", err)) + return nil, err + } + + logger.Info("✅ Dependencies installed. Check your flow.json") + + return nil, nil +} diff --git a/contractinstaller.go b/contractinstaller.go new file mode 100644 index 000000000..b5561a791 --- /dev/null +++ b/contractinstaller.go @@ -0,0 +1,262 @@ +package dependencymanager + +import ( + "fmt" + "sync" + + "github.com/onflow/flow-go/fvm/systemcontracts" + "github.com/onflow/flow-go/model/flow" + + "github.com/onflow/flow-cli/flowkit/gateway" + + "github.com/onflow/flow-cli/flowkit/project" + + "github.com/onflow/flow-cli/flowkit/config" + flowsdk "github.com/onflow/flow-go-sdk" + + "github.com/onflow/flow-cli/flowkit" + "github.com/onflow/flow-cli/flowkit/output" +) + +type ContractInstaller struct { + Gateways map[string]gateway.Gateway + Logger output.Logger + State *flowkit.State + Mutex sync.Mutex +} + +func NewContractInstaller(logger output.Logger, state *flowkit.State) *ContractInstaller { + emulatorGateway, err := gateway.NewGrpcGateway(config.EmulatorNetwork) + if err != nil { + logger.Error(fmt.Sprintf("Error creating emulator gateway: %v", err)) + } + + testnetGateway, err := gateway.NewGrpcGateway(config.TestnetNetwork) + if err != nil { + logger.Error(fmt.Sprintf("Error creating testnet gateway: %v", err)) + } + + mainnetGateway, err := gateway.NewGrpcGateway(config.MainnetNetwork) + if err != nil { + logger.Error(fmt.Sprintf("Error creating mainnet gateway: %v", err)) + } + + gateways := map[string]gateway.Gateway{ + config.EmulatorNetwork.Name: emulatorGateway, + config.TestnetNetwork.Name: testnetGateway, + config.MainnetNetwork.Name: mainnetGateway, + } + + return &ContractInstaller{ + Gateways: gateways, + Logger: logger, + State: state, + } +} + +func (ci *ContractInstaller) install() error { + for _, dependency := range *ci.State.Dependencies() { + if err := ci.processDependency(dependency); err != nil { + ci.Logger.Error(fmt.Sprintf("Error processing dependency: %v", err)) + return err + } + } + return nil +} + +func (ci *ContractInstaller) add(depRemoteSource, customName string) error { + depNetwork, depAddress, depContractName, err := config.ParseRemoteSourceString(depRemoteSource) + if err != nil { + return fmt.Errorf("error parsing remote source: %w", err) + } + + var name string + + if customName != "" { + name = customName + } else { + name = depContractName + } + + dep := config.Dependency{ + Name: name, + RemoteSource: config.RemoteSource{ + NetworkName: depNetwork, + Address: flowsdk.HexToAddress(depAddress), + ContractName: depContractName, + }, + } + + if err := ci.processDependency(dep); err != nil { + return fmt.Errorf("error processing dependency: %w", err) + } + + return nil +} + +func (ci *ContractInstaller) processDependency(dependency config.Dependency) error { + depAddress := flowsdk.HexToAddress(dependency.RemoteSource.Address.String()) + return ci.fetchDependencies(dependency.RemoteSource.NetworkName, depAddress, dependency.Name, dependency.RemoteSource.ContractName) +} + +func (ci *ContractInstaller) fetchDependencies(networkName string, address flowsdk.Address, assignedName, contractName string) error { + account, err := ci.Gateways[networkName].GetAccount(address) + if err != nil { + return fmt.Errorf("failed to get account: %v", err) + } + if account == nil { + return fmt.Errorf("account is nil for address: %s", address) + } + + if account.Contracts == nil { + return fmt.Errorf("contracts are nil for account: %s", address) + } + + var wg sync.WaitGroup + errCh := make(chan error, len(account.Contracts)) + + for _, contract := range account.Contracts { + + program, err := project.NewProgram(contract, nil, "") + if err != nil { + return fmt.Errorf("failed to parse program: %v", err) + } + + parsedContractName, err := program.Name() + if err != nil { + return fmt.Errorf("failed to parse contract name: %v", err) + } + + if parsedContractName == contractName { + program.ConvertImports() + + if err := ci.handleFoundContract(networkName, address.String(), assignedName, parsedContractName, string(program.DevelopmentCode())); err != nil { + return fmt.Errorf("failed to handle found contract: %v", err) + } + + if program.HasAddressImports() { + imports := program.AddressImportDeclarations() + for _, imp := range imports { + wg.Add(1) + go func(importAddress flowsdk.Address, contractName string) { + defer wg.Done() + err := ci.fetchDependencies("testnet", importAddress, contractName, contractName) + if err != nil { + errCh <- err + } + }(flowsdk.HexToAddress(imp.Location.String()), imp.Identifiers[0].String()) + } + } + } + } + + wg.Wait() + close(errCh) + + for err := range errCh { + if err != nil { + return err + } + } + + return nil +} + +func (ci *ContractInstaller) handleFoundContract(networkName, contractAddr, assignedName, contractName, contractData string) error { + ci.Mutex.Lock() + defer ci.Mutex.Unlock() + + if !contractFileExists(contractAddr, contractName) { + if err := createContractFile(contractAddr, contractName, contractData); err != nil { + return fmt.Errorf("failed to create contract file: %v", err) + } + } + + err := ci.updateState(networkName, contractAddr, assignedName, contractName) + if err != nil { + ci.Logger.Error(fmt.Sprintf("Error updating state: %v", err)) + return err + } + + return nil +} + +const ( + NetworkEmulator = "emulator" + NetworkTestnet = "testnet" + NetworkMainnet = "mainnet" +) + +var networkToChainID = map[string]flow.ChainID{ + NetworkEmulator: flow.Emulator, + NetworkTestnet: flow.Testnet, + NetworkMainnet: flow.Mainnet, +} + +func isCoreContract(networkName, contractName, contractAddress string) bool { + sc := systemcontracts.SystemContractsForChain(networkToChainID[networkName]) + coreContracts := sc.All() + + for _, coreContract := range coreContracts { + if coreContract.Name == contractName && coreContract.Address.String() == contractAddress { + return true + } + } + + return false +} + +func getCoreContractByName(networkName, contractName string) *systemcontracts.SystemContract { + sc := systemcontracts.SystemContractsForChain(networkToChainID[networkName]) + + for i, coreContract := range sc.All() { + if coreContract.Name == contractName { + return &sc.All()[i] + } + } + + return nil +} + +func (ci *ContractInstaller) updateState(networkName, contractAddress, assignedName, contractName string) error { + dep := config.Dependency{ + Name: assignedName, + RemoteSource: config.RemoteSource{ + NetworkName: networkName, + Address: flowsdk.HexToAddress(contractAddress), + ContractName: contractName, + }, + } + + var aliases []config.Alias + + // If core contract found by name and address matches, then use all core contract aliases across networks + if isCoreContract(networkName, contractName, contractAddress) { + for _, networkStr := range []string{NetworkEmulator, NetworkTestnet, NetworkMainnet} { + coreContract := getCoreContractByName(networkStr, contractName) + if coreContract != nil { + aliases = append(aliases, config.Alias{ + Network: networkStr, + Address: flowsdk.HexToAddress(coreContract.Address.String()), + }) + } + } + } + + // If no core contract match, then use the address in remoteSource as alias + if len(aliases) == 0 { + aliases = append(aliases, config.Alias{ + Network: dep.RemoteSource.NetworkName, + Address: dep.RemoteSource.Address, + }) + } + + ci.State.Dependencies().AddOrUpdate(dep) + ci.State.Contracts().AddDependencyAsContract(dep, aliases) + err := ci.State.SaveDefault() + if err != nil { + return err + } + + return nil +} diff --git a/dependencies.go b/dependencies.go new file mode 100644 index 000000000..6d9934af2 --- /dev/null +++ b/dependencies.go @@ -0,0 +1,18 @@ +package dependencymanager + +import ( + "github.com/spf13/cobra" +) + +var Cmd = &cobra.Command{ + Use: "dependencies", + Short: "Manage contracts and dependencies", + TraverseChildren: true, + GroupID: "manager", + Aliases: []string{"deps"}, +} + +func init() { + addCommand.AddToParent(Cmd) + installCommand.AddToParent(Cmd) +} diff --git a/fileutils.go b/fileutils.go new file mode 100644 index 000000000..cc1a342e5 --- /dev/null +++ b/fileutils.go @@ -0,0 +1,23 @@ +package dependencymanager + +import ( + "os" + "path/filepath" +) + +func contractFileExists(address, contractName string) bool { + path := filepath.Join("imports", address, contractName) + _, err := os.Stat(path) + return !os.IsNotExist(err) +} + +func createContractFile(address, contractName, data string) error { + path := filepath.Join("imports", address, contractName) + + dir := filepath.Dir(path) + if err := os.MkdirAll(dir, os.ModePerm); err != nil { + return err + } + + return os.WriteFile(path, []byte(data), 0644) +} diff --git a/install.go b/install.go new file mode 100644 index 000000000..a7a1fd107 --- /dev/null +++ b/install.go @@ -0,0 +1,44 @@ +package dependencymanager + +import ( + "fmt" + + "github.com/onflow/flow-cli/flowkit" + "github.com/onflow/flow-cli/flowkit/output" + "github.com/onflow/flow-cli/internal/command" + "github.com/spf13/cobra" +) + +type installFlagsCollection struct{} + +var installFlags = installFlagsCollection{} + +var installCommand = &command.Command{ + Cmd: &cobra.Command{ + Use: "install", + Short: "Install contract and dependencies.", + }, + Flags: &installFlags, + RunS: install, +} + +func install( + _ []string, + _ command.GlobalFlags, + logger output.Logger, + flow flowkit.Services, + state *flowkit.State, +) (result command.Result, err error) { + logger.StartProgress("Installing dependencies from flow.json...") + defer logger.StopProgress() + + installer := NewContractInstaller(logger, state) + if err := installer.install(); err != nil { + logger.Error(fmt.Sprintf("Error: %v", err)) + return nil, err + } + + logger.Info("✅ Dependencies installed. Check your flow.json") + + return nil, nil +} From b1807630fef5c1db1972092319c36671aec405c8 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Fri, 15 Dec 2023 09:43:08 -0800 Subject: [PATCH 002/101] Switch to DependencyManager --- add.go | 2 +- contractinstaller.go => dependencyinstaller.go | 18 +++++++++--------- install.go | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) rename contractinstaller.go => dependencyinstaller.go (89%) diff --git a/add.go b/add.go index 2145642cf..475a214ca 100644 --- a/add.go +++ b/add.go @@ -37,7 +37,7 @@ func add( dep := args[0] - installer := NewContractInstaller(logger, state) + installer := NewDepdencyInstaller(logger, state) if err := installer.add(dep, addFlags.name); err != nil { logger.Error(fmt.Sprintf("Error: %v", err)) return nil, err diff --git a/contractinstaller.go b/dependencyinstaller.go similarity index 89% rename from contractinstaller.go rename to dependencyinstaller.go index b5561a791..579bf185d 100644 --- a/contractinstaller.go +++ b/dependencyinstaller.go @@ -18,14 +18,14 @@ import ( "github.com/onflow/flow-cli/flowkit/output" ) -type ContractInstaller struct { +type DependencyInstaller struct { Gateways map[string]gateway.Gateway Logger output.Logger State *flowkit.State Mutex sync.Mutex } -func NewContractInstaller(logger output.Logger, state *flowkit.State) *ContractInstaller { +func NewDepdencyInstaller(logger output.Logger, state *flowkit.State) *DependencyInstaller { emulatorGateway, err := gateway.NewGrpcGateway(config.EmulatorNetwork) if err != nil { logger.Error(fmt.Sprintf("Error creating emulator gateway: %v", err)) @@ -47,14 +47,14 @@ func NewContractInstaller(logger output.Logger, state *flowkit.State) *ContractI config.MainnetNetwork.Name: mainnetGateway, } - return &ContractInstaller{ + return &DependencyInstaller{ Gateways: gateways, Logger: logger, State: state, } } -func (ci *ContractInstaller) install() error { +func (ci *DependencyInstaller) install() error { for _, dependency := range *ci.State.Dependencies() { if err := ci.processDependency(dependency); err != nil { ci.Logger.Error(fmt.Sprintf("Error processing dependency: %v", err)) @@ -64,7 +64,7 @@ func (ci *ContractInstaller) install() error { return nil } -func (ci *ContractInstaller) add(depRemoteSource, customName string) error { +func (ci *DependencyInstaller) add(depRemoteSource, customName string) error { depNetwork, depAddress, depContractName, err := config.ParseRemoteSourceString(depRemoteSource) if err != nil { return fmt.Errorf("error parsing remote source: %w", err) @@ -94,12 +94,12 @@ func (ci *ContractInstaller) add(depRemoteSource, customName string) error { return nil } -func (ci *ContractInstaller) processDependency(dependency config.Dependency) error { +func (ci *DependencyInstaller) processDependency(dependency config.Dependency) error { depAddress := flowsdk.HexToAddress(dependency.RemoteSource.Address.String()) return ci.fetchDependencies(dependency.RemoteSource.NetworkName, depAddress, dependency.Name, dependency.RemoteSource.ContractName) } -func (ci *ContractInstaller) fetchDependencies(networkName string, address flowsdk.Address, assignedName, contractName string) error { +func (ci *DependencyInstaller) fetchDependencies(networkName string, address flowsdk.Address, assignedName, contractName string) error { account, err := ci.Gateways[networkName].GetAccount(address) if err != nil { return fmt.Errorf("failed to get account: %v", err) @@ -162,7 +162,7 @@ func (ci *ContractInstaller) fetchDependencies(networkName string, address flows return nil } -func (ci *ContractInstaller) handleFoundContract(networkName, contractAddr, assignedName, contractName, contractData string) error { +func (ci *DependencyInstaller) handleFoundContract(networkName, contractAddr, assignedName, contractName, contractData string) error { ci.Mutex.Lock() defer ci.Mutex.Unlock() @@ -218,7 +218,7 @@ func getCoreContractByName(networkName, contractName string) *systemcontracts.Sy return nil } -func (ci *ContractInstaller) updateState(networkName, contractAddress, assignedName, contractName string) error { +func (ci *DependencyInstaller) updateState(networkName, contractAddress, assignedName, contractName string) error { dep := config.Dependency{ Name: assignedName, RemoteSource: config.RemoteSource{ diff --git a/install.go b/install.go index a7a1fd107..4c0e4900c 100644 --- a/install.go +++ b/install.go @@ -32,7 +32,7 @@ func install( logger.StartProgress("Installing dependencies from flow.json...") defer logger.StopProgress() - installer := NewContractInstaller(logger, state) + installer := NewDepdencyInstaller(logger, state) if err := installer.install(); err != nil { logger.Error(fmt.Sprintf("Error: %v", err)) return nil, err From a7213f14309635f4caa64218be251288695f967e Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Tue, 19 Dec 2023 13:51:40 -0800 Subject: [PATCH 003/101] Don't save dependencies as contracts, just use under the hood --- dependencyinstaller.go | 65 +----------------------------------------- 1 file changed, 1 insertion(+), 64 deletions(-) diff --git a/dependencyinstaller.go b/dependencyinstaller.go index 579bf185d..2ecc5e1b4 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -4,9 +4,6 @@ import ( "fmt" "sync" - "github.com/onflow/flow-go/fvm/systemcontracts" - "github.com/onflow/flow-go/model/flow" - "github.com/onflow/flow-cli/flowkit/gateway" "github.com/onflow/flow-cli/flowkit/project" @@ -181,43 +178,6 @@ func (ci *DependencyInstaller) handleFoundContract(networkName, contractAddr, as return nil } -const ( - NetworkEmulator = "emulator" - NetworkTestnet = "testnet" - NetworkMainnet = "mainnet" -) - -var networkToChainID = map[string]flow.ChainID{ - NetworkEmulator: flow.Emulator, - NetworkTestnet: flow.Testnet, - NetworkMainnet: flow.Mainnet, -} - -func isCoreContract(networkName, contractName, contractAddress string) bool { - sc := systemcontracts.SystemContractsForChain(networkToChainID[networkName]) - coreContracts := sc.All() - - for _, coreContract := range coreContracts { - if coreContract.Name == contractName && coreContract.Address.String() == contractAddress { - return true - } - } - - return false -} - -func getCoreContractByName(networkName, contractName string) *systemcontracts.SystemContract { - sc := systemcontracts.SystemContractsForChain(networkToChainID[networkName]) - - for i, coreContract := range sc.All() { - if coreContract.Name == contractName { - return &sc.All()[i] - } - } - - return nil -} - func (ci *DependencyInstaller) updateState(networkName, contractAddress, assignedName, contractName string) error { dep := config.Dependency{ Name: assignedName, @@ -228,31 +188,8 @@ func (ci *DependencyInstaller) updateState(networkName, contractAddress, assigne }, } - var aliases []config.Alias - - // If core contract found by name and address matches, then use all core contract aliases across networks - if isCoreContract(networkName, contractName, contractAddress) { - for _, networkStr := range []string{NetworkEmulator, NetworkTestnet, NetworkMainnet} { - coreContract := getCoreContractByName(networkStr, contractName) - if coreContract != nil { - aliases = append(aliases, config.Alias{ - Network: networkStr, - Address: flowsdk.HexToAddress(coreContract.Address.String()), - }) - } - } - } - - // If no core contract match, then use the address in remoteSource as alias - if len(aliases) == 0 { - aliases = append(aliases, config.Alias{ - Network: dep.RemoteSource.NetworkName, - Address: dep.RemoteSource.Address, - }) - } - ci.State.Dependencies().AddOrUpdate(dep) - ci.State.Contracts().AddDependencyAsContract(dep, aliases) + ci.State.Contracts().AddDependencyAsContract(dep, networkName) err := ci.State.SaveDefault() if err != nil { return err From cd432089cf713a0d59ef8266ea6faffb076c4b56 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Tue, 2 Jan 2024 10:50:57 -0800 Subject: [PATCH 004/101] Add license headers --- add.go | 18 ++++++++++++++++++ dependencies.go | 18 ++++++++++++++++++ dependencyinstaller.go | 18 ++++++++++++++++++ fileutils.go | 18 ++++++++++++++++++ install.go | 18 ++++++++++++++++++ 5 files changed, 90 insertions(+) diff --git a/add.go b/add.go index 475a214ca..81ed39db1 100644 --- a/add.go +++ b/add.go @@ -1,3 +1,21 @@ +/* + * Flow CLI + * + * Copyright 2019 Dapper Labs, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package dependencymanager import ( diff --git a/dependencies.go b/dependencies.go index 6d9934af2..7175b7e9b 100644 --- a/dependencies.go +++ b/dependencies.go @@ -1,3 +1,21 @@ +/* + * Flow CLI + * + * Copyright 2019 Dapper Labs, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package dependencymanager import ( diff --git a/dependencyinstaller.go b/dependencyinstaller.go index 2ecc5e1b4..4449857c9 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -1,3 +1,21 @@ +/* + * Flow CLI + * + * Copyright 2019 Dapper Labs, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package dependencymanager import ( diff --git a/fileutils.go b/fileutils.go index cc1a342e5..485dc57ba 100644 --- a/fileutils.go +++ b/fileutils.go @@ -1,3 +1,21 @@ +/* + * Flow CLI + * + * Copyright 2019 Dapper Labs, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package dependencymanager import ( diff --git a/install.go b/install.go index 4c0e4900c..8045818a6 100644 --- a/install.go +++ b/install.go @@ -1,3 +1,21 @@ +/* + * Flow CLI + * + * Copyright 2019 Dapper Labs, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package dependencymanager import ( From f7769775a28cccccbf7e50d0af4597a9a5558a6d Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Tue, 2 Jan 2024 14:40:56 -0800 Subject: [PATCH 005/101] Fix golint --- add.go | 3 ++- dependencyinstaller.go | 3 ++- install.go | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/add.go b/add.go index 81ed39db1..bd237ad70 100644 --- a/add.go +++ b/add.go @@ -21,10 +21,11 @@ package dependencymanager import ( "fmt" + "github.com/spf13/cobra" + "github.com/onflow/flow-cli/flowkit" "github.com/onflow/flow-cli/flowkit/output" "github.com/onflow/flow-cli/internal/command" - "github.com/spf13/cobra" ) type addFlagsCollection struct { diff --git a/dependencyinstaller.go b/dependencyinstaller.go index 4449857c9..38ae18745 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -26,9 +26,10 @@ import ( "github.com/onflow/flow-cli/flowkit/project" - "github.com/onflow/flow-cli/flowkit/config" flowsdk "github.com/onflow/flow-go-sdk" + "github.com/onflow/flow-cli/flowkit/config" + "github.com/onflow/flow-cli/flowkit" "github.com/onflow/flow-cli/flowkit/output" ) diff --git a/install.go b/install.go index 8045818a6..0c132ea53 100644 --- a/install.go +++ b/install.go @@ -21,10 +21,11 @@ package dependencymanager import ( "fmt" + "github.com/spf13/cobra" + "github.com/onflow/flow-cli/flowkit" "github.com/onflow/flow-cli/flowkit/output" "github.com/onflow/flow-cli/internal/command" - "github.com/spf13/cobra" ) type installFlagsCollection struct{} From 19d3afc085e4c790b9d11dc91d29081723b17531 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Wed, 10 Jan 2024 10:02:36 -0800 Subject: [PATCH 006/101] Move import conversion to handleFoundContract --- dependencyinstaller.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/dependencyinstaller.go b/dependencyinstaller.go index 38ae18745..c16396841 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -144,9 +144,8 @@ func (ci *DependencyInstaller) fetchDependencies(networkName string, address flo } if parsedContractName == contractName { - program.ConvertImports() - if err := ci.handleFoundContract(networkName, address.String(), assignedName, parsedContractName, string(program.DevelopmentCode())); err != nil { + if err := ci.handleFoundContract(networkName, address.String(), assignedName, parsedContractName, program); err != nil { return fmt.Errorf("failed to handle found contract: %v", err) } @@ -178,10 +177,13 @@ func (ci *DependencyInstaller) fetchDependencies(networkName string, address flo return nil } -func (ci *DependencyInstaller) handleFoundContract(networkName, contractAddr, assignedName, contractName, contractData string) error { +func (ci *DependencyInstaller) handleFoundContract(networkName, contractAddr, assignedName, contractName string, program *project.Program) error { ci.Mutex.Lock() defer ci.Mutex.Unlock() + program.ConvertImports() + contractData := string(program.DevelopmentCode()) + if !contractFileExists(contractAddr, contractName) { if err := createContractFile(contractAddr, contractName, contractData); err != nil { return fmt.Errorf("failed to create contract file: %v", err) From c61b8f338aca6e1c4b8f39192cbde240626de540 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Wed, 10 Jan 2024 10:49:46 -0800 Subject: [PATCH 007/101] Add version hash to dependency --- dependencyinstaller.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/dependencyinstaller.go b/dependencyinstaller.go index c16396841..86d76fdde 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -19,6 +19,8 @@ package dependencymanager import ( + "crypto/sha256" + "encoding/hex" "fmt" "sync" @@ -181,6 +183,10 @@ func (ci *DependencyInstaller) handleFoundContract(networkName, contractAddr, as ci.Mutex.Lock() defer ci.Mutex.Unlock() + hash := sha256.New() + hash.Write(program.DevelopmentCode()) + originalContractDataHash := hex.EncodeToString(hash.Sum(nil)) + program.ConvertImports() contractData := string(program.DevelopmentCode()) @@ -190,7 +196,7 @@ func (ci *DependencyInstaller) handleFoundContract(networkName, contractAddr, as } } - err := ci.updateState(networkName, contractAddr, assignedName, contractName) + err := ci.updateState(networkName, contractAddr, assignedName, contractName, originalContractDataHash) if err != nil { ci.Logger.Error(fmt.Sprintf("Error updating state: %v", err)) return err @@ -199,7 +205,7 @@ func (ci *DependencyInstaller) handleFoundContract(networkName, contractAddr, as return nil } -func (ci *DependencyInstaller) updateState(networkName, contractAddress, assignedName, contractName string) error { +func (ci *DependencyInstaller) updateState(networkName, contractAddress, assignedName, contractName, contractHash string) error { dep := config.Dependency{ Name: assignedName, RemoteSource: config.RemoteSource{ @@ -207,6 +213,7 @@ func (ci *DependencyInstaller) updateState(networkName, contractAddress, assigne Address: flowsdk.HexToAddress(contractAddress), ContractName: contractName, }, + Version: contractHash, } ci.State.Dependencies().AddOrUpdate(dep) From 90929316c45dbeac3b5ce71b1db49bcaeaca12fa Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Wed, 10 Jan 2024 15:44:06 -0800 Subject: [PATCH 008/101] Add prompt for updating out of date deps --- add.go | 3 +-- dependencyinstaller.go | 11 +++++++++++ install.go | 3 +-- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/add.go b/add.go index bd237ad70..9a473b190 100644 --- a/add.go +++ b/add.go @@ -51,8 +51,7 @@ func add( flow flowkit.Services, state *flowkit.State, ) (result command.Result, err error) { - logger.StartProgress(fmt.Sprintf("Installing dependencies for %s...", args[0])) - defer logger.StopProgress() + logger.Info(fmt.Sprintf("🔄 Installing dependencies for %s...", args[0])) dep := args[0] diff --git a/dependencyinstaller.go b/dependencyinstaller.go index 86d76fdde..3ee15180d 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -22,6 +22,7 @@ import ( "crypto/sha256" "encoding/hex" "fmt" + "github.com/onflow/flow-cli/internal/util" "sync" "github.com/onflow/flow-cli/flowkit/gateway" @@ -190,6 +191,16 @@ func (ci *DependencyInstaller) handleFoundContract(networkName, contractAddr, as program.ConvertImports() contractData := string(program.DevelopmentCode()) + // Check version hash and prompt if different + // Ignore if no hash + dependency := ci.State.Dependencies().ByName(assignedName) + if dependency != nil && dependency.Version != "" && dependency.Version != originalContractDataHash { + msg := fmt.Sprintf("The latest version of %s is different from the one you have locally. Do you want to update it?", contractName) + if !util.GenericBoolPrompt(msg) { + return nil + } + } + if !contractFileExists(contractAddr, contractName) { if err := createContractFile(contractAddr, contractName, contractData); err != nil { return fmt.Errorf("failed to create contract file: %v", err) diff --git a/install.go b/install.go index 0c132ea53..83a571172 100644 --- a/install.go +++ b/install.go @@ -48,8 +48,7 @@ func install( flow flowkit.Services, state *flowkit.State, ) (result command.Result, err error) { - logger.StartProgress("Installing dependencies from flow.json...") - defer logger.StopProgress() + logger.Info("🔄 Installing dependencies from flow.json...") installer := NewDepdencyInstaller(logger, state) if err := installer.install(); err != nil { From 46a3fe881b2a39aecb876de2c36e0689b8c3efc3 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Thu, 11 Jan 2024 09:29:05 -0800 Subject: [PATCH 009/101] Fix lint --- dependencyinstaller.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dependencyinstaller.go b/dependencyinstaller.go index 3ee15180d..c7e4eaba2 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -22,9 +22,10 @@ import ( "crypto/sha256" "encoding/hex" "fmt" - "github.com/onflow/flow-cli/internal/util" "sync" + "github.com/onflow/flow-cli/internal/util" + "github.com/onflow/flow-cli/flowkit/gateway" "github.com/onflow/flow-cli/flowkit/project" From d5f99d0d49636f549226aad49d102b455bd2eff5 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Thu, 11 Jan 2024 16:38:13 -0800 Subject: [PATCH 010/101] Error if conflict exists --- dependencyinstaller.go | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/dependencyinstaller.go b/dependencyinstaller.go index c7e4eaba2..3b53e86c0 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -22,9 +22,9 @@ import ( "crypto/sha256" "encoding/hex" "fmt" - "sync" - "github.com/onflow/flow-cli/internal/util" + "os" + "sync" "github.com/onflow/flow-cli/flowkit/gateway" @@ -192,9 +192,18 @@ func (ci *DependencyInstaller) handleFoundContract(networkName, contractAddr, as program.ConvertImports() contractData := string(program.DevelopmentCode()) - // Check version hash and prompt if different - // Ignore if no hash dependency := ci.State.Dependencies().ByName(assignedName) + + // If a dependency by this name already exists and its remote source network or address does not match, then give option to stop or continue + if dependency != nil && (dependency.RemoteSource.NetworkName != networkName || dependency.RemoteSource.Address.String() != contractAddr) { + ci.Logger.Info(fmt.Sprintf("🚫 A dependency named %s already exists with a different remote source. Please fix the conflict and retry.", assignedName)) + os.Exit(0) + return nil + } + + // Check if remote source version is different from local version + // If it is, ask if they want to update + // If no hash, ignore if dependency != nil && dependency.Version != "" && dependency.Version != originalContractDataHash { msg := fmt.Sprintf("The latest version of %s is different from the one you have locally. Do you want to update it?", contractName) if !util.GenericBoolPrompt(msg) { From 68d84f25d4589d289478d5aef181038a82d1e316 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Thu, 11 Jan 2024 17:02:43 -0800 Subject: [PATCH 011/101] Run lint --- dependencyinstaller.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dependencyinstaller.go b/dependencyinstaller.go index 3b53e86c0..625f0f14e 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -22,10 +22,11 @@ import ( "crypto/sha256" "encoding/hex" "fmt" - "github.com/onflow/flow-cli/internal/util" "os" "sync" + "github.com/onflow/flow-cli/internal/util" + "github.com/onflow/flow-cli/flowkit/gateway" "github.com/onflow/flow-cli/flowkit/project" From fcf3cfacc64dda7b7b339abdfcfb217b8a5c5872 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Tue, 16 Jan 2024 14:50:37 -0800 Subject: [PATCH 012/101] Fix typo --- add.go | 2 +- dependencyinstaller.go | 2 +- install.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/add.go b/add.go index 9a473b190..7cb4399d4 100644 --- a/add.go +++ b/add.go @@ -55,7 +55,7 @@ func add( dep := args[0] - installer := NewDepdencyInstaller(logger, state) + installer := NewDependencyInstaller(logger, state) if err := installer.add(dep, addFlags.name); err != nil { logger.Error(fmt.Sprintf("Error: %v", err)) return nil, err diff --git a/dependencyinstaller.go b/dependencyinstaller.go index 625f0f14e..1d3036c7d 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -46,7 +46,7 @@ type DependencyInstaller struct { Mutex sync.Mutex } -func NewDepdencyInstaller(logger output.Logger, state *flowkit.State) *DependencyInstaller { +func NewDependencyInstaller(logger output.Logger, state *flowkit.State) *DependencyInstaller { emulatorGateway, err := gateway.NewGrpcGateway(config.EmulatorNetwork) if err != nil { logger.Error(fmt.Sprintf("Error creating emulator gateway: %v", err)) diff --git a/install.go b/install.go index 83a571172..751a8a087 100644 --- a/install.go +++ b/install.go @@ -50,7 +50,7 @@ func install( ) (result command.Result, err error) { logger.Info("🔄 Installing dependencies from flow.json...") - installer := NewDepdencyInstaller(logger, state) + installer := NewDependencyInstaller(logger, state) if err := installer.install(); err != nil { logger.Error(fmt.Sprintf("Error: %v", err)) return nil, err From ffaec6068c44a13182b6e2c9274298827d0c19c9 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Tue, 16 Jan 2024 15:00:32 -0800 Subject: [PATCH 013/101] Change to wrapped error when returned --- dependencyinstaller.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dependencyinstaller.go b/dependencyinstaller.go index 1d3036c7d..c8c3f23ac 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -123,7 +123,7 @@ func (ci *DependencyInstaller) processDependency(dependency config.Dependency) e func (ci *DependencyInstaller) fetchDependencies(networkName string, address flowsdk.Address, assignedName, contractName string) error { account, err := ci.Gateways[networkName].GetAccount(address) if err != nil { - return fmt.Errorf("failed to get account: %v", err) + return fmt.Errorf("failed to get account: %w", err) } if account == nil { return fmt.Errorf("account is nil for address: %s", address) @@ -140,18 +140,18 @@ func (ci *DependencyInstaller) fetchDependencies(networkName string, address flo program, err := project.NewProgram(contract, nil, "") if err != nil { - return fmt.Errorf("failed to parse program: %v", err) + return fmt.Errorf("failed to parse program: %w", err) } parsedContractName, err := program.Name() if err != nil { - return fmt.Errorf("failed to parse contract name: %v", err) + return fmt.Errorf("failed to parse contract name: %w", err) } if parsedContractName == contractName { if err := ci.handleFoundContract(networkName, address.String(), assignedName, parsedContractName, program); err != nil { - return fmt.Errorf("failed to handle found contract: %v", err) + return fmt.Errorf("failed to handle found contract: %w", err) } if program.HasAddressImports() { @@ -214,7 +214,7 @@ func (ci *DependencyInstaller) handleFoundContract(networkName, contractAddr, as if !contractFileExists(contractAddr, contractName) { if err := createContractFile(contractAddr, contractName, contractData); err != nil { - return fmt.Errorf("failed to create contract file: %v", err) + return fmt.Errorf("failed to create contract file: %w", err) } } From 4fe7d5d4ea03af5a31eee4819851ea7898cd99af Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Tue, 16 Jan 2024 16:02:26 -0800 Subject: [PATCH 014/101] Add message around dep installed --- dependencyinstaller.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dependencyinstaller.go b/dependencyinstaller.go index c8c3f23ac..71ea086b9 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -216,6 +216,8 @@ func (ci *DependencyInstaller) handleFoundContract(networkName, contractAddr, as if err := createContractFile(contractAddr, contractName, contractData); err != nil { return fmt.Errorf("failed to create contract file: %w", err) } + + ci.Logger.Info(fmt.Sprintf("Dependency Manager: %s from %s on %s installed", contractName, contractAddr, networkName)) } err := ci.updateState(networkName, contractAddr, assignedName, contractName, originalContractDataHash) From e26bcd32df8b5c26bb1ec0dc8f28194c1d23aa95 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Tue, 16 Jan 2024 16:07:11 -0800 Subject: [PATCH 015/101] Add message if added to flow.json --- dependencyinstaller.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dependencyinstaller.go b/dependencyinstaller.go index 71ea086b9..e659fa849 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -240,6 +240,8 @@ func (ci *DependencyInstaller) updateState(networkName, contractAddress, assigne Version: contractHash, } + isNewDep := ci.State.Dependencies().ByName(dep.Name) == nil + ci.State.Dependencies().AddOrUpdate(dep) ci.State.Contracts().AddDependencyAsContract(dep, networkName) err := ci.State.SaveDefault() @@ -247,5 +249,9 @@ func (ci *DependencyInstaller) updateState(networkName, contractAddress, assigne return err } + if isNewDep { + ci.Logger.Info(fmt.Sprintf("Dependency Manager: %s added to flow.json", dep.Name)) + } + return nil } From eca4fb07f64f5742f8669d3592fd3c1f8e0ef1bd Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Wed, 17 Jan 2024 11:53:43 -0800 Subject: [PATCH 016/101] Clean up name conditional --- dependencyinstaller.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/dependencyinstaller.go b/dependencyinstaller.go index e659fa849..6694a7dc7 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -91,12 +91,10 @@ func (ci *DependencyInstaller) add(depRemoteSource, customName string) error { return fmt.Errorf("error parsing remote source: %w", err) } - var name string + name := depContractName if customName != "" { name = customName - } else { - name = depContractName } dep := config.Dependency{ From 3aed1a10a30d1731d2699c906eebf74c83af334a Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Fri, 19 Jan 2024 09:49:00 -0800 Subject: [PATCH 017/101] Fix issue with hardcoded network --- dependencyinstaller.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencyinstaller.go b/dependencyinstaller.go index 6694a7dc7..d9fa1233b 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -158,7 +158,7 @@ func (ci *DependencyInstaller) fetchDependencies(networkName string, address flo wg.Add(1) go func(importAddress flowsdk.Address, contractName string) { defer wg.Done() - err := ci.fetchDependencies("testnet", importAddress, contractName, contractName) + err := ci.fetchDependencies(networkName, importAddress, contractName, contractName) if err != nil { errCh <- err } From 321d6e71fd57627d9dd870c1880d059d04dbb0f8 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Fri, 19 Jan 2024 14:48:32 -0800 Subject: [PATCH 018/101] Add test for install --- install_test.go | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 install_test.go diff --git a/install_test.go b/install_test.go new file mode 100644 index 000000000..8306b2610 --- /dev/null +++ b/install_test.go @@ -0,0 +1,46 @@ +package dependencymanager + +import ( + "github.com/onflow/flow-cli/flowkit/config" + "github.com/onflow/flow-cli/flowkit/output" + "github.com/onflow/flow-cli/flowkit/tests" + "github.com/onflow/flow-cli/internal/command" + "github.com/onflow/flow-cli/internal/util" + "github.com/onflow/flow-go-sdk" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "testing" +) + +func TestInstallDependencies(t *testing.T) { + logger := output.NewStdoutLogger(output.NoneLog) + srv, state, _ := util.TestMocks(t) + + dep := config.Dependency{ + Name: "Hello", + RemoteSource: config.RemoteSource{ + NetworkName: "emulator", + Address: flow.HexToAddress("0000000000000001"), + ContractName: "Hello", + }, + } + + state.Dependencies().AddOrUpdate(dep) + + t.Run("Success", func(t *testing.T) { + inArgs := []string{"0x1"} + + srv.GetAccount.Run(func(args mock.Arguments) { + addr := args.Get(1).(flow.Address) + assert.Equal(t, "0000000000000001", addr.String()) + srv.GetAccount.Return(tests.NewAccountWithContracts(inArgs[0], tests.ContractHelloString), nil) + }) + + _, err := install([]string{}, command.GlobalFlags{}, logger, srv.Mock, state) + assert.NoError(t, err, "Failed to install dependencies") + + fileContent, err := state.ReaderWriter().ReadFile("imports/0000000000000001/Hello") + assert.NoError(t, err, "Failed to read generated file") + assert.NotNil(t, fileContent) + }) +} From ff9470173250fa6160475e39c9d70f1d8ea1147c Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Fri, 19 Jan 2024 15:45:31 -0800 Subject: [PATCH 019/101] Add test for install --- dependencyinstaller.go | 28 +++++++++++++-- dependencyinstaller_test.go | 68 +++++++++++++++++++++++++++++++++++++ fileutils.go | 41 ---------------------- install_test.go | 46 ------------------------- 4 files changed, 94 insertions(+), 89 deletions(-) create mode 100644 dependencyinstaller_test.go delete mode 100644 fileutils.go delete mode 100644 install_test.go diff --git a/dependencyinstaller.go b/dependencyinstaller.go index d9fa1233b..79287ea9c 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -23,6 +23,7 @@ import ( "encoding/hex" "fmt" "os" + "path/filepath" "sync" "github.com/onflow/flow-cli/internal/util" @@ -180,6 +181,29 @@ func (ci *DependencyInstaller) fetchDependencies(networkName string, address flo return nil } +func (ci *DependencyInstaller) contractFileExists(address, contractName string) bool { + path := filepath.Join("imports", address, contractName) + + _, err := ci.State.ReaderWriter().Stat(path) + + return err == nil +} + +func (ci *DependencyInstaller) createContractFile(address, contractName, data string) error { + path := filepath.Join("imports", address, contractName) + dir := filepath.Dir(path) + + if err := ci.State.ReaderWriter().MkdirAll(dir, 0755); err != nil { + return fmt.Errorf("error creating directories: %w", err) + } + + if err := ci.State.ReaderWriter().WriteFile(path, []byte(data), 0644); err != nil { + return fmt.Errorf("error writing file: %w", err) + } + + return nil +} + func (ci *DependencyInstaller) handleFoundContract(networkName, contractAddr, assignedName, contractName string, program *project.Program) error { ci.Mutex.Lock() defer ci.Mutex.Unlock() @@ -210,8 +234,8 @@ func (ci *DependencyInstaller) handleFoundContract(networkName, contractAddr, as } } - if !contractFileExists(contractAddr, contractName) { - if err := createContractFile(contractAddr, contractName, contractData); err != nil { + if !ci.contractFileExists(contractAddr, contractName) { + if err := ci.createContractFile(contractAddr, contractName, contractData); err != nil { return fmt.Errorf("failed to create contract file: %w", err) } diff --git a/dependencyinstaller_test.go b/dependencyinstaller_test.go new file mode 100644 index 000000000..f4ff585d1 --- /dev/null +++ b/dependencyinstaller_test.go @@ -0,0 +1,68 @@ +package dependencymanager + +import ( + "fmt" + "github.com/onflow/flow-cli/flowkit/config" + "github.com/onflow/flow-cli/flowkit/gateway" + "github.com/onflow/flow-cli/flowkit/gateway/mocks" + "github.com/onflow/flow-cli/flowkit/output" + "github.com/onflow/flow-cli/flowkit/tests" + "github.com/onflow/flow-cli/internal/util" + "github.com/onflow/flow-go-sdk" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "testing" +) + +func TestDependencyInstallerInstall(t *testing.T) { + + logger := output.NewStdoutLogger(output.NoneLog) + _, state, _ := util.TestMocks(t) + + serviceAcc, _ := state.EmulatorServiceAccount() + serviceAddress := serviceAcc.Address + + dep := config.Dependency{ + Name: "Hello", + RemoteSource: config.RemoteSource{ + NetworkName: "emulator", + Address: serviceAddress, + ContractName: "Hello", + }, + } + + state.Dependencies().AddOrUpdate(dep) + + t.Run("Success", func(t *testing.T) { + gw := mocks.DefaultMockGateway() + + gw.GetAccount.Run(func(args mock.Arguments) { + addr := args.Get(0).(flow.Address) + assert.Equal(t, addr.String(), serviceAcc.Address.String()) + racc := tests.NewAccountWithAddress(addr.String()) + racc.Contracts = map[string][]byte{ + tests.ContractHelloString.Name: tests.ContractHelloString.Source, + } + + gw.GetAccount.Return(racc, nil) + }) + + di := &DependencyInstaller{ + Gateways: map[string]gateway.Gateway{ + config.EmulatorNetwork.Name: gw.Mock, + config.TestnetNetwork.Name: gw.Mock, + config.MainnetNetwork.Name: gw.Mock, + }, + Logger: logger, + State: state, + } + + err := di.install() + assert.NoError(t, err, "Failed to install dependencies") + + filePath := fmt.Sprintf("imports/%s/Hello", serviceAddress.String()) + fileContent, err := state.ReaderWriter().ReadFile(filePath) + assert.NoError(t, err, "Failed to read generated file") + assert.NotNil(t, fileContent) + }) +} diff --git a/fileutils.go b/fileutils.go deleted file mode 100644 index 485dc57ba..000000000 --- a/fileutils.go +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Flow CLI - * - * Copyright 2019 Dapper Labs, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dependencymanager - -import ( - "os" - "path/filepath" -) - -func contractFileExists(address, contractName string) bool { - path := filepath.Join("imports", address, contractName) - _, err := os.Stat(path) - return !os.IsNotExist(err) -} - -func createContractFile(address, contractName, data string) error { - path := filepath.Join("imports", address, contractName) - - dir := filepath.Dir(path) - if err := os.MkdirAll(dir, os.ModePerm); err != nil { - return err - } - - return os.WriteFile(path, []byte(data), 0644) -} diff --git a/install_test.go b/install_test.go deleted file mode 100644 index 8306b2610..000000000 --- a/install_test.go +++ /dev/null @@ -1,46 +0,0 @@ -package dependencymanager - -import ( - "github.com/onflow/flow-cli/flowkit/config" - "github.com/onflow/flow-cli/flowkit/output" - "github.com/onflow/flow-cli/flowkit/tests" - "github.com/onflow/flow-cli/internal/command" - "github.com/onflow/flow-cli/internal/util" - "github.com/onflow/flow-go-sdk" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "testing" -) - -func TestInstallDependencies(t *testing.T) { - logger := output.NewStdoutLogger(output.NoneLog) - srv, state, _ := util.TestMocks(t) - - dep := config.Dependency{ - Name: "Hello", - RemoteSource: config.RemoteSource{ - NetworkName: "emulator", - Address: flow.HexToAddress("0000000000000001"), - ContractName: "Hello", - }, - } - - state.Dependencies().AddOrUpdate(dep) - - t.Run("Success", func(t *testing.T) { - inArgs := []string{"0x1"} - - srv.GetAccount.Run(func(args mock.Arguments) { - addr := args.Get(1).(flow.Address) - assert.Equal(t, "0000000000000001", addr.String()) - srv.GetAccount.Return(tests.NewAccountWithContracts(inArgs[0], tests.ContractHelloString), nil) - }) - - _, err := install([]string{}, command.GlobalFlags{}, logger, srv.Mock, state) - assert.NoError(t, err, "Failed to install dependencies") - - fileContent, err := state.ReaderWriter().ReadFile("imports/0000000000000001/Hello") - assert.NoError(t, err, "Failed to read generated file") - assert.NotNil(t, fileContent) - }) -} From e2d655eae5e62fbbab4fa444ee7c8126781971a0 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Fri, 19 Jan 2024 15:47:39 -0800 Subject: [PATCH 020/101] Change ci to di --- dependencyinstaller.go | 66 +++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/dependencyinstaller.go b/dependencyinstaller.go index 79287ea9c..171797f3c 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -76,17 +76,17 @@ func NewDependencyInstaller(logger output.Logger, state *flowkit.State) *Depende } } -func (ci *DependencyInstaller) install() error { - for _, dependency := range *ci.State.Dependencies() { - if err := ci.processDependency(dependency); err != nil { - ci.Logger.Error(fmt.Sprintf("Error processing dependency: %v", err)) +func (di *DependencyInstaller) install() error { + for _, dependency := range *di.State.Dependencies() { + if err := di.processDependency(dependency); err != nil { + di.Logger.Error(fmt.Sprintf("Error processing dependency: %v", err)) return err } } return nil } -func (ci *DependencyInstaller) add(depRemoteSource, customName string) error { +func (di *DependencyInstaller) add(depRemoteSource, customName string) error { depNetwork, depAddress, depContractName, err := config.ParseRemoteSourceString(depRemoteSource) if err != nil { return fmt.Errorf("error parsing remote source: %w", err) @@ -107,20 +107,20 @@ func (ci *DependencyInstaller) add(depRemoteSource, customName string) error { }, } - if err := ci.processDependency(dep); err != nil { + if err := di.processDependency(dep); err != nil { return fmt.Errorf("error processing dependency: %w", err) } return nil } -func (ci *DependencyInstaller) processDependency(dependency config.Dependency) error { +func (di *DependencyInstaller) processDependency(dependency config.Dependency) error { depAddress := flowsdk.HexToAddress(dependency.RemoteSource.Address.String()) - return ci.fetchDependencies(dependency.RemoteSource.NetworkName, depAddress, dependency.Name, dependency.RemoteSource.ContractName) + return di.fetchDependencies(dependency.RemoteSource.NetworkName, depAddress, dependency.Name, dependency.RemoteSource.ContractName) } -func (ci *DependencyInstaller) fetchDependencies(networkName string, address flowsdk.Address, assignedName, contractName string) error { - account, err := ci.Gateways[networkName].GetAccount(address) +func (di *DependencyInstaller) fetchDependencies(networkName string, address flowsdk.Address, assignedName, contractName string) error { + account, err := di.Gateways[networkName].GetAccount(address) if err != nil { return fmt.Errorf("failed to get account: %w", err) } @@ -149,7 +149,7 @@ func (ci *DependencyInstaller) fetchDependencies(networkName string, address flo if parsedContractName == contractName { - if err := ci.handleFoundContract(networkName, address.String(), assignedName, parsedContractName, program); err != nil { + if err := di.handleFoundContract(networkName, address.String(), assignedName, parsedContractName, program); err != nil { return fmt.Errorf("failed to handle found contract: %w", err) } @@ -159,7 +159,7 @@ func (ci *DependencyInstaller) fetchDependencies(networkName string, address flo wg.Add(1) go func(importAddress flowsdk.Address, contractName string) { defer wg.Done() - err := ci.fetchDependencies(networkName, importAddress, contractName, contractName) + err := di.fetchDependencies(networkName, importAddress, contractName, contractName) if err != nil { errCh <- err } @@ -181,32 +181,32 @@ func (ci *DependencyInstaller) fetchDependencies(networkName string, address flo return nil } -func (ci *DependencyInstaller) contractFileExists(address, contractName string) bool { +func (di *DependencyInstaller) contractFileExists(address, contractName string) bool { path := filepath.Join("imports", address, contractName) - _, err := ci.State.ReaderWriter().Stat(path) + _, err := di.State.ReaderWriter().Stat(path) return err == nil } -func (ci *DependencyInstaller) createContractFile(address, contractName, data string) error { +func (di *DependencyInstaller) createContractFile(address, contractName, data string) error { path := filepath.Join("imports", address, contractName) dir := filepath.Dir(path) - if err := ci.State.ReaderWriter().MkdirAll(dir, 0755); err != nil { + if err := di.State.ReaderWriter().MkdirAll(dir, 0755); err != nil { return fmt.Errorf("error creating directories: %w", err) } - if err := ci.State.ReaderWriter().WriteFile(path, []byte(data), 0644); err != nil { + if err := di.State.ReaderWriter().WriteFile(path, []byte(data), 0644); err != nil { return fmt.Errorf("error writing file: %w", err) } return nil } -func (ci *DependencyInstaller) handleFoundContract(networkName, contractAddr, assignedName, contractName string, program *project.Program) error { - ci.Mutex.Lock() - defer ci.Mutex.Unlock() +func (di *DependencyInstaller) handleFoundContract(networkName, contractAddr, assignedName, contractName string, program *project.Program) error { + di.Mutex.Lock() + defer di.Mutex.Unlock() hash := sha256.New() hash.Write(program.DevelopmentCode()) @@ -215,11 +215,11 @@ func (ci *DependencyInstaller) handleFoundContract(networkName, contractAddr, as program.ConvertImports() contractData := string(program.DevelopmentCode()) - dependency := ci.State.Dependencies().ByName(assignedName) + dependency := di.State.Dependencies().ByName(assignedName) // If a dependency by this name already exists and its remote source network or address does not match, then give option to stop or continue if dependency != nil && (dependency.RemoteSource.NetworkName != networkName || dependency.RemoteSource.Address.String() != contractAddr) { - ci.Logger.Info(fmt.Sprintf("🚫 A dependency named %s already exists with a different remote source. Please fix the conflict and retry.", assignedName)) + di.Logger.Info(fmt.Sprintf("🚫 A dependency named %s already exists with a different remote source. Please fix the conflict and retry.", assignedName)) os.Exit(0) return nil } @@ -234,24 +234,24 @@ func (ci *DependencyInstaller) handleFoundContract(networkName, contractAddr, as } } - if !ci.contractFileExists(contractAddr, contractName) { - if err := ci.createContractFile(contractAddr, contractName, contractData); err != nil { + if !di.contractFileExists(contractAddr, contractName) { + if err := di.createContractFile(contractAddr, contractName, contractData); err != nil { return fmt.Errorf("failed to create contract file: %w", err) } - ci.Logger.Info(fmt.Sprintf("Dependency Manager: %s from %s on %s installed", contractName, contractAddr, networkName)) + di.Logger.Info(fmt.Sprintf("Dependency Manager: %s from %s on %s installed", contractName, contractAddr, networkName)) } - err := ci.updateState(networkName, contractAddr, assignedName, contractName, originalContractDataHash) + err := di.updateState(networkName, contractAddr, assignedName, contractName, originalContractDataHash) if err != nil { - ci.Logger.Error(fmt.Sprintf("Error updating state: %v", err)) + di.Logger.Error(fmt.Sprintf("Error updating state: %v", err)) return err } return nil } -func (ci *DependencyInstaller) updateState(networkName, contractAddress, assignedName, contractName, contractHash string) error { +func (di *DependencyInstaller) updateState(networkName, contractAddress, assignedName, contractName, contractHash string) error { dep := config.Dependency{ Name: assignedName, RemoteSource: config.RemoteSource{ @@ -262,17 +262,17 @@ func (ci *DependencyInstaller) updateState(networkName, contractAddress, assigne Version: contractHash, } - isNewDep := ci.State.Dependencies().ByName(dep.Name) == nil + isNewDep := di.State.Dependencies().ByName(dep.Name) == nil - ci.State.Dependencies().AddOrUpdate(dep) - ci.State.Contracts().AddDependencyAsContract(dep, networkName) - err := ci.State.SaveDefault() + di.State.Dependencies().AddOrUpdate(dep) + di.State.Contracts().AddDependencyAsContract(dep, networkName) + err := di.State.SaveDefault() if err != nil { return err } if isNewDep { - ci.Logger.Info(fmt.Sprintf("Dependency Manager: %s added to flow.json", dep.Name)) + di.Logger.Info(fmt.Sprintf("Dependency Manager: %s added to flow.json", dep.Name)) } return nil From db9191a4bfe67629c32e8a97a7d3e7fe6eb509e0 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Fri, 19 Jan 2024 15:50:39 -0800 Subject: [PATCH 021/101] Run lintfix --- dependencyinstaller_test.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/dependencyinstaller_test.go b/dependencyinstaller_test.go index f4ff585d1..0db7d641b 100644 --- a/dependencyinstaller_test.go +++ b/dependencyinstaller_test.go @@ -2,16 +2,18 @@ package dependencymanager import ( "fmt" + "testing" + + "github.com/onflow/flow-go-sdk" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/onflow/flow-cli/flowkit/config" "github.com/onflow/flow-cli/flowkit/gateway" "github.com/onflow/flow-cli/flowkit/gateway/mocks" "github.com/onflow/flow-cli/flowkit/output" "github.com/onflow/flow-cli/flowkit/tests" "github.com/onflow/flow-cli/internal/util" - "github.com/onflow/flow-go-sdk" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "testing" ) func TestDependencyInstallerInstall(t *testing.T) { From 5231143d0ef051e1e7660521ccc70ae228266cd6 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Fri, 19 Jan 2024 15:54:24 -0800 Subject: [PATCH 022/101] Add license header --- dependencyinstaller_test.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/dependencyinstaller_test.go b/dependencyinstaller_test.go index 0db7d641b..2536eef7e 100644 --- a/dependencyinstaller_test.go +++ b/dependencyinstaller_test.go @@ -1,3 +1,21 @@ +/* + * Flow CLI + * + * Copyright 2019 Dapper Labs, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package dependencymanager import ( From c341a30e7d7b0787a0997f2ad636863a1c1091ac Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Mon, 22 Jan 2024 11:16:40 -0800 Subject: [PATCH 023/101] Make add and install public --- add.go | 2 +- dependencyinstaller.go | 4 ++-- dependencyinstaller_test.go | 2 +- install.go | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/add.go b/add.go index 7cb4399d4..614caeb64 100644 --- a/add.go +++ b/add.go @@ -56,7 +56,7 @@ func add( dep := args[0] installer := NewDependencyInstaller(logger, state) - if err := installer.add(dep, addFlags.name); err != nil { + if err := installer.Add(dep, addFlags.name); err != nil { logger.Error(fmt.Sprintf("Error: %v", err)) return nil, err } diff --git a/dependencyinstaller.go b/dependencyinstaller.go index 171797f3c..a122bd21b 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -76,7 +76,7 @@ func NewDependencyInstaller(logger output.Logger, state *flowkit.State) *Depende } } -func (di *DependencyInstaller) install() error { +func (di *DependencyInstaller) Install() error { for _, dependency := range *di.State.Dependencies() { if err := di.processDependency(dependency); err != nil { di.Logger.Error(fmt.Sprintf("Error processing dependency: %v", err)) @@ -86,7 +86,7 @@ func (di *DependencyInstaller) install() error { return nil } -func (di *DependencyInstaller) add(depRemoteSource, customName string) error { +func (di *DependencyInstaller) Add(depRemoteSource, customName string) error { depNetwork, depAddress, depContractName, err := config.ParseRemoteSourceString(depRemoteSource) if err != nil { return fmt.Errorf("error parsing remote source: %w", err) diff --git a/dependencyinstaller_test.go b/dependencyinstaller_test.go index 2536eef7e..7bede1392 100644 --- a/dependencyinstaller_test.go +++ b/dependencyinstaller_test.go @@ -77,7 +77,7 @@ func TestDependencyInstallerInstall(t *testing.T) { State: state, } - err := di.install() + err := di.Install() assert.NoError(t, err, "Failed to install dependencies") filePath := fmt.Sprintf("imports/%s/Hello", serviceAddress.String()) diff --git a/install.go b/install.go index 751a8a087..049a348b2 100644 --- a/install.go +++ b/install.go @@ -51,7 +51,7 @@ func install( logger.Info("🔄 Installing dependencies from flow.json...") installer := NewDependencyInstaller(logger, state) - if err := installer.install(); err != nil { + if err := installer.Install(); err != nil { logger.Error(fmt.Sprintf("Error: %v", err)) return nil, err } From 1471877c2c140453288885dced1d351a4a1e3cb8 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Mon, 22 Jan 2024 11:24:05 -0800 Subject: [PATCH 024/101] Fix typo --- dependencyinstaller_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dependencyinstaller_test.go b/dependencyinstaller_test.go index 7bede1392..7a0ce0d3b 100644 --- a/dependencyinstaller_test.go +++ b/dependencyinstaller_test.go @@ -59,12 +59,12 @@ func TestDependencyInstallerInstall(t *testing.T) { gw.GetAccount.Run(func(args mock.Arguments) { addr := args.Get(0).(flow.Address) assert.Equal(t, addr.String(), serviceAcc.Address.String()) - racc := tests.NewAccountWithAddress(addr.String()) - racc.Contracts = map[string][]byte{ + acc := tests.NewAccountWithAddress(addr.String()) + acc.Contracts = map[string][]byte{ tests.ContractHelloString.Name: tests.ContractHelloString.Source, } - gw.GetAccount.Return(racc, nil) + gw.GetAccount.Return(acc, nil) }) di := &DependencyInstaller{ From c74a725cdaa51e3e794f8403b7952f53397af99f Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Mon, 22 Jan 2024 11:29:08 -0800 Subject: [PATCH 025/101] Add test for DependencyInstaller.Add --- dependencyinstaller_test.go | 45 ++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/dependencyinstaller_test.go b/dependencyinstaller_test.go index 7a0ce0d3b..8f5d92f17 100644 --- a/dependencyinstaller_test.go +++ b/dependencyinstaller_test.go @@ -80,7 +80,50 @@ func TestDependencyInstallerInstall(t *testing.T) { err := di.Install() assert.NoError(t, err, "Failed to install dependencies") - filePath := fmt.Sprintf("imports/%s/Hello", serviceAddress.String()) + filePath := fmt.Sprintf("imports/%s/%s", serviceAddress.String(), tests.ContractHelloString.Name) + fileContent, err := state.ReaderWriter().ReadFile(filePath) + assert.NoError(t, err, "Failed to read generated file") + assert.NotNil(t, fileContent) + }) +} + +func TestDependencyInstallerAdd(t *testing.T) { + + logger := output.NewStdoutLogger(output.NoneLog) + _, state, _ := util.TestMocks(t) + + serviceAcc, _ := state.EmulatorServiceAccount() + serviceAddress := serviceAcc.Address + + t.Run("Success", func(t *testing.T) { + gw := mocks.DefaultMockGateway() + + gw.GetAccount.Run(func(args mock.Arguments) { + addr := args.Get(0).(flow.Address) + assert.Equal(t, addr.String(), serviceAcc.Address.String()) + acc := tests.NewAccountWithAddress(addr.String()) + acc.Contracts = map[string][]byte{ + tests.ContractHelloString.Name: tests.ContractHelloString.Source, + } + + gw.GetAccount.Return(acc, nil) + }) + + di := &DependencyInstaller{ + Gateways: map[string]gateway.Gateway{ + config.EmulatorNetwork.Name: gw.Mock, + config.TestnetNetwork.Name: gw.Mock, + config.MainnetNetwork.Name: gw.Mock, + }, + Logger: logger, + State: state, + } + + remoteSourceStr := fmt.Sprintf("emulator://%s.%s", serviceAddress.String(), tests.ContractHelloString.Name) + err := di.Add(remoteSourceStr, "") + assert.NoError(t, err, "Failed to install dependencies") + + filePath := fmt.Sprintf("imports/%s/%s", serviceAddress.String(), tests.ContractHelloString.Name) fileContent, err := state.ReaderWriter().ReadFile(filePath) assert.NoError(t, err, "Failed to read generated file") assert.NotNil(t, fileContent) From cedb9001784b5b913cd90fb3831a4784beb3ffbe Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Mon, 22 Jan 2024 11:41:02 -0800 Subject: [PATCH 026/101] Create max number of concurrent routines --- dependencyinstaller.go | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/dependencyinstaller.go b/dependencyinstaller.go index a122bd21b..1ed41f4db 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -135,8 +135,11 @@ func (di *DependencyInstaller) fetchDependencies(networkName string, address flo var wg sync.WaitGroup errCh := make(chan error, len(account.Contracts)) - for _, contract := range account.Contracts { + // Create a max number of goroutines so that we don't rate limit the access node + maxGoroutines := 5 + semaphore := make(chan struct{}, maxGoroutines) + for _, contract := range account.Contracts { program, err := project.NewProgram(contract, nil, "") if err != nil { return fmt.Errorf("failed to parse program: %w", err) @@ -148,7 +151,6 @@ func (di *DependencyInstaller) fetchDependencies(networkName string, address flo } if parsedContractName == contractName { - if err := di.handleFoundContract(networkName, address.String(), assignedName, parsedContractName, program); err != nil { return fmt.Errorf("failed to handle found contract: %w", err) } @@ -158,7 +160,11 @@ func (di *DependencyInstaller) fetchDependencies(networkName string, address flo for _, imp := range imports { wg.Add(1) go func(importAddress flowsdk.Address, contractName string) { - defer wg.Done() + semaphore <- struct{}{} + defer func() { + <-semaphore + wg.Done() + }() err := di.fetchDependencies(networkName, importAddress, contractName, contractName) if err != nil { errCh <- err @@ -171,6 +177,7 @@ func (di *DependencyInstaller) fetchDependencies(networkName string, address flo wg.Wait() close(errCh) + close(semaphore) for err := range errCh { if err != nil { From 26e04f06668dae016711e655878bab792c7379f6 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Mon, 22 Jan 2024 14:01:35 -0800 Subject: [PATCH 027/101] Move mutex to only file system --- dependencyinstaller.go | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/dependencyinstaller.go b/dependencyinstaller.go index 1ed41f4db..856d37503 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -211,10 +211,22 @@ func (di *DependencyInstaller) createContractFile(address, contractName, data st return nil } -func (di *DependencyInstaller) handleFoundContract(networkName, contractAddr, assignedName, contractName string, program *project.Program) error { +func (di *DependencyInstaller) handleFileSystem(contractAddr, contractName, contractData, networkName string) error { di.Mutex.Lock() defer di.Mutex.Unlock() + if !di.contractFileExists(contractAddr, contractName) { + if err := di.createContractFile(contractAddr, contractName, contractData); err != nil { + return fmt.Errorf("failed to create contract file: %w", err) + } + + di.Logger.Info(fmt.Sprintf("Dependency Manager: %s from %s on %s installed", contractName, contractAddr, networkName)) + } + + return nil +} + +func (di *DependencyInstaller) handleFoundContract(networkName, contractAddr, assignedName, contractName string, program *project.Program) error { hash := sha256.New() hash.Write(program.DevelopmentCode()) originalContractDataHash := hex.EncodeToString(hash.Sum(nil)) @@ -241,15 +253,12 @@ func (di *DependencyInstaller) handleFoundContract(networkName, contractAddr, as } } - if !di.contractFileExists(contractAddr, contractName) { - if err := di.createContractFile(contractAddr, contractName, contractData); err != nil { - return fmt.Errorf("failed to create contract file: %w", err) - } - - di.Logger.Info(fmt.Sprintf("Dependency Manager: %s from %s on %s installed", contractName, contractAddr, networkName)) + err := di.handleFileSystem(contractAddr, contractName, contractData, networkName) + if err != nil { + return fmt.Errorf("error handling file system: %w", err) } - err := di.updateState(networkName, contractAddr, assignedName, contractName, originalContractDataHash) + err = di.updateState(networkName, contractAddr, assignedName, contractName, originalContractDataHash) if err != nil { di.Logger.Error(fmt.Sprintf("Error updating state: %v", err)) return err From d654ae1c3a0627311ec640ff987dc50b3cf1a280 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Mon, 22 Jan 2024 14:20:40 -0800 Subject: [PATCH 028/101] Add comments to exposed methods --- dependencyinstaller.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dependencyinstaller.go b/dependencyinstaller.go index 856d37503..b4b066574 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -47,6 +47,7 @@ type DependencyInstaller struct { Mutex sync.Mutex } +// NewDependencyInstaller creates a new instance of DependencyInstaller func NewDependencyInstaller(logger output.Logger, state *flowkit.State) *DependencyInstaller { emulatorGateway, err := gateway.NewGrpcGateway(config.EmulatorNetwork) if err != nil { @@ -76,6 +77,7 @@ func NewDependencyInstaller(logger output.Logger, state *flowkit.State) *Depende } } +// Install processes all the dependencies in the state and installs them and any dependencies they have func (di *DependencyInstaller) Install() error { for _, dependency := range *di.State.Dependencies() { if err := di.processDependency(dependency); err != nil { @@ -86,6 +88,7 @@ func (di *DependencyInstaller) Install() error { return nil } +// Add processes a single dependency and installs it and any dependencies it has, as well as adding it to the state func (di *DependencyInstaller) Add(depRemoteSource, customName string) error { depNetwork, depAddress, depContractName, err := config.ParseRemoteSourceString(depRemoteSource) if err != nil { From 4cbbffec5e05eadc6eb471f0562294e8f6f148b0 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Wed, 24 Jan 2024 14:14:53 -0800 Subject: [PATCH 029/101] Add examples --- add.go | 7 ++++--- install.go | 5 +++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/add.go b/add.go index 614caeb64..ba5446119 100644 --- a/add.go +++ b/add.go @@ -36,9 +36,10 @@ var addFlags = addFlagsCollection{} var addCommand = &command.Command{ Cmd: &cobra.Command{ - Use: "add", - Short: "Add a single contract and its dependencies.", - Args: cobra.ExactArgs(1), + Use: "add ", + Short: "Add a single contract and its dependencies.", + Example: "flow dependencies add testnet://0afe396ebc8eee65.FlowToken", + Args: cobra.ExactArgs(1), }, Flags: &addFlags, RunS: add, diff --git a/install.go b/install.go index 049a348b2..13e8ce29e 100644 --- a/install.go +++ b/install.go @@ -34,8 +34,9 @@ var installFlags = installFlagsCollection{} var installCommand = &command.Command{ Cmd: &cobra.Command{ - Use: "install", - Short: "Install contract and dependencies.", + Use: "install", + Short: "Install contract and dependencies.", + Example: "flow dependencies install", }, Flags: &installFlags, RunS: install, From ed31711124f4425e5c536ee394209bb3b96c3c11 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Wed, 24 Jan 2024 14:34:08 -0800 Subject: [PATCH 030/101] Add .cdc file extension --- dependencyinstaller.go | 6 ++++-- dependencyinstaller_test.go | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/dependencyinstaller.go b/dependencyinstaller.go index b4b066574..05cb4fb95 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -192,7 +192,8 @@ func (di *DependencyInstaller) fetchDependencies(networkName string, address flo } func (di *DependencyInstaller) contractFileExists(address, contractName string) bool { - path := filepath.Join("imports", address, contractName) + fileName := fmt.Sprintf("%s.cdc", contractName) + path := filepath.Join("imports", address, fileName) _, err := di.State.ReaderWriter().Stat(path) @@ -200,7 +201,8 @@ func (di *DependencyInstaller) contractFileExists(address, contractName string) } func (di *DependencyInstaller) createContractFile(address, contractName, data string) error { - path := filepath.Join("imports", address, contractName) + fileName := fmt.Sprintf("%s.cdc", contractName) + path := filepath.Join("imports", address, fileName) dir := filepath.Dir(path) if err := di.State.ReaderWriter().MkdirAll(dir, 0755); err != nil { diff --git a/dependencyinstaller_test.go b/dependencyinstaller_test.go index 8f5d92f17..5e44609f3 100644 --- a/dependencyinstaller_test.go +++ b/dependencyinstaller_test.go @@ -80,7 +80,7 @@ func TestDependencyInstallerInstall(t *testing.T) { err := di.Install() assert.NoError(t, err, "Failed to install dependencies") - filePath := fmt.Sprintf("imports/%s/%s", serviceAddress.String(), tests.ContractHelloString.Name) + filePath := fmt.Sprintf("imports/%s/%s.cdc", serviceAddress.String(), tests.ContractHelloString.Name) fileContent, err := state.ReaderWriter().ReadFile(filePath) assert.NoError(t, err, "Failed to read generated file") assert.NotNil(t, fileContent) @@ -123,7 +123,7 @@ func TestDependencyInstallerAdd(t *testing.T) { err := di.Add(remoteSourceStr, "") assert.NoError(t, err, "Failed to install dependencies") - filePath := fmt.Sprintf("imports/%s/%s", serviceAddress.String(), tests.ContractHelloString.Name) + filePath := fmt.Sprintf("imports/%s/%s.cdc", serviceAddress.String(), tests.ContractHelloString.Name) fileContent, err := state.ReaderWriter().ReadFile(filePath) assert.NoError(t, err, "Failed to read generated file") assert.NotNil(t, fileContent) From 2d94810d7a0822185f3e5268a711fc7965c8264e Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Wed, 24 Jan 2024 14:46:08 -0800 Subject: [PATCH 031/101] Rename variable --- dependencyinstaller.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dependencyinstaller.go b/dependencyinstaller.go index 05cb4fb95..f37c555ac 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -233,11 +233,11 @@ func (di *DependencyInstaller) handleFileSystem(contractAddr, contractName, cont func (di *DependencyInstaller) handleFoundContract(networkName, contractAddr, assignedName, contractName string, program *project.Program) error { hash := sha256.New() - hash.Write(program.DevelopmentCode()) + hash.Write(program.CodeWithUnprocessedImports()) originalContractDataHash := hex.EncodeToString(hash.Sum(nil)) program.ConvertImports() - contractData := string(program.DevelopmentCode()) + contractData := string(program.CodeWithUnprocessedImports()) dependency := di.State.Dependencies().ByName(assignedName) From ebf517048054313d10808e7192efad4ae754a9a7 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Wed, 24 Jan 2024 16:36:16 -0800 Subject: [PATCH 032/101] Error if NewDependencyInstaller errors --- add.go | 7 ++++++- dependencyinstaller.go | 10 +++++----- install.go | 7 ++++++- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/add.go b/add.go index ba5446119..2cf9cd1e5 100644 --- a/add.go +++ b/add.go @@ -56,7 +56,12 @@ func add( dep := args[0] - installer := NewDependencyInstaller(logger, state) + installer, err := NewDependencyInstaller(logger, state) + if err != nil { + logger.Error(fmt.Sprintf("Error: %v", err)) + return nil, err + } + if err := installer.Add(dep, addFlags.name); err != nil { logger.Error(fmt.Sprintf("Error: %v", err)) return nil, err diff --git a/dependencyinstaller.go b/dependencyinstaller.go index f37c555ac..987cd986c 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -48,20 +48,20 @@ type DependencyInstaller struct { } // NewDependencyInstaller creates a new instance of DependencyInstaller -func NewDependencyInstaller(logger output.Logger, state *flowkit.State) *DependencyInstaller { +func NewDependencyInstaller(logger output.Logger, state *flowkit.State) (*DependencyInstaller, error) { emulatorGateway, err := gateway.NewGrpcGateway(config.EmulatorNetwork) if err != nil { - logger.Error(fmt.Sprintf("Error creating emulator gateway: %v", err)) + return nil, fmt.Errorf("error creating emulator gateway: %v", err) } testnetGateway, err := gateway.NewGrpcGateway(config.TestnetNetwork) if err != nil { - logger.Error(fmt.Sprintf("Error creating testnet gateway: %v", err)) + return nil, fmt.Errorf("error creating testnet gateway: %v", err) } mainnetGateway, err := gateway.NewGrpcGateway(config.MainnetNetwork) if err != nil { - logger.Error(fmt.Sprintf("Error creating mainnet gateway: %v", err)) + return nil, fmt.Errorf("error creating mainnet gateway: %v", err) } gateways := map[string]gateway.Gateway{ @@ -74,7 +74,7 @@ func NewDependencyInstaller(logger output.Logger, state *flowkit.State) *Depende Gateways: gateways, Logger: logger, State: state, - } + }, nil } // Install processes all the dependencies in the state and installs them and any dependencies they have diff --git a/install.go b/install.go index 13e8ce29e..2e3e8fb01 100644 --- a/install.go +++ b/install.go @@ -51,7 +51,12 @@ func install( ) (result command.Result, err error) { logger.Info("🔄 Installing dependencies from flow.json...") - installer := NewDependencyInstaller(logger, state) + installer, err := NewDependencyInstaller(logger, state) + if err != nil { + logger.Error(fmt.Sprintf("Error: %v", err)) + return nil, err + } + if err := installer.Install(); err != nil { logger.Error(fmt.Sprintf("Error: %v", err)) return nil, err From 90db76a461b44a5a3c8a383b705b5e5a6f7a01e0 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Wed, 24 Jan 2024 16:46:22 -0800 Subject: [PATCH 033/101] Error if not found --- add.go | 2 +- dependencyinstaller.go | 9 +++++++++ install.go | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/add.go b/add.go index 2cf9cd1e5..fb4d58c17 100644 --- a/add.go +++ b/add.go @@ -67,7 +67,7 @@ func add( return nil, err } - logger.Info("✅ Dependencies installed. Check your flow.json") + logger.Info("✅ Dependencies installation complete. Check your flow.json") return nil, nil } diff --git a/dependencyinstaller.go b/dependencyinstaller.go index 987cd986c..d190c9fee 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -142,6 +142,8 @@ func (di *DependencyInstaller) fetchDependencies(networkName string, address flo maxGoroutines := 5 semaphore := make(chan struct{}, maxGoroutines) + found := false + for _, contract := range account.Contracts { program, err := project.NewProgram(contract, nil, "") if err != nil { @@ -154,6 +156,8 @@ func (di *DependencyInstaller) fetchDependencies(networkName string, address flo } if parsedContractName == contractName { + found = true + if err := di.handleFoundContract(networkName, address.String(), assignedName, parsedContractName, program); err != nil { return fmt.Errorf("failed to handle found contract: %w", err) } @@ -176,6 +180,11 @@ func (di *DependencyInstaller) fetchDependencies(networkName string, address flo } } } + + if !found { + errMsg := fmt.Sprintf("contract %s not found for account %s on network %s", contractName, address, networkName) + di.Logger.Error(errMsg) + } } wg.Wait() diff --git a/install.go b/install.go index 2e3e8fb01..f21ec0194 100644 --- a/install.go +++ b/install.go @@ -62,7 +62,7 @@ func install( return nil, err } - logger.Info("✅ Dependencies installed. Check your flow.json") + logger.Info("✅ Dependencies installation complete. Check your flow.json") return nil, nil } From ee95c4859ed22b37318caf1138d3cd4dd4dcd5d5 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Thu, 25 Jan 2024 09:13:56 -0800 Subject: [PATCH 034/101] Fix found check --- dependencyinstaller.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dependencyinstaller.go b/dependencyinstaller.go index d190c9fee..dbb1133c4 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -180,11 +180,11 @@ func (di *DependencyInstaller) fetchDependencies(networkName string, address flo } } } + } - if !found { - errMsg := fmt.Sprintf("contract %s not found for account %s on network %s", contractName, address, networkName) - di.Logger.Error(errMsg) - } + if !found { + errMsg := fmt.Sprintf("contract %s not found for account %s on network %s", contractName, address, networkName) + di.Logger.Error(errMsg) } wg.Wait() From 4fd9e572096c9102b467107f7371091bab072735 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Thu, 25 Jan 2024 15:51:21 -0800 Subject: [PATCH 035/101] Change remoteSource to source --- dependencyinstaller.go | 16 ++++++++-------- dependencyinstaller_test.go | 6 +++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/dependencyinstaller.go b/dependencyinstaller.go index dbb1133c4..7ca177a40 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -89,10 +89,10 @@ func (di *DependencyInstaller) Install() error { } // Add processes a single dependency and installs it and any dependencies it has, as well as adding it to the state -func (di *DependencyInstaller) Add(depRemoteSource, customName string) error { - depNetwork, depAddress, depContractName, err := config.ParseRemoteSourceString(depRemoteSource) +func (di *DependencyInstaller) Add(depSource, customName string) error { + depNetwork, depAddress, depContractName, err := config.ParseSourceString(depSource) if err != nil { - return fmt.Errorf("error parsing remote source: %w", err) + return fmt.Errorf("error parsing source: %w", err) } name := depContractName @@ -103,7 +103,7 @@ func (di *DependencyInstaller) Add(depRemoteSource, customName string) error { dep := config.Dependency{ Name: name, - RemoteSource: config.RemoteSource{ + Source: config.Source{ NetworkName: depNetwork, Address: flowsdk.HexToAddress(depAddress), ContractName: depContractName, @@ -118,8 +118,8 @@ func (di *DependencyInstaller) Add(depRemoteSource, customName string) error { } func (di *DependencyInstaller) processDependency(dependency config.Dependency) error { - depAddress := flowsdk.HexToAddress(dependency.RemoteSource.Address.String()) - return di.fetchDependencies(dependency.RemoteSource.NetworkName, depAddress, dependency.Name, dependency.RemoteSource.ContractName) + depAddress := flowsdk.HexToAddress(dependency.Source.Address.String()) + return di.fetchDependencies(dependency.Source.NetworkName, depAddress, dependency.Name, dependency.Source.ContractName) } func (di *DependencyInstaller) fetchDependencies(networkName string, address flowsdk.Address, assignedName, contractName string) error { @@ -251,7 +251,7 @@ func (di *DependencyInstaller) handleFoundContract(networkName, contractAddr, as dependency := di.State.Dependencies().ByName(assignedName) // If a dependency by this name already exists and its remote source network or address does not match, then give option to stop or continue - if dependency != nil && (dependency.RemoteSource.NetworkName != networkName || dependency.RemoteSource.Address.String() != contractAddr) { + if dependency != nil && (dependency.Source.NetworkName != networkName || dependency.Source.Address.String() != contractAddr) { di.Logger.Info(fmt.Sprintf("🚫 A dependency named %s already exists with a different remote source. Please fix the conflict and retry.", assignedName)) os.Exit(0) return nil @@ -284,7 +284,7 @@ func (di *DependencyInstaller) handleFoundContract(networkName, contractAddr, as func (di *DependencyInstaller) updateState(networkName, contractAddress, assignedName, contractName, contractHash string) error { dep := config.Dependency{ Name: assignedName, - RemoteSource: config.RemoteSource{ + Source: config.Source{ NetworkName: networkName, Address: flowsdk.HexToAddress(contractAddress), ContractName: contractName, diff --git a/dependencyinstaller_test.go b/dependencyinstaller_test.go index 5e44609f3..9a7e1ac59 100644 --- a/dependencyinstaller_test.go +++ b/dependencyinstaller_test.go @@ -44,7 +44,7 @@ func TestDependencyInstallerInstall(t *testing.T) { dep := config.Dependency{ Name: "Hello", - RemoteSource: config.RemoteSource{ + Source: config.Source{ NetworkName: "emulator", Address: serviceAddress, ContractName: "Hello", @@ -119,8 +119,8 @@ func TestDependencyInstallerAdd(t *testing.T) { State: state, } - remoteSourceStr := fmt.Sprintf("emulator://%s.%s", serviceAddress.String(), tests.ContractHelloString.Name) - err := di.Add(remoteSourceStr, "") + sourceStr := fmt.Sprintf("emulator://%s.%s", serviceAddress.String(), tests.ContractHelloString.Name) + err := di.Add(sourceStr, "") assert.NoError(t, err, "Failed to install dependencies") filePath := fmt.Sprintf("imports/%s/%s.cdc", serviceAddress.String(), tests.ContractHelloString.Name) From be376fc19bfb9d3acffd6175717aa61c62756e2f Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Thu, 25 Jan 2024 15:55:14 -0800 Subject: [PATCH 036/101] Change version to hash --- dependencyinstaller.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dependencyinstaller.go b/dependencyinstaller.go index 7ca177a40..aac94f39f 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -260,7 +260,7 @@ func (di *DependencyInstaller) handleFoundContract(networkName, contractAddr, as // Check if remote source version is different from local version // If it is, ask if they want to update // If no hash, ignore - if dependency != nil && dependency.Version != "" && dependency.Version != originalContractDataHash { + if dependency != nil && dependency.Hash != "" && dependency.Hash != originalContractDataHash { msg := fmt.Sprintf("The latest version of %s is different from the one you have locally. Do you want to update it?", contractName) if !util.GenericBoolPrompt(msg) { return nil @@ -289,7 +289,7 @@ func (di *DependencyInstaller) updateState(networkName, contractAddress, assigne Address: flowsdk.HexToAddress(contractAddress), ContractName: contractName, }, - Version: contractHash, + Hash: contractHash, } isNewDep := di.State.Dependencies().ByName(dep.Name) == nil From f738d40109dd3476770974da15744dd0aa90384b Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Thu, 25 Jan 2024 16:11:51 -0800 Subject: [PATCH 037/101] Change import naming. Don't break flowkit --- dependencyinstaller.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencyinstaller.go b/dependencyinstaller.go index aac94f39f..0be79d74b 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -245,7 +245,7 @@ func (di *DependencyInstaller) handleFoundContract(networkName, contractAddr, as hash.Write(program.CodeWithUnprocessedImports()) originalContractDataHash := hex.EncodeToString(hash.Sum(nil)) - program.ConvertImports() + program.ConvertAddressImports() contractData := string(program.CodeWithUnprocessedImports()) dependency := di.State.Dependencies().ByName(assignedName) From 8ab8c74df33b0caf86a83a053093979bcbabc77e Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Thu, 25 Jan 2024 16:14:09 -0800 Subject: [PATCH 038/101] change naming --- add.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/add.go b/add.go index fb4d58c17..b1866e467 100644 --- a/add.go +++ b/add.go @@ -36,7 +36,7 @@ var addFlags = addFlagsCollection{} var addCommand = &command.Command{ Cmd: &cobra.Command{ - Use: "add ", + Use: "add ", Short: "Add a single contract and its dependencies.", Example: "flow dependencies add testnet://0afe396ebc8eee65.FlowToken", Args: cobra.ExactArgs(1), From 509fd5946ceaa42138895449b14a49b4c04cba18 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Thu, 25 Jan 2024 17:01:26 -0800 Subject: [PATCH 039/101] Add log for deployments --- add.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/add.go b/add.go index b1866e467..3ff026d17 100644 --- a/add.go +++ b/add.go @@ -68,6 +68,8 @@ func add( } logger.Info("✅ Dependencies installation complete. Check your flow.json") + logger.Info("Make sure you add any dependencies you need to your 'deployments' section. You can do this with 'flow add config deployment'") + logger.Info("Note: core contracts do not need to be added to deployments. See this url for reference: https://github.com/onflow/flow-core-contracts") return nil, nil } From 9f5b3b4dd483ab6b909e6b61e3137e3944b76ab0 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Thu, 25 Jan 2024 17:12:34 -0800 Subject: [PATCH 040/101] Fix grammar --- add.go | 6 +++--- install.go | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/add.go b/add.go index 3ff026d17..b972e99a1 100644 --- a/add.go +++ b/add.go @@ -67,9 +67,9 @@ func add( return nil, err } - logger.Info("✅ Dependencies installation complete. Check your flow.json") - logger.Info("Make sure you add any dependencies you need to your 'deployments' section. You can do this with 'flow add config deployment'") - logger.Info("Note: core contracts do not need to be added to deployments. See this url for reference: https://github.com/onflow/flow-core-contracts") + logger.Info("✅ Dependency installation complete. Check your flow.json") + logger.Info("Ensure you add any required dependencies to your 'deployments' section. This can be done using the 'flow add config deployment' command.") + logger.Info("Note: Core contracts do not need to be added to deployments. For reference, see this URL: https://github.com/onflow/flow-core-contracts") return nil, nil } diff --git a/install.go b/install.go index f21ec0194..cd16effb9 100644 --- a/install.go +++ b/install.go @@ -62,7 +62,7 @@ func install( return nil, err } - logger.Info("✅ Dependencies installation complete. Check your flow.json") + logger.Info("✅ Dependency installation complete. Check your flow.json") return nil, nil } From 593dce71eeafe92ec6b110d48d6b8c48fc2483a8 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Tue, 30 Jan 2024 11:37:01 -0800 Subject: [PATCH 041/101] Fix command message for config add --- add.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/add.go b/add.go index b972e99a1..72eaedb7e 100644 --- a/add.go +++ b/add.go @@ -68,7 +68,7 @@ func add( } logger.Info("✅ Dependency installation complete. Check your flow.json") - logger.Info("Ensure you add any required dependencies to your 'deployments' section. This can be done using the 'flow add config deployment' command.") + logger.Info("Ensure you add any required dependencies to your 'deployments' section. This can be done using the 'flow config add deployment' command.") logger.Info("Note: Core contracts do not need to be added to deployments. For reference, see this URL: https://github.com/onflow/flow-core-contracts") return nil, nil From 680073f1d47cb2b0784e34100a5bb386ad029514 Mon Sep 17 00:00:00 2001 From: Ian Pun Date: Thu, 1 Feb 2024 13:30:24 -0800 Subject: [PATCH 042/101] update to use flowkit externally --- add.go | 4 ++-- dependencyinstaller.go | 10 +++++----- dependencyinstaller_test.go | 10 +++++----- install.go | 4 ++-- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/add.go b/add.go index 72eaedb7e..79a601715 100644 --- a/add.go +++ b/add.go @@ -23,9 +23,9 @@ import ( "github.com/spf13/cobra" - "github.com/onflow/flow-cli/flowkit" - "github.com/onflow/flow-cli/flowkit/output" "github.com/onflow/flow-cli/internal/command" + "github.com/onflow/flowkit" + "github.com/onflow/flowkit/output" ) type addFlagsCollection struct { diff --git a/dependencyinstaller.go b/dependencyinstaller.go index 0be79d74b..b2581255b 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -28,16 +28,16 @@ import ( "github.com/onflow/flow-cli/internal/util" - "github.com/onflow/flow-cli/flowkit/gateway" + "github.com/onflow/flowkit/gateway" - "github.com/onflow/flow-cli/flowkit/project" + "github.com/onflow/flowkit/project" flowsdk "github.com/onflow/flow-go-sdk" - "github.com/onflow/flow-cli/flowkit/config" + "github.com/onflow/flowkit/config" - "github.com/onflow/flow-cli/flowkit" - "github.com/onflow/flow-cli/flowkit/output" + "github.com/onflow/flowkit" + "github.com/onflow/flowkit/output" ) type DependencyInstaller struct { diff --git a/dependencyinstaller_test.go b/dependencyinstaller_test.go index 9a7e1ac59..abeda12d2 100644 --- a/dependencyinstaller_test.go +++ b/dependencyinstaller_test.go @@ -26,12 +26,12 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" - "github.com/onflow/flow-cli/flowkit/config" - "github.com/onflow/flow-cli/flowkit/gateway" - "github.com/onflow/flow-cli/flowkit/gateway/mocks" - "github.com/onflow/flow-cli/flowkit/output" - "github.com/onflow/flow-cli/flowkit/tests" "github.com/onflow/flow-cli/internal/util" + "github.com/onflow/flowkit/config" + "github.com/onflow/flowkit/gateway" + "github.com/onflow/flowkit/gateway/mocks" + "github.com/onflow/flowkit/output" + "github.com/onflow/flowkit/tests" ) func TestDependencyInstallerInstall(t *testing.T) { diff --git a/install.go b/install.go index cd16effb9..4eb17be18 100644 --- a/install.go +++ b/install.go @@ -23,9 +23,9 @@ import ( "github.com/spf13/cobra" - "github.com/onflow/flow-cli/flowkit" - "github.com/onflow/flow-cli/flowkit/output" "github.com/onflow/flow-cli/internal/command" + "github.com/onflow/flowkit" + "github.com/onflow/flowkit/output" ) type installFlagsCollection struct{} From 693df90d9a2ac46326d6e048d99a0df30e24dd33 Mon Sep 17 00:00:00 2001 From: Ian Pun Date: Thu, 1 Feb 2024 16:02:03 -0800 Subject: [PATCH 043/101] linter --- add.go | 3 ++- dependencyinstaller_test.go | 3 ++- install.go | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/add.go b/add.go index 79a601715..30bc66e7b 100644 --- a/add.go +++ b/add.go @@ -23,9 +23,10 @@ import ( "github.com/spf13/cobra" - "github.com/onflow/flow-cli/internal/command" "github.com/onflow/flowkit" "github.com/onflow/flowkit/output" + + "github.com/onflow/flow-cli/internal/command" ) type addFlagsCollection struct { diff --git a/dependencyinstaller_test.go b/dependencyinstaller_test.go index abeda12d2..ecacc944c 100644 --- a/dependencyinstaller_test.go +++ b/dependencyinstaller_test.go @@ -26,12 +26,13 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" - "github.com/onflow/flow-cli/internal/util" "github.com/onflow/flowkit/config" "github.com/onflow/flowkit/gateway" "github.com/onflow/flowkit/gateway/mocks" "github.com/onflow/flowkit/output" "github.com/onflow/flowkit/tests" + + "github.com/onflow/flow-cli/internal/util" ) func TestDependencyInstallerInstall(t *testing.T) { diff --git a/install.go b/install.go index 4eb17be18..f1a49fea1 100644 --- a/install.go +++ b/install.go @@ -23,9 +23,10 @@ import ( "github.com/spf13/cobra" - "github.com/onflow/flow-cli/internal/command" "github.com/onflow/flowkit" "github.com/onflow/flowkit/output" + + "github.com/onflow/flow-cli/internal/command" ) type installFlagsCollection struct{} From e20f0ef86e6e2281bd503e22226abc501c537f8d Mon Sep 17 00:00:00 2001 From: Ian Pun Date: Mon, 5 Feb 2024 12:48:05 -0800 Subject: [PATCH 044/101] use flowkit v2 --- add.go | 4 ++-- dependencyinstaller.go | 10 +++++----- dependencyinstaller_test.go | 10 +++++----- install.go | 4 ++-- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/add.go b/add.go index b972e99a1..1e635cc20 100644 --- a/add.go +++ b/add.go @@ -23,9 +23,9 @@ import ( "github.com/spf13/cobra" - "github.com/onflow/flow-cli/flowkit" - "github.com/onflow/flow-cli/flowkit/output" "github.com/onflow/flow-cli/internal/command" + "github.com/onflow/flowkit/v2" + "github.com/onflow/flowkit/v2/output" ) type addFlagsCollection struct { diff --git a/dependencyinstaller.go b/dependencyinstaller.go index 0be79d74b..c142bf51b 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -28,16 +28,16 @@ import ( "github.com/onflow/flow-cli/internal/util" - "github.com/onflow/flow-cli/flowkit/gateway" + "github.com/onflow/flowkit/v2/gateway" - "github.com/onflow/flow-cli/flowkit/project" + "github.com/onflow/flowkit/v2/project" flowsdk "github.com/onflow/flow-go-sdk" - "github.com/onflow/flow-cli/flowkit/config" + "github.com/onflow/flowkit/v2/config" - "github.com/onflow/flow-cli/flowkit" - "github.com/onflow/flow-cli/flowkit/output" + "github.com/onflow/flowkit/v2" + "github.com/onflow/flowkit/v2/output" ) type DependencyInstaller struct { diff --git a/dependencyinstaller_test.go b/dependencyinstaller_test.go index 9a7e1ac59..fd18a30ee 100644 --- a/dependencyinstaller_test.go +++ b/dependencyinstaller_test.go @@ -26,12 +26,12 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" - "github.com/onflow/flow-cli/flowkit/config" - "github.com/onflow/flow-cli/flowkit/gateway" - "github.com/onflow/flow-cli/flowkit/gateway/mocks" - "github.com/onflow/flow-cli/flowkit/output" - "github.com/onflow/flow-cli/flowkit/tests" "github.com/onflow/flow-cli/internal/util" + "github.com/onflow/flowkit/v2/config" + "github.com/onflow/flowkit/v2/gateway" + "github.com/onflow/flowkit/v2/gateway/mocks" + "github.com/onflow/flowkit/v2/output" + "github.com/onflow/flowkit/v2/tests" ) func TestDependencyInstallerInstall(t *testing.T) { diff --git a/install.go b/install.go index cd16effb9..45f262762 100644 --- a/install.go +++ b/install.go @@ -23,9 +23,9 @@ import ( "github.com/spf13/cobra" - "github.com/onflow/flow-cli/flowkit" - "github.com/onflow/flow-cli/flowkit/output" "github.com/onflow/flow-cli/internal/command" + "github.com/onflow/flowkit/v2" + "github.com/onflow/flowkit/v2/output" ) type installFlagsCollection struct{} From 8aca9cf5010a4f7dabb1805c3f859d7c056d4798 Mon Sep 17 00:00:00 2001 From: Ian Pun Date: Mon, 5 Feb 2024 13:20:01 -0800 Subject: [PATCH 045/101] fix imports --- add.go | 3 ++- dependencyinstaller_test.go | 3 ++- install.go | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/add.go b/add.go index 1e635cc20..b7ee54943 100644 --- a/add.go +++ b/add.go @@ -23,9 +23,10 @@ import ( "github.com/spf13/cobra" - "github.com/onflow/flow-cli/internal/command" "github.com/onflow/flowkit/v2" "github.com/onflow/flowkit/v2/output" + + "github.com/onflow/flow-cli/internal/command" ) type addFlagsCollection struct { diff --git a/dependencyinstaller_test.go b/dependencyinstaller_test.go index fd18a30ee..23f6e6626 100644 --- a/dependencyinstaller_test.go +++ b/dependencyinstaller_test.go @@ -26,12 +26,13 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" - "github.com/onflow/flow-cli/internal/util" "github.com/onflow/flowkit/v2/config" "github.com/onflow/flowkit/v2/gateway" "github.com/onflow/flowkit/v2/gateway/mocks" "github.com/onflow/flowkit/v2/output" "github.com/onflow/flowkit/v2/tests" + + "github.com/onflow/flow-cli/internal/util" ) func TestDependencyInstallerInstall(t *testing.T) { diff --git a/install.go b/install.go index 45f262762..4014b4c66 100644 --- a/install.go +++ b/install.go @@ -23,9 +23,10 @@ import ( "github.com/spf13/cobra" - "github.com/onflow/flow-cli/internal/command" "github.com/onflow/flowkit/v2" "github.com/onflow/flowkit/v2/output" + + "github.com/onflow/flow-cli/internal/command" ) type installFlagsCollection struct{} From 9e5a7d059463969d24944ae2fb209083065ef8be Mon Sep 17 00:00:00 2001 From: Ian Pun Date: Fri, 16 Feb 2024 10:48:34 -0800 Subject: [PATCH 046/101] revert commits --- dependencyinstaller.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dependencyinstaller.go b/dependencyinstaller.go index b2581255b..c00cdcba2 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -19,6 +19,7 @@ package dependencymanager import ( + "context" "crypto/sha256" "encoding/hex" "fmt" @@ -123,7 +124,7 @@ func (di *DependencyInstaller) processDependency(dependency config.Dependency) e } func (di *DependencyInstaller) fetchDependencies(networkName string, address flowsdk.Address, assignedName, contractName string) error { - account, err := di.Gateways[networkName].GetAccount(address) + account, err := di.Gateways[networkName].GetAccount(context.Background(), address) if err != nil { return fmt.Errorf("failed to get account: %w", err) } From c61a80bc87b5ab29a50c5c1de5d04ee370b1f86a Mon Sep 17 00:00:00 2001 From: Ian Pun Date: Fri, 16 Feb 2024 10:52:57 -0800 Subject: [PATCH 047/101] revert changes to update --- dependencyinstaller.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dependencyinstaller.go b/dependencyinstaller.go index c00cdcba2..b2581255b 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -19,7 +19,6 @@ package dependencymanager import ( - "context" "crypto/sha256" "encoding/hex" "fmt" @@ -124,7 +123,7 @@ func (di *DependencyInstaller) processDependency(dependency config.Dependency) e } func (di *DependencyInstaller) fetchDependencies(networkName string, address flowsdk.Address, assignedName, contractName string) error { - account, err := di.Gateways[networkName].GetAccount(context.Background(), address) + account, err := di.Gateways[networkName].GetAccount(address) if err != nil { return fmt.Errorf("failed to get account: %w", err) } From 9c574a07000334385985b93cccf3dd681962300a Mon Sep 17 00:00:00 2001 From: Tom Haile Date: Wed, 21 Feb 2024 16:16:52 -0600 Subject: [PATCH 048/101] fix unit tests --- dependencyinstaller_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dependencyinstaller_test.go b/dependencyinstaller_test.go index 23f6e6626..cd63691f9 100644 --- a/dependencyinstaller_test.go +++ b/dependencyinstaller_test.go @@ -58,7 +58,7 @@ func TestDependencyInstallerInstall(t *testing.T) { gw := mocks.DefaultMockGateway() gw.GetAccount.Run(func(args mock.Arguments) { - addr := args.Get(0).(flow.Address) + addr := args.Get(1).(flow.Address) assert.Equal(t, addr.String(), serviceAcc.Address.String()) acc := tests.NewAccountWithAddress(addr.String()) acc.Contracts = map[string][]byte{ @@ -100,7 +100,7 @@ func TestDependencyInstallerAdd(t *testing.T) { gw := mocks.DefaultMockGateway() gw.GetAccount.Run(func(args mock.Arguments) { - addr := args.Get(0).(flow.Address) + addr := args.Get(1).(flow.Address) assert.Equal(t, addr.String(), serviceAcc.Address.String()) acc := tests.NewAccountWithAddress(addr.String()) acc.Contracts = map[string][]byte{ From 263958c47f3dfeb28124325f384be2550df6c90a Mon Sep 17 00:00:00 2001 From: Jordan Ribbink Date: Tue, 27 Feb 2024 15:00:32 -0800 Subject: [PATCH 049/101] Add Previewnet network (#1432) --- dependencyinstaller.go | 12 +++++++++--- dependencyinstaller_test.go | 14 ++++++++------ 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/dependencyinstaller.go b/dependencyinstaller.go index 09d6280b0..9a42f4ff6 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -65,10 +65,16 @@ func NewDependencyInstaller(logger output.Logger, state *flowkit.State) (*Depend return nil, fmt.Errorf("error creating mainnet gateway: %v", err) } + previewnetGateway, err := gateway.NewGrpcGateway(config.PreviewnetNetwork) + if err != nil { + return nil, fmt.Errorf("error creating previewnet gateway: %v", err) + } + gateways := map[string]gateway.Gateway{ - config.EmulatorNetwork.Name: emulatorGateway, - config.TestnetNetwork.Name: testnetGateway, - config.MainnetNetwork.Name: mainnetGateway, + config.EmulatorNetwork.Name: emulatorGateway, + config.TestnetNetwork.Name: testnetGateway, + config.MainnetNetwork.Name: mainnetGateway, + config.PreviewnetNetwork.Name: previewnetGateway, } return &DependencyInstaller{ diff --git a/dependencyinstaller_test.go b/dependencyinstaller_test.go index cd63691f9..9fd03cde4 100644 --- a/dependencyinstaller_test.go +++ b/dependencyinstaller_test.go @@ -70,9 +70,10 @@ func TestDependencyInstallerInstall(t *testing.T) { di := &DependencyInstaller{ Gateways: map[string]gateway.Gateway{ - config.EmulatorNetwork.Name: gw.Mock, - config.TestnetNetwork.Name: gw.Mock, - config.MainnetNetwork.Name: gw.Mock, + config.EmulatorNetwork.Name: gw.Mock, + config.TestnetNetwork.Name: gw.Mock, + config.MainnetNetwork.Name: gw.Mock, + config.PreviewnetNetwork.Name: gw.Mock, }, Logger: logger, State: state, @@ -112,9 +113,10 @@ func TestDependencyInstallerAdd(t *testing.T) { di := &DependencyInstaller{ Gateways: map[string]gateway.Gateway{ - config.EmulatorNetwork.Name: gw.Mock, - config.TestnetNetwork.Name: gw.Mock, - config.MainnetNetwork.Name: gw.Mock, + config.EmulatorNetwork.Name: gw.Mock, + config.TestnetNetwork.Name: gw.Mock, + config.MainnetNetwork.Name: gw.Mock, + config.PreviewnetNetwork.Name: gw.Mock, }, Logger: logger, State: state, From b9328f38d14eb8fe497fb4e7dde657844d40d0be Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Tue, 5 Mar 2024 13:42:15 -0800 Subject: [PATCH 050/101] Bump flowkit to v1.16.0 --- dependencyinstaller.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dependencyinstaller.go b/dependencyinstaller.go index b2581255b..67f14595b 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -19,6 +19,7 @@ package dependencymanager import ( + "context" "crypto/sha256" "encoding/hex" "fmt" @@ -123,7 +124,8 @@ func (di *DependencyInstaller) processDependency(dependency config.Dependency) e } func (di *DependencyInstaller) fetchDependencies(networkName string, address flowsdk.Address, assignedName, contractName string) error { - account, err := di.Gateways[networkName].GetAccount(address) + ctx := context.Background() + account, err := di.Gateways[networkName].GetAccount(ctx, address) if err != nil { return fmt.Errorf("failed to get account: %w", err) } From 5fd75e6b965e2189eb8fca32bc4028538d5f4f1d Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Tue, 5 Mar 2024 14:06:18 -0800 Subject: [PATCH 051/101] Fix tests --- dependencyinstaller_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dependencyinstaller_test.go b/dependencyinstaller_test.go index ecacc944c..ef8bba2e6 100644 --- a/dependencyinstaller_test.go +++ b/dependencyinstaller_test.go @@ -58,7 +58,7 @@ func TestDependencyInstallerInstall(t *testing.T) { gw := mocks.DefaultMockGateway() gw.GetAccount.Run(func(args mock.Arguments) { - addr := args.Get(0).(flow.Address) + addr := args.Get(1).(flow.Address) assert.Equal(t, addr.String(), serviceAcc.Address.String()) acc := tests.NewAccountWithAddress(addr.String()) acc.Contracts = map[string][]byte{ @@ -100,7 +100,7 @@ func TestDependencyInstallerAdd(t *testing.T) { gw := mocks.DefaultMockGateway() gw.GetAccount.Run(func(args mock.Arguments) { - addr := args.Get(0).(flow.Address) + addr := args.Get(1).(flow.Address) assert.Equal(t, addr.String(), serviceAcc.Address.String()) acc := tests.NewAccountWithAddress(addr.String()) acc.Contracts = map[string][]byte{ From 7e5cdf0817951159359abf47b114b7ffce278fed Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Tue, 26 Mar 2024 13:09:13 -0700 Subject: [PATCH 052/101] Add skip deployments flag --- add.go | 5 +++-- dependencyinstaller.go | 10 ++++++---- install.go | 6 ++++-- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/add.go b/add.go index 30bc66e7b..b54ae3f06 100644 --- a/add.go +++ b/add.go @@ -30,7 +30,8 @@ import ( ) type addFlagsCollection struct { - name string `default:"" flag:"name" info:"Name of the dependency"` + name string `default:"" flag:"name" info:"Name of the dependency"` + skipDeployments bool `default:"false" flag:"skip-deployments" info:"Skip adding the dependency to deployments"` } var addFlags = addFlagsCollection{} @@ -63,7 +64,7 @@ func add( return nil, err } - if err := installer.Add(dep, addFlags.name); err != nil { + if err := installer.Add(dep, addFlags.name, addFlags.skipDeployments); err != nil { logger.Error(fmt.Sprintf("Error: %v", err)) return nil, err } diff --git a/dependencyinstaller.go b/dependencyinstaller.go index 67f14595b..d2737c9ea 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -79,7 +79,7 @@ func NewDependencyInstaller(logger output.Logger, state *flowkit.State) (*Depend } // Install processes all the dependencies in the state and installs them and any dependencies they have -func (di *DependencyInstaller) Install() error { +func (di *DependencyInstaller) Install(skipDeployments bool) error { for _, dependency := range *di.State.Dependencies() { if err := di.processDependency(dependency); err != nil { di.Logger.Error(fmt.Sprintf("Error processing dependency: %v", err)) @@ -90,7 +90,7 @@ func (di *DependencyInstaller) Install() error { } // Add processes a single dependency and installs it and any dependencies it has, as well as adding it to the state -func (di *DependencyInstaller) Add(depSource, customName string) error { +func (di *DependencyInstaller) Add(depSource, customName string, skipDeployments bool) error { depNetwork, depAddress, depContractName, err := config.ParseSourceString(depSource) if err != nil { return fmt.Errorf("error parsing source: %w", err) @@ -274,16 +274,18 @@ func (di *DependencyInstaller) handleFoundContract(networkName, contractAddr, as return fmt.Errorf("error handling file system: %w", err) } - err = di.updateState(networkName, contractAddr, assignedName, contractName, originalContractDataHash) + err = di.updateDependencyState(networkName, contractAddr, assignedName, contractName, originalContractDataHash) if err != nil { di.Logger.Error(fmt.Sprintf("Error updating state: %v", err)) return err } + // TODO: Handle adding to dependencies + return nil } -func (di *DependencyInstaller) updateState(networkName, contractAddress, assignedName, contractName, contractHash string) error { +func (di *DependencyInstaller) updateDependencyState(networkName, contractAddress, assignedName, contractName, contractHash string) error { dep := config.Dependency{ Name: assignedName, Source: config.Source{ diff --git a/install.go b/install.go index f1a49fea1..3dfd44345 100644 --- a/install.go +++ b/install.go @@ -29,7 +29,9 @@ import ( "github.com/onflow/flow-cli/internal/command" ) -type installFlagsCollection struct{} +type installFlagsCollection struct { + skipDeployments bool `default:"false" flag:"skip-deployments" info:"Skip adding the dependency to deployments"` +} var installFlags = installFlagsCollection{} @@ -58,7 +60,7 @@ func install( return nil, err } - if err := installer.Install(); err != nil { + if err := installer.Install(installFlags.skipDeployments); err != nil { logger.Error(fmt.Sprintf("Error: %v", err)) return nil, err } From 579b90738620e7c3346dd2c353438dac86985e9f Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Tue, 26 Mar 2024 13:16:13 -0700 Subject: [PATCH 053/101] Move skipDeployments to struct --- add.go | 4 ++-- dependencyinstaller.go | 25 +++++++++++++++---------- install.go | 4 ++-- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/add.go b/add.go index b54ae3f06..ac6e5f94a 100644 --- a/add.go +++ b/add.go @@ -58,13 +58,13 @@ func add( dep := args[0] - installer, err := NewDependencyInstaller(logger, state) + installer, err := NewDependencyInstaller(logger, state, addFlags.skipDeployments) if err != nil { logger.Error(fmt.Sprintf("Error: %v", err)) return nil, err } - if err := installer.Add(dep, addFlags.name, addFlags.skipDeployments); err != nil { + if err := installer.Add(dep, addFlags.name); err != nil { logger.Error(fmt.Sprintf("Error: %v", err)) return nil, err } diff --git a/dependencyinstaller.go b/dependencyinstaller.go index d2737c9ea..5b0249e6c 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -42,14 +42,15 @@ import ( ) type DependencyInstaller struct { - Gateways map[string]gateway.Gateway - Logger output.Logger - State *flowkit.State - Mutex sync.Mutex + Gateways map[string]gateway.Gateway + Logger output.Logger + State *flowkit.State + Mutex sync.Mutex + SkipDeployments bool } // NewDependencyInstaller creates a new instance of DependencyInstaller -func NewDependencyInstaller(logger output.Logger, state *flowkit.State) (*DependencyInstaller, error) { +func NewDependencyInstaller(logger output.Logger, state *flowkit.State, skipDeployments bool) (*DependencyInstaller, error) { emulatorGateway, err := gateway.NewGrpcGateway(config.EmulatorNetwork) if err != nil { return nil, fmt.Errorf("error creating emulator gateway: %v", err) @@ -72,14 +73,15 @@ func NewDependencyInstaller(logger output.Logger, state *flowkit.State) (*Depend } return &DependencyInstaller{ - Gateways: gateways, - Logger: logger, - State: state, + Gateways: gateways, + Logger: logger, + State: state, + SkipDeployments: skipDeployments, }, nil } // Install processes all the dependencies in the state and installs them and any dependencies they have -func (di *DependencyInstaller) Install(skipDeployments bool) error { +func (di *DependencyInstaller) Install() error { for _, dependency := range *di.State.Dependencies() { if err := di.processDependency(dependency); err != nil { di.Logger.Error(fmt.Sprintf("Error processing dependency: %v", err)) @@ -90,7 +92,7 @@ func (di *DependencyInstaller) Install(skipDeployments bool) error { } // Add processes a single dependency and installs it and any dependencies it has, as well as adding it to the state -func (di *DependencyInstaller) Add(depSource, customName string, skipDeployments bool) error { +func (di *DependencyInstaller) Add(depSource, customName string) error { depNetwork, depAddress, depContractName, err := config.ParseSourceString(depSource) if err != nil { return fmt.Errorf("error parsing source: %w", err) @@ -281,6 +283,9 @@ func (di *DependencyInstaller) handleFoundContract(networkName, contractAddr, as } // TODO: Handle adding to dependencies + if !di.SkipDeployments { + // Add to deployments + } return nil } diff --git a/install.go b/install.go index 3dfd44345..dcb4d47a8 100644 --- a/install.go +++ b/install.go @@ -54,13 +54,13 @@ func install( ) (result command.Result, err error) { logger.Info("🔄 Installing dependencies from flow.json...") - installer, err := NewDependencyInstaller(logger, state) + installer, err := NewDependencyInstaller(logger, state, installFlags.skipDeployments) if err != nil { logger.Error(fmt.Sprintf("Error: %v", err)) return nil, err } - if err := installer.Install(installFlags.skipDeployments); err != nil { + if err := installer.Install(); err != nil { logger.Error(fmt.Sprintf("Error: %v", err)) return nil, err } From b809f170f260ab69a47320c4e0e3d8678b46a8d5 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Tue, 26 Mar 2024 16:02:59 -0700 Subject: [PATCH 054/101] Add dependency to deployments on selection --- dependencyinstaller.go | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/dependencyinstaller.go b/dependencyinstaller.go index 5b0249e6c..7a0ac79d2 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -282,9 +282,42 @@ func (di *DependencyInstaller) handleFoundContract(networkName, contractAddr, as return err } - // TODO: Handle adding to dependencies if !di.SkipDeployments { - // Add to deployments + err = di.updateDependencyDeployment(contractName) + if err != nil { + di.Logger.Error(fmt.Sprintf("Error updating deployment: %v", err)) + return err + } + } + + return nil +} + +func (di *DependencyInstaller) updateDependencyDeployment(contractName string) error { + // Add to deployments + // If a deployment already exists for that account, contract, and network, then ignore + raw := util.AddContractToDeploymentPrompt("emulator", *di.State.Accounts(), contractName) + + if raw != nil { + deployment := di.State.Deployments().ByAccountAndNetwork(raw.Account, raw.Network) + if deployment == nil { + di.State.Deployments().AddOrUpdate(config.Deployment{ + Network: raw.Network, + Account: raw.Account, + }) + deployment = di.State.Deployments().ByAccountAndNetwork(raw.Account, raw.Network) + } + + for _, c := range raw.Contracts { + deployment.AddContract(config.ContractDeployment{Name: c}) + } + + err := di.State.SaveDefault() + if err != nil { + return err + } + + di.Logger.Info(fmt.Sprintf("Dependency Manager: %s added to emulator deployments in flow.json", contractName)) } return nil From ecb47ccc4ed0500cd6a64b40df4e3901b84734cb Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Tue, 26 Mar 2024 16:11:41 -0700 Subject: [PATCH 055/101] Ignore core contracts for adding to deployments --- dependencyinstaller.go | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/dependencyinstaller.go b/dependencyinstaller.go index 7a0ac79d2..80f93c36f 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -23,6 +23,8 @@ import ( "crypto/sha256" "encoding/hex" "fmt" + "github.com/onflow/flow-go/fvm/systemcontracts" + flowGo "github.com/onflow/flow-go/model/flow" "os" "path/filepath" "sync" @@ -244,6 +246,17 @@ func (di *DependencyInstaller) handleFileSystem(contractAddr, contractName, cont return nil } +func isCoreContract(contractName string) bool { + sc := systemcontracts.SystemContractsForChain(flowGo.Emulator) + + for _, coreContract := range sc.All() { + if coreContract.Name == contractName { + return true + } + } + return false +} + func (di *DependencyInstaller) handleFoundContract(networkName, contractAddr, assignedName, contractName string, program *project.Program) error { hash := sha256.New() hash.Write(program.CodeWithUnprocessedImports()) @@ -282,7 +295,7 @@ func (di *DependencyInstaller) handleFoundContract(networkName, contractAddr, as return err } - if !di.SkipDeployments { + if !di.SkipDeployments && !isCoreContract(contractName) { err = di.updateDependencyDeployment(contractName) if err != nil { di.Logger.Error(fmt.Sprintf("Error updating deployment: %v", err)) From 83e943c6ab1b47505dbb3966718e504e3cc1feb5 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Tue, 26 Mar 2024 16:30:57 -0700 Subject: [PATCH 056/101] Create thread safe save function --- dependencyinstaller.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/dependencyinstaller.go b/dependencyinstaller.go index 80f93c36f..5746145c1 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -325,7 +325,7 @@ func (di *DependencyInstaller) updateDependencyDeployment(contractName string) e deployment.AddContract(config.ContractDeployment{Name: c}) } - err := di.State.SaveDefault() + err := di.SaveState() if err != nil { return err } @@ -351,7 +351,7 @@ func (di *DependencyInstaller) updateDependencyState(networkName, contractAddres di.State.Dependencies().AddOrUpdate(dep) di.State.Contracts().AddDependencyAsContract(dep, networkName) - err := di.State.SaveDefault() + err := di.SaveState() if err != nil { return err } @@ -362,3 +362,10 @@ func (di *DependencyInstaller) updateDependencyState(networkName, contractAddres return nil } + +func (di *DependencyInstaller) SaveState() error { + di.Mutex.Lock() + defer di.Mutex.Unlock() + + return di.State.SaveDefault() +} From 8155f85cceeba089d33a5fe7012ab4aff3bc6903 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Wed, 27 Mar 2024 11:07:00 -0700 Subject: [PATCH 057/101] Skip deployments on test --- dependencyinstaller_test.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/dependencyinstaller_test.go b/dependencyinstaller_test.go index ef8bba2e6..22ef485cf 100644 --- a/dependencyinstaller_test.go +++ b/dependencyinstaller_test.go @@ -74,8 +74,9 @@ func TestDependencyInstallerInstall(t *testing.T) { config.TestnetNetwork.Name: gw.Mock, config.MainnetNetwork.Name: gw.Mock, }, - Logger: logger, - State: state, + Logger: logger, + State: state, + SkipDeployments: true, } err := di.Install() @@ -116,8 +117,9 @@ func TestDependencyInstallerAdd(t *testing.T) { config.TestnetNetwork.Name: gw.Mock, config.MainnetNetwork.Name: gw.Mock, }, - Logger: logger, - State: state, + Logger: logger, + State: state, + SkipDeployments: true, } sourceStr := fmt.Sprintf("emulator://%s.%s", serviceAddress.String(), tests.ContractHelloString.Name) From 9e2ad5c0c1152701de6d253820490af889f721b0 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Wed, 27 Mar 2024 11:49:39 -0700 Subject: [PATCH 058/101] Remove concurrency --- dependencyinstaller.go | 53 +++++++----------------------------------- 1 file changed, 8 insertions(+), 45 deletions(-) diff --git a/dependencyinstaller.go b/dependencyinstaller.go index 5746145c1..d416fef0c 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -23,13 +23,11 @@ import ( "crypto/sha256" "encoding/hex" "fmt" + "github.com/onflow/flow-cli/internal/util" "github.com/onflow/flow-go/fvm/systemcontracts" flowGo "github.com/onflow/flow-go/model/flow" "os" "path/filepath" - "sync" - - "github.com/onflow/flow-cli/internal/util" "github.com/onflow/flowkit/gateway" @@ -47,7 +45,6 @@ type DependencyInstaller struct { Gateways map[string]gateway.Gateway Logger output.Logger State *flowkit.State - Mutex sync.Mutex SkipDeployments bool } @@ -141,13 +138,6 @@ func (di *DependencyInstaller) fetchDependencies(networkName string, address flo return fmt.Errorf("contracts are nil for account: %s", address) } - var wg sync.WaitGroup - errCh := make(chan error, len(account.Contracts)) - - // Create a max number of goroutines so that we don't rate limit the access node - maxGoroutines := 5 - semaphore := make(chan struct{}, maxGoroutines) - found := false for _, contract := range account.Contracts { @@ -171,18 +161,11 @@ func (di *DependencyInstaller) fetchDependencies(networkName string, address flo if program.HasAddressImports() { imports := program.AddressImportDeclarations() for _, imp := range imports { - wg.Add(1) - go func(importAddress flowsdk.Address, contractName string) { - semaphore <- struct{}{} - defer func() { - <-semaphore - wg.Done() - }() - err := di.fetchDependencies(networkName, importAddress, contractName, contractName) - if err != nil { - errCh <- err - } - }(flowsdk.HexToAddress(imp.Location.String()), imp.Identifiers[0].String()) + contractName := imp.Identifiers[0].String() + err := di.fetchDependencies(networkName, flowsdk.HexToAddress(imp.Location.String()), contractName, contractName) + if err != nil { + return err + } } } } @@ -193,16 +176,6 @@ func (di *DependencyInstaller) fetchDependencies(networkName string, address flo di.Logger.Error(errMsg) } - wg.Wait() - close(errCh) - close(semaphore) - - for err := range errCh { - if err != nil { - return err - } - } - return nil } @@ -232,9 +205,6 @@ func (di *DependencyInstaller) createContractFile(address, contractName, data st } func (di *DependencyInstaller) handleFileSystem(contractAddr, contractName, contractData, networkName string) error { - di.Mutex.Lock() - defer di.Mutex.Unlock() - if !di.contractFileExists(contractAddr, contractName) { if err := di.createContractFile(contractAddr, contractName, contractData); err != nil { return fmt.Errorf("failed to create contract file: %w", err) @@ -325,7 +295,7 @@ func (di *DependencyInstaller) updateDependencyDeployment(contractName string) e deployment.AddContract(config.ContractDeployment{Name: c}) } - err := di.SaveState() + err := di.State.SaveDefault() if err != nil { return err } @@ -351,7 +321,7 @@ func (di *DependencyInstaller) updateDependencyState(networkName, contractAddres di.State.Dependencies().AddOrUpdate(dep) di.State.Contracts().AddDependencyAsContract(dep, networkName) - err := di.SaveState() + err := di.State.SaveDefault() if err != nil { return err } @@ -362,10 +332,3 @@ func (di *DependencyInstaller) updateDependencyState(networkName, contractAddres return nil } - -func (di *DependencyInstaller) SaveState() error { - di.Mutex.Lock() - defer di.Mutex.Unlock() - - return di.State.SaveDefault() -} From 75efeeeca7960f1c306619d071da6042e348cc75 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Wed, 27 Mar 2024 14:19:42 -0700 Subject: [PATCH 059/101] Run lintfix --- dependencyinstaller.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/dependencyinstaller.go b/dependencyinstaller.go index d416fef0c..5e90df1a2 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -23,12 +23,14 @@ import ( "crypto/sha256" "encoding/hex" "fmt" - "github.com/onflow/flow-cli/internal/util" - "github.com/onflow/flow-go/fvm/systemcontracts" - flowGo "github.com/onflow/flow-go/model/flow" "os" "path/filepath" + "github.com/onflow/flow-go/fvm/systemcontracts" + flowGo "github.com/onflow/flow-go/model/flow" + + "github.com/onflow/flow-cli/internal/util" + "github.com/onflow/flowkit/gateway" "github.com/onflow/flowkit/project" From 92dc09eb1521b1d2e786372cfd01ea3a93d7de99 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Mon, 1 Apr 2024 13:25:37 -0700 Subject: [PATCH 060/101] Setup prompt for empty and flag --- add.go | 3 ++- dependencyinstaller.go | 36 +++++++++++++++++++++++++++++++++++- dependencyinstaller_test.go | 2 ++ install.go | 3 ++- 4 files changed, 41 insertions(+), 3 deletions(-) diff --git a/add.go b/add.go index ac6e5f94a..b6d5bac85 100644 --- a/add.go +++ b/add.go @@ -32,6 +32,7 @@ import ( type addFlagsCollection struct { name string `default:"" flag:"name" info:"Name of the dependency"` skipDeployments bool `default:"false" flag:"skip-deployments" info:"Skip adding the dependency to deployments"` + skipAlias bool `default:"false" flag:"skip-alias" info:"Skip prompting for an alias"` } var addFlags = addFlagsCollection{} @@ -58,7 +59,7 @@ func add( dep := args[0] - installer, err := NewDependencyInstaller(logger, state, addFlags.skipDeployments) + installer, err := NewDependencyInstaller(logger, state, addFlags.skipDeployments, addFlags.skipAlias) if err != nil { logger.Error(fmt.Sprintf("Error: %v", err)) return nil, err diff --git a/dependencyinstaller.go b/dependencyinstaller.go index 5e90df1a2..657846a67 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -48,10 +48,11 @@ type DependencyInstaller struct { Logger output.Logger State *flowkit.State SkipDeployments bool + SkipAlias bool } // NewDependencyInstaller creates a new instance of DependencyInstaller -func NewDependencyInstaller(logger output.Logger, state *flowkit.State, skipDeployments bool) (*DependencyInstaller, error) { +func NewDependencyInstaller(logger output.Logger, state *flowkit.State, skipDeployments, skipAlias bool) (*DependencyInstaller, error) { emulatorGateway, err := gateway.NewGrpcGateway(config.EmulatorNetwork) if err != nil { return nil, fmt.Errorf("error creating emulator gateway: %v", err) @@ -78,6 +79,7 @@ func NewDependencyInstaller(logger output.Logger, state *flowkit.State, skipDepl Logger: logger, State: state, SkipDeployments: skipDeployments, + SkipAlias: skipAlias, }, nil } @@ -275,6 +277,14 @@ func (di *DependencyInstaller) handleFoundContract(networkName, contractAddr, as } } + if !di.SkipAlias && !isCoreContract(contractName) { + err = di.updateDependencyAlias(contractName, networkName) + if err != nil { + di.Logger.Error(fmt.Sprintf("Error updating alias: %v", err)) + return err + } + } + return nil } @@ -308,6 +318,30 @@ func (di *DependencyInstaller) updateDependencyDeployment(contractName string) e return nil } +func (di *DependencyInstaller) updateDependencyAlias(contractName, aliasNetwork string) error { + var missingNetwork string + + if aliasNetwork == "testnet" { + missingNetwork = "mainnet" + } else { + missingNetwork = "testnet" + } + + label := fmt.Sprintf("Enter an alias address for %s on %s if you have one, otherwise leave blank", contractName, missingNetwork) + raw := util.AddressPromptOrEmpty(label, "Invalid alias address") + + if raw != "" { + contract, err := di.State.Contracts().ByName(contractName) + if err != nil { + return err + } + + contract.Aliases.Add(missingNetwork, flowsdk.HexToAddress(raw)) + } + + return nil +} + func (di *DependencyInstaller) updateDependencyState(networkName, contractAddress, assignedName, contractName, contractHash string) error { dep := config.Dependency{ Name: assignedName, diff --git a/dependencyinstaller_test.go b/dependencyinstaller_test.go index 22ef485cf..92d64427e 100644 --- a/dependencyinstaller_test.go +++ b/dependencyinstaller_test.go @@ -77,6 +77,7 @@ func TestDependencyInstallerInstall(t *testing.T) { Logger: logger, State: state, SkipDeployments: true, + SkipAlias: true, } err := di.Install() @@ -120,6 +121,7 @@ func TestDependencyInstallerAdd(t *testing.T) { Logger: logger, State: state, SkipDeployments: true, + SkipAlias: true, } sourceStr := fmt.Sprintf("emulator://%s.%s", serviceAddress.String(), tests.ContractHelloString.Name) diff --git a/install.go b/install.go index dcb4d47a8..5a42852a0 100644 --- a/install.go +++ b/install.go @@ -31,6 +31,7 @@ import ( type installFlagsCollection struct { skipDeployments bool `default:"false" flag:"skip-deployments" info:"Skip adding the dependency to deployments"` + skipAlias bool `default:"false" flag:"skip-alias" info:"Skip prompting for an alias"` } var installFlags = installFlagsCollection{} @@ -54,7 +55,7 @@ func install( ) (result command.Result, err error) { logger.Info("🔄 Installing dependencies from flow.json...") - installer, err := NewDependencyInstaller(logger, state, installFlags.skipDeployments) + installer, err := NewDependencyInstaller(logger, state, installFlags.skipDeployments, addFlags.skipAlias) if err != nil { logger.Error(fmt.Sprintf("Error: %v", err)) return nil, err From 9da3be22651593bc16b0b89c00ba1cc01efd25b2 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Mon, 1 Apr 2024 14:24:19 -0700 Subject: [PATCH 061/101] Add comments --- dependencyinstaller.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dependencyinstaller.go b/dependencyinstaller.go index 657846a67..bd97c5129 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -269,6 +269,7 @@ func (di *DependencyInstaller) handleFoundContract(networkName, contractAddr, as return err } + // If the contract is not a core contract and the user does not want to skip deployments, then prompt for a deployment if !di.SkipDeployments && !isCoreContract(contractName) { err = di.updateDependencyDeployment(contractName) if err != nil { @@ -277,6 +278,7 @@ func (di *DependencyInstaller) handleFoundContract(networkName, contractAddr, as } } + // If the contract is not a core contract and the user does not want to skip aliasing, then prompt for an alias if !di.SkipAlias && !isCoreContract(contractName) { err = di.updateDependencyAlias(contractName, networkName) if err != nil { From ef269b07984f36f7b73943e326a125cfd94990b4 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Mon, 1 Apr 2024 14:26:54 -0700 Subject: [PATCH 062/101] Use constants for network --- dependencyinstaller.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dependencyinstaller.go b/dependencyinstaller.go index bd97c5129..5da6ff1d9 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -323,10 +323,10 @@ func (di *DependencyInstaller) updateDependencyDeployment(contractName string) e func (di *DependencyInstaller) updateDependencyAlias(contractName, aliasNetwork string) error { var missingNetwork string - if aliasNetwork == "testnet" { - missingNetwork = "mainnet" + if aliasNetwork == config.TestnetNetwork.Name { + missingNetwork = config.MainnetNetwork.Name } else { - missingNetwork = "testnet" + missingNetwork = config.TestnetNetwork.Name } label := fmt.Sprintf("Enter an alias address for %s on %s if you have one, otherwise leave blank", contractName, missingNetwork) From e9a70676d084dd031dfbfd28d3f428b496c676c2 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Mon, 1 Apr 2024 14:30:31 -0700 Subject: [PATCH 063/101] Fix flags name --- install.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install.go b/install.go index 5a42852a0..a4e553b02 100644 --- a/install.go +++ b/install.go @@ -55,7 +55,7 @@ func install( ) (result command.Result, err error) { logger.Info("🔄 Installing dependencies from flow.json...") - installer, err := NewDependencyInstaller(logger, state, installFlags.skipDeployments, addFlags.skipAlias) + installer, err := NewDependencyInstaller(logger, state, installFlags.skipDeployments, installFlags.skipAlias) if err != nil { logger.Error(fmt.Sprintf("Error: %v", err)) return nil, err From eee682832ec2ceadd1468fc2462fd110cb0f8841 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Mon, 1 Apr 2024 14:33:52 -0700 Subject: [PATCH 064/101] Embed deps flags collection --- add.go | 5 ++--- install.go | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/add.go b/add.go index b6d5bac85..7ecb4e3d5 100644 --- a/add.go +++ b/add.go @@ -30,9 +30,8 @@ import ( ) type addFlagsCollection struct { - name string `default:"" flag:"name" info:"Name of the dependency"` - skipDeployments bool `default:"false" flag:"skip-deployments" info:"Skip adding the dependency to deployments"` - skipAlias bool `default:"false" flag:"skip-alias" info:"Skip prompting for an alias"` + dependencyManagerFlagsCollection + name string `default:"" flag:"name" info:"Name of the dependency"` } var addFlags = addFlagsCollection{} diff --git a/install.go b/install.go index a4e553b02..514703a37 100644 --- a/install.go +++ b/install.go @@ -29,12 +29,12 @@ import ( "github.com/onflow/flow-cli/internal/command" ) -type installFlagsCollection struct { +type dependencyManagerFlagsCollection struct { skipDeployments bool `default:"false" flag:"skip-deployments" info:"Skip adding the dependency to deployments"` skipAlias bool `default:"false" flag:"skip-alias" info:"Skip prompting for an alias"` } -var installFlags = installFlagsCollection{} +var installFlags = dependencyManagerFlagsCollection{} var installCommand = &command.Command{ Cmd: &cobra.Command{ From 3e1a8eea039341c5e1726a8ffa1d80e4497a165e Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Mon, 1 Apr 2024 14:40:59 -0700 Subject: [PATCH 065/101] Pass flags as arg --- add.go | 2 +- dependencyinstaller.go | 11 ++++++++--- install.go | 7 +------ 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/add.go b/add.go index 7ecb4e3d5..020312b8f 100644 --- a/add.go +++ b/add.go @@ -58,7 +58,7 @@ func add( dep := args[0] - installer, err := NewDependencyInstaller(logger, state, addFlags.skipDeployments, addFlags.skipAlias) + installer, err := NewDependencyInstaller(logger, state, addFlags.dependencyManagerFlagsCollection) if err != nil { logger.Error(fmt.Sprintf("Error: %v", err)) return nil, err diff --git a/dependencyinstaller.go b/dependencyinstaller.go index 5da6ff1d9..a00bc6fde 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -43,6 +43,11 @@ import ( "github.com/onflow/flowkit/output" ) +type dependencyManagerFlagsCollection struct { + skipDeployments bool `default:"false" flag:"skip-deployments" info:"Skip adding the dependency to deployments"` + skipAlias bool `default:"false" flag:"skip-alias" info:"Skip prompting for an alias"` +} + type DependencyInstaller struct { Gateways map[string]gateway.Gateway Logger output.Logger @@ -52,7 +57,7 @@ type DependencyInstaller struct { } // NewDependencyInstaller creates a new instance of DependencyInstaller -func NewDependencyInstaller(logger output.Logger, state *flowkit.State, skipDeployments, skipAlias bool) (*DependencyInstaller, error) { +func NewDependencyInstaller(logger output.Logger, state *flowkit.State, flags dependencyManagerFlagsCollection) (*DependencyInstaller, error) { emulatorGateway, err := gateway.NewGrpcGateway(config.EmulatorNetwork) if err != nil { return nil, fmt.Errorf("error creating emulator gateway: %v", err) @@ -78,8 +83,8 @@ func NewDependencyInstaller(logger output.Logger, state *flowkit.State, skipDepl Gateways: gateways, Logger: logger, State: state, - SkipDeployments: skipDeployments, - SkipAlias: skipAlias, + SkipDeployments: flags.skipDeployments, + SkipAlias: flags.skipAlias, }, nil } diff --git a/install.go b/install.go index 514703a37..96f3f1583 100644 --- a/install.go +++ b/install.go @@ -29,11 +29,6 @@ import ( "github.com/onflow/flow-cli/internal/command" ) -type dependencyManagerFlagsCollection struct { - skipDeployments bool `default:"false" flag:"skip-deployments" info:"Skip adding the dependency to deployments"` - skipAlias bool `default:"false" flag:"skip-alias" info:"Skip prompting for an alias"` -} - var installFlags = dependencyManagerFlagsCollection{} var installCommand = &command.Command{ @@ -55,7 +50,7 @@ func install( ) (result command.Result, err error) { logger.Info("🔄 Installing dependencies from flow.json...") - installer, err := NewDependencyInstaller(logger, state, installFlags.skipDeployments, installFlags.skipAlias) + installer, err := NewDependencyInstaller(logger, state, installFlags) if err != nil { logger.Error(fmt.Sprintf("Error: %v", err)) return nil, err From 466e6ea44159cb13bd16074883246d066b89a617 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Tue, 2 Apr 2024 11:00:17 -0700 Subject: [PATCH 066/101] Save state at end --- dependencyinstaller.go | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/dependencyinstaller.go b/dependencyinstaller.go index a00bc6fde..2da380017 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -96,6 +96,12 @@ func (di *DependencyInstaller) Install() error { return err } } + + err := di.State.SaveDefault() + if err != nil { + return fmt.Errorf("error saving state: %w", err) + } + return nil } @@ -125,6 +131,11 @@ func (di *DependencyInstaller) Add(depSource, customName string) error { return fmt.Errorf("error processing dependency: %w", err) } + err = di.State.SaveDefault() + if err != nil { + return fmt.Errorf("error saving state: %w", err) + } + return nil } @@ -314,11 +325,6 @@ func (di *DependencyInstaller) updateDependencyDeployment(contractName string) e deployment.AddContract(config.ContractDeployment{Name: c}) } - err := di.State.SaveDefault() - if err != nil { - return err - } - di.Logger.Info(fmt.Sprintf("Dependency Manager: %s added to emulator deployments in flow.json", contractName)) } @@ -364,10 +370,6 @@ func (di *DependencyInstaller) updateDependencyState(networkName, contractAddres di.State.Dependencies().AddOrUpdate(dep) di.State.Contracts().AddDependencyAsContract(dep, networkName) - err := di.State.SaveDefault() - if err != nil { - return err - } if isNewDep { di.Logger.Info(fmt.Sprintf("Dependency Manager: %s added to flow.json", dep.Name)) From b6928dfdb7480127e69410336ad5dedd13c8d4e8 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Tue, 2 Apr 2024 11:00:46 -0700 Subject: [PATCH 067/101] Remove no longer necessary message --- add.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/add.go b/add.go index 020312b8f..09d8d26ab 100644 --- a/add.go +++ b/add.go @@ -70,8 +70,6 @@ func add( } logger.Info("✅ Dependency installation complete. Check your flow.json") - logger.Info("Ensure you add any required dependencies to your 'deployments' section. This can be done using the 'flow config add deployment' command.") - logger.Info("Note: Core contracts do not need to be added to deployments. For reference, see this URL: https://github.com/onflow/flow-core-contracts") return nil, nil } From d914353e2e14910934b19dd4d0dbfba5770e80e6 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Tue, 2 Apr 2024 14:08:38 -0700 Subject: [PATCH 068/101] Add LogAll at end for summary --- add.go | 2 -- dependencyinstaller.go | 50 ++++++++++++++++++++++++++++++++++++++---- install.go | 2 -- 3 files changed, 46 insertions(+), 8 deletions(-) diff --git a/add.go b/add.go index 09d8d26ab..40252f0d7 100644 --- a/add.go +++ b/add.go @@ -69,7 +69,5 @@ func add( return nil, err } - logger.Info("✅ Dependency installation complete. Check your flow.json") - return nil, nil } diff --git a/dependencyinstaller.go b/dependencyinstaller.go index 2da380017..1c38ba51f 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -43,6 +43,41 @@ import ( "github.com/onflow/flowkit/output" ) +type categorizedLogs struct { + dependencyActions []string + fileSystemActions []string + stateUpdates []string +} + +func (cl *categorizedLogs) LogAll(logger output.Logger) { + logger.Info("📝 Dependency Manager Actions Summary") + logger.Info("") // Add a line break after the section + + if len(cl.dependencyActions) > 0 { + logger.Info("🔨 Dependency Actions:") + for _, msg := range cl.dependencyActions { + logger.Info(fmt.Sprintf("✅ %s", msg)) + } + logger.Info("") // Add a line break after the section + } + + if len(cl.fileSystemActions) > 0 { + logger.Info("🗃️ File System Actions:") + for _, msg := range cl.fileSystemActions { + logger.Info(fmt.Sprintf("✅ %s", msg)) + } + logger.Info("") // Add a line break after the section + } + + if len(cl.stateUpdates) > 0 { + logger.Info("💾 State Updates:") + for _, msg := range cl.stateUpdates { + logger.Info(fmt.Sprintf("✅ %s", msg)) + } + logger.Info("") // Add a line break after the section + } +} + type dependencyManagerFlagsCollection struct { skipDeployments bool `default:"false" flag:"skip-deployments" info:"Skip adding the dependency to deployments"` skipAlias bool `default:"false" flag:"skip-alias" info:"Skip prompting for an alias"` @@ -54,6 +89,7 @@ type DependencyInstaller struct { State *flowkit.State SkipDeployments bool SkipAlias bool + logs categorizedLogs } // NewDependencyInstaller creates a new instance of DependencyInstaller @@ -102,6 +138,8 @@ func (di *DependencyInstaller) Install() error { return fmt.Errorf("error saving state: %w", err) } + di.logs.LogAll(di.Logger) + return nil } @@ -136,6 +174,8 @@ func (di *DependencyInstaller) Add(depSource, customName string) error { return fmt.Errorf("error saving state: %w", err) } + di.logs.LogAll(di.Logger) + return nil } @@ -230,7 +270,7 @@ func (di *DependencyInstaller) handleFileSystem(contractAddr, contractName, cont return fmt.Errorf("failed to create contract file: %w", err) } - di.Logger.Info(fmt.Sprintf("Dependency Manager: %s from %s on %s installed", contractName, contractAddr, networkName)) + di.logs.fileSystemActions = append(di.logs.fileSystemActions, fmt.Sprintf("%s from %s on %s installed", contractName, contractAddr, networkName)) } return nil @@ -292,6 +332,8 @@ func (di *DependencyInstaller) handleFoundContract(networkName, contractAddr, as di.Logger.Error(fmt.Sprintf("Error updating deployment: %v", err)) return err } + + di.logs.dependencyActions = append(di.logs.dependencyActions, fmt.Sprintf("%s added to emulator deployments", contractName)) } // If the contract is not a core contract and the user does not want to skip aliasing, then prompt for an alias @@ -301,6 +343,8 @@ func (di *DependencyInstaller) handleFoundContract(networkName, contractAddr, as di.Logger.Error(fmt.Sprintf("Error updating alias: %v", err)) return err } + + di.logs.dependencyActions = append(di.logs.dependencyActions, fmt.Sprintf("Alias added for %s on %s", contractName, networkName)) } return nil @@ -324,8 +368,6 @@ func (di *DependencyInstaller) updateDependencyDeployment(contractName string) e for _, c := range raw.Contracts { deployment.AddContract(config.ContractDeployment{Name: c}) } - - di.Logger.Info(fmt.Sprintf("Dependency Manager: %s added to emulator deployments in flow.json", contractName)) } return nil @@ -372,7 +414,7 @@ func (di *DependencyInstaller) updateDependencyState(networkName, contractAddres di.State.Contracts().AddDependencyAsContract(dep, networkName) if isNewDep { - di.Logger.Info(fmt.Sprintf("Dependency Manager: %s added to flow.json", dep.Name)) + di.logs.stateUpdates = append(di.logs.stateUpdates, fmt.Sprintf("%s added to flow.json", dep.Name)) } return nil diff --git a/install.go b/install.go index 96f3f1583..25bbb1ba1 100644 --- a/install.go +++ b/install.go @@ -61,7 +61,5 @@ func install( return nil, err } - logger.Info("✅ Dependency installation complete. Check your flow.json") - return nil, nil } From 1fa8e46232ce5a56eccead6a1b4573f7ee44966b Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Tue, 2 Apr 2024 14:35:45 -0700 Subject: [PATCH 069/101] Consolidate dep logs categories --- dependencyinstaller.go | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/dependencyinstaller.go b/dependencyinstaller.go index 1c38ba51f..610709afd 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -44,7 +44,6 @@ import ( ) type categorizedLogs struct { - dependencyActions []string fileSystemActions []string stateUpdates []string } @@ -53,14 +52,6 @@ func (cl *categorizedLogs) LogAll(logger output.Logger) { logger.Info("📝 Dependency Manager Actions Summary") logger.Info("") // Add a line break after the section - if len(cl.dependencyActions) > 0 { - logger.Info("🔨 Dependency Actions:") - for _, msg := range cl.dependencyActions { - logger.Info(fmt.Sprintf("✅ %s", msg)) - } - logger.Info("") // Add a line break after the section - } - if len(cl.fileSystemActions) > 0 { logger.Info("🗃️ File System Actions:") for _, msg := range cl.fileSystemActions { @@ -333,7 +324,7 @@ func (di *DependencyInstaller) handleFoundContract(networkName, contractAddr, as return err } - di.logs.dependencyActions = append(di.logs.dependencyActions, fmt.Sprintf("%s added to emulator deployments", contractName)) + di.logs.stateUpdates = append(di.logs.stateUpdates, fmt.Sprintf("%s added to emulator deployments", contractName)) } // If the contract is not a core contract and the user does not want to skip aliasing, then prompt for an alias @@ -344,7 +335,7 @@ func (di *DependencyInstaller) handleFoundContract(networkName, contractAddr, as return err } - di.logs.dependencyActions = append(di.logs.dependencyActions, fmt.Sprintf("Alias added for %s on %s", contractName, networkName)) + di.logs.stateUpdates = append(di.logs.stateUpdates, fmt.Sprintf("Alias added for %s on %s", contractName, networkName)) } return nil From f901ff6836efc6e2cebcf81ade14615c6eb9169b Mon Sep 17 00:00:00 2001 From: Chase Fleming Date: Mon, 15 Apr 2024 16:56:53 -0700 Subject: [PATCH 070/101] Setup should prompt to add core contracts as dependencies and install (#1517) * Bump codecov/codecov-action from 1 to 4 Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 1 to 4. - [Release notes](https://github.com/codecov/codecov-action/releases) - [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/codecov/codecov-action/compare/v1...v4) --- updated-dependencies: - dependency-name: codecov/codecov-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] * Bump actions/add-to-project from 0.4.1 to 0.6.1 Bumps [actions/add-to-project](https://github.com/actions/add-to-project) from 0.4.1 to 0.6.1. - [Release notes](https://github.com/actions/add-to-project/releases) - [Commits](https://github.com/actions/add-to-project/compare/v0.4.1...v0.6.1) --- updated-dependencies: - dependency-name: actions/add-to-project dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Create option select prompt * Create AddMany method in dependency manager * Update flags naming * Add SaveState option to DependencyManager * Add target dir to dependencymanager for imports * Update Flow dependencies to latest version (#1509) * Update to latest Cadence Language Server (#1513) * Save to target dir * Add dependencies when selected * Fix tests * Change to addbysourcestring * Merge master * Fix imports * Remove test * Use constant for network --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jordan Ribbink Co-authored-by: Chase Fleming <1666730+chasefleming@users.noreply.github.com> --- add.go | 6 +- dependencyinstaller.go | 67 +++++++++++++++++---- dependencyinstaller_test.go | 115 +++++++++++++++++++++++++++++++++++- install.go | 4 +- 4 files changed, 175 insertions(+), 17 deletions(-) diff --git a/add.go b/add.go index 40252f0d7..1542628f1 100644 --- a/add.go +++ b/add.go @@ -30,7 +30,7 @@ import ( ) type addFlagsCollection struct { - dependencyManagerFlagsCollection + DependencyManagerFlagsCollection name string `default:"" flag:"name" info:"Name of the dependency"` } @@ -58,13 +58,13 @@ func add( dep := args[0] - installer, err := NewDependencyInstaller(logger, state, addFlags.dependencyManagerFlagsCollection) + installer, err := NewDependencyInstaller(logger, state, true, "", addFlags.DependencyManagerFlagsCollection) if err != nil { logger.Error(fmt.Sprintf("Error: %v", err)) return nil, err } - if err := installer.Add(dep, addFlags.name); err != nil { + if err := installer.AddBySourceString(dep, addFlags.name); err != nil { logger.Error(fmt.Sprintf("Error: %v", err)) return nil, err } diff --git a/dependencyinstaller.go b/dependencyinstaller.go index 610709afd..14fdb9470 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -69,7 +69,7 @@ func (cl *categorizedLogs) LogAll(logger output.Logger) { } } -type dependencyManagerFlagsCollection struct { +type DependencyManagerFlagsCollection struct { skipDeployments bool `default:"false" flag:"skip-deployments" info:"Skip adding the dependency to deployments"` skipAlias bool `default:"false" flag:"skip-alias" info:"Skip prompting for an alias"` } @@ -78,13 +78,15 @@ type DependencyInstaller struct { Gateways map[string]gateway.Gateway Logger output.Logger State *flowkit.State + SaveState bool + TargetDir string SkipDeployments bool SkipAlias bool logs categorizedLogs } // NewDependencyInstaller creates a new instance of DependencyInstaller -func NewDependencyInstaller(logger output.Logger, state *flowkit.State, flags dependencyManagerFlagsCollection) (*DependencyInstaller, error) { +func NewDependencyInstaller(logger output.Logger, state *flowkit.State, saveState bool, targetDir string, flags DependencyManagerFlagsCollection) (*DependencyInstaller, error) { emulatorGateway, err := gateway.NewGrpcGateway(config.EmulatorNetwork) if err != nil { return nil, fmt.Errorf("error creating emulator gateway: %v", err) @@ -110,11 +112,24 @@ func NewDependencyInstaller(logger output.Logger, state *flowkit.State, flags de Gateways: gateways, Logger: logger, State: state, + SaveState: saveState, + TargetDir: targetDir, SkipDeployments: flags.skipDeployments, SkipAlias: flags.skipAlias, }, nil } +// saveState checks the SaveState flag and saves the state if set to true. +func (di *DependencyInstaller) saveState() error { + if di.SaveState { + statePath := filepath.Join(di.TargetDir, "flow.json") + if err := di.State.Save(statePath); err != nil { + return fmt.Errorf("error saving state: %w", err) + } + } + return nil +} + // Install processes all the dependencies in the state and installs them and any dependencies they have func (di *DependencyInstaller) Install() error { for _, dependency := range *di.State.Dependencies() { @@ -124,9 +139,8 @@ func (di *DependencyInstaller) Install() error { } } - err := di.State.SaveDefault() - if err != nil { - return fmt.Errorf("error saving state: %w", err) + if err := di.saveState(); err != nil { + return err } di.logs.LogAll(di.Logger) @@ -134,8 +148,8 @@ func (di *DependencyInstaller) Install() error { return nil } -// Add processes a single dependency and installs it and any dependencies it has, as well as adding it to the state -func (di *DependencyInstaller) Add(depSource, customName string) error { +// AddBySourceString processes a single dependency and installs it and any dependencies it has, as well as adding it to the state +func (di *DependencyInstaller) AddBySourceString(depSource, customName string) error { depNetwork, depAddress, depContractName, err := config.ParseSourceString(depSource) if err != nil { return fmt.Errorf("error parsing source: %w", err) @@ -160,9 +174,40 @@ func (di *DependencyInstaller) Add(depSource, customName string) error { return fmt.Errorf("error processing dependency: %w", err) } - err = di.State.SaveDefault() - if err != nil { - return fmt.Errorf("error saving state: %w", err) + if err := di.saveState(); err != nil { + return err + } + + di.logs.LogAll(di.Logger) + + return nil +} + +// Add processes a single dependency and installs it and any dependencies it has, as well as adding it to the state +func (di *DependencyInstaller) Add(dep config.Dependency) error { + if err := di.processDependency(dep); err != nil { + return fmt.Errorf("error processing dependency: %w", err) + } + + if err := di.saveState(); err != nil { + return err + } + + di.logs.LogAll(di.Logger) + + return nil +} + +// AddMany processes multiple dependencies and installs them as well as adding them to the state +func (di *DependencyInstaller) AddMany(dependencies []config.Dependency) error { + for _, dep := range dependencies { + if err := di.processDependency(dep); err != nil { + return fmt.Errorf("error processing dependency: %w", err) + } + } + + if err := di.saveState(); err != nil { + return err } di.logs.LogAll(di.Logger) @@ -241,7 +286,7 @@ func (di *DependencyInstaller) contractFileExists(address, contractName string) func (di *DependencyInstaller) createContractFile(address, contractName, data string) error { fileName := fmt.Sprintf("%s.cdc", contractName) - path := filepath.Join("imports", address, fileName) + path := filepath.Join(di.TargetDir, "imports", address, fileName) dir := filepath.Dir(path) if err := di.State.ReaderWriter().MkdirAll(dir, 0755); err != nil { diff --git a/dependencyinstaller_test.go b/dependencyinstaller_test.go index 92d64427e..dd1941bba 100644 --- a/dependencyinstaller_test.go +++ b/dependencyinstaller_test.go @@ -76,6 +76,8 @@ func TestDependencyInstallerInstall(t *testing.T) { }, Logger: logger, State: state, + SaveState: true, + TargetDir: "", SkipDeployments: true, SkipAlias: true, } @@ -120,12 +122,14 @@ func TestDependencyInstallerAdd(t *testing.T) { }, Logger: logger, State: state, + SaveState: true, + TargetDir: "", SkipDeployments: true, SkipAlias: true, } sourceStr := fmt.Sprintf("emulator://%s.%s", serviceAddress.String(), tests.ContractHelloString.Name) - err := di.Add(sourceStr, "") + err := di.AddBySourceString(sourceStr, "") assert.NoError(t, err, "Failed to install dependencies") filePath := fmt.Sprintf("imports/%s/%s.cdc", serviceAddress.String(), tests.ContractHelloString.Name) @@ -133,4 +137,113 @@ func TestDependencyInstallerAdd(t *testing.T) { assert.NoError(t, err, "Failed to read generated file") assert.NotNil(t, fileContent) }) + + t.Run("Success", func(t *testing.T) { + gw := mocks.DefaultMockGateway() + + gw.GetAccount.Run(func(args mock.Arguments) { + addr := args.Get(1).(flow.Address) + assert.Equal(t, addr.String(), serviceAcc.Address.String()) + acc := tests.NewAccountWithAddress(addr.String()) + acc.Contracts = map[string][]byte{ + tests.ContractHelloString.Name: tests.ContractHelloString.Source, + } + + gw.GetAccount.Return(acc, nil) + }) + + di := &DependencyInstaller{ + Gateways: map[string]gateway.Gateway{ + config.EmulatorNetwork.Name: gw.Mock, + config.TestnetNetwork.Name: gw.Mock, + config.MainnetNetwork.Name: gw.Mock, + }, + Logger: logger, + State: state, + SaveState: true, + TargetDir: "", + SkipDeployments: true, + SkipAlias: true, + } + + dep := config.Dependency{ + Name: tests.ContractHelloString.Name, + Source: config.Source{ + NetworkName: "emulator", + Address: flow.HexToAddress(serviceAddress.String()), + ContractName: tests.ContractHelloString.Name, + }, + } + err := di.Add(dep) + assert.NoError(t, err, "Failed to install dependencies") + + filePath := fmt.Sprintf("imports/%s/%s.cdc", serviceAddress.String(), tests.ContractHelloString.Name) + fileContent, err := state.ReaderWriter().ReadFile(filePath) + assert.NoError(t, err, "Failed to read generated file") + assert.NotNil(t, fileContent) + }) +} + +func TestDependencyInstallerAddMany(t *testing.T) { + logger := output.NewStdoutLogger(output.NoneLog) + _, state, _ := util.TestMocks(t) + + serviceAcc, _ := state.EmulatorServiceAccount() + serviceAddress := serviceAcc.Address.String() + + dependencies := []config.Dependency{ + { + Name: "ContractOne", + Source: config.Source{ + NetworkName: "emulator", + Address: flow.HexToAddress(serviceAddress), + ContractName: "ContractOne", + }, + }, + { + Name: "ContractTwo", + Source: config.Source{ + NetworkName: "emulator", + Address: flow.HexToAddress(serviceAddress), + ContractName: "ContractTwo", + }, + }, + } + + t.Run("AddMultipleDependencies", func(t *testing.T) { + gw := mocks.DefaultMockGateway() + gw.GetAccount.Run(func(args mock.Arguments) { + addr := args.Get(1).(flow.Address) + assert.Equal(t, addr.String(), serviceAddress) + acc := tests.NewAccountWithAddress(addr.String()) + acc.Contracts = map[string][]byte{ + "ContractOne": []byte("pub contract ContractOne {}"), + "ContractTwo": []byte("pub contract ContractTwo {}"), + } + gw.GetAccount.Return(acc, nil) + }) + + di := &DependencyInstaller{ + Gateways: map[string]gateway.Gateway{ + config.EmulatorNetwork.Name: gw.Mock, + config.TestnetNetwork.Name: gw.Mock, + config.MainnetNetwork.Name: gw.Mock, + }, + Logger: logger, + State: state, + SaveState: true, + TargetDir: "", + SkipDeployments: true, + SkipAlias: true, + } + + err := di.AddMany(dependencies) + assert.NoError(t, err, "Failed to add multiple dependencies") + + for _, dep := range dependencies { + filePath := fmt.Sprintf("imports/%s/%s.cdc", dep.Source.Address.String(), dep.Name) + _, err := state.ReaderWriter().ReadFile(filePath) + assert.NoError(t, err, fmt.Sprintf("Failed to read generated file for %s", dep.Name)) + } + }) } diff --git a/install.go b/install.go index 25bbb1ba1..4f1a72500 100644 --- a/install.go +++ b/install.go @@ -29,7 +29,7 @@ import ( "github.com/onflow/flow-cli/internal/command" ) -var installFlags = dependencyManagerFlagsCollection{} +var installFlags = DependencyManagerFlagsCollection{} var installCommand = &command.Command{ Cmd: &cobra.Command{ @@ -50,7 +50,7 @@ func install( ) (result command.Result, err error) { logger.Info("🔄 Installing dependencies from flow.json...") - installer, err := NewDependencyInstaller(logger, state, installFlags) + installer, err := NewDependencyInstaller(logger, state, true, "", installFlags) if err != nil { logger.Error(fmt.Sprintf("Error: %v", err)) return nil, err From 56c4febc8d70609b032f54f865cc07cf43d4c4fd Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Tue, 16 Apr 2024 14:35:04 -0700 Subject: [PATCH 071/101] Move to prompt pkg --- dependencyinstaller.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/dependencyinstaller.go b/dependencyinstaller.go index 14fdb9470..6a4c3ac3c 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -23,14 +23,13 @@ import ( "crypto/sha256" "encoding/hex" "fmt" + "github.com/onflow/flow-cli/internal/prompt" "os" "path/filepath" "github.com/onflow/flow-go/fvm/systemcontracts" flowGo "github.com/onflow/flow-go/model/flow" - "github.com/onflow/flow-cli/internal/util" - "github.com/onflow/flowkit/gateway" "github.com/onflow/flowkit/project" @@ -345,7 +344,7 @@ func (di *DependencyInstaller) handleFoundContract(networkName, contractAddr, as // If no hash, ignore if dependency != nil && dependency.Hash != "" && dependency.Hash != originalContractDataHash { msg := fmt.Sprintf("The latest version of %s is different from the one you have locally. Do you want to update it?", contractName) - if !util.GenericBoolPrompt(msg) { + if !prompt.GenericBoolPrompt(msg) { return nil } } @@ -389,7 +388,7 @@ func (di *DependencyInstaller) handleFoundContract(networkName, contractAddr, as func (di *DependencyInstaller) updateDependencyDeployment(contractName string) error { // Add to deployments // If a deployment already exists for that account, contract, and network, then ignore - raw := util.AddContractToDeploymentPrompt("emulator", *di.State.Accounts(), contractName) + raw := prompt.AddContractToDeploymentPrompt("emulator", *di.State.Accounts(), contractName) if raw != nil { deployment := di.State.Deployments().ByAccountAndNetwork(raw.Account, raw.Network) @@ -419,7 +418,7 @@ func (di *DependencyInstaller) updateDependencyAlias(contractName, aliasNetwork } label := fmt.Sprintf("Enter an alias address for %s on %s if you have one, otherwise leave blank", contractName, missingNetwork) - raw := util.AddressPromptOrEmpty(label, "Invalid alias address") + raw := prompt.AddressPromptOrEmpty(label, "Invalid alias address") if raw != "" { contract, err := di.State.Contracts().ByName(contractName) From 7206c4af2a8184607631ce87904238bbddce4bae Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Tue, 16 Apr 2024 14:41:34 -0700 Subject: [PATCH 072/101] Run go imports fix --- dependencyinstaller.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dependencyinstaller.go b/dependencyinstaller.go index 6a4c3ac3c..d2cee2731 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -23,10 +23,11 @@ import ( "crypto/sha256" "encoding/hex" "fmt" - "github.com/onflow/flow-cli/internal/prompt" "os" "path/filepath" + "github.com/onflow/flow-cli/internal/prompt" + "github.com/onflow/flow-go/fvm/systemcontracts" flowGo "github.com/onflow/flow-go/model/flow" From af4218f6d692467ac8a3423ac04169c3cbabb5ef Mon Sep 17 00:00:00 2001 From: Chase Fleming Date: Mon, 22 Apr 2024 13:34:08 -0700 Subject: [PATCH 073/101] Fix embedded flags issue when running Dependency Manager flags manually (#1530) * Fix embedded flags issue * Run lint fix * Use sconfig * Run goimport fix --------- Co-authored-by: Chase Fleming <1666730+chasefleming@users.noreply.github.com> --- add.go | 20 ++++++++++++++------ dependencyinstaller.go | 15 +++++++++++++++ 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/add.go b/add.go index 40252f0d7..0270016b9 100644 --- a/add.go +++ b/add.go @@ -30,11 +30,13 @@ import ( ) type addFlagsCollection struct { - dependencyManagerFlagsCollection - name string `default:"" flag:"name" info:"Name of the dependency"` + *dependencyManagerFlagsCollection + name string } -var addFlags = addFlagsCollection{} +var addFlags = addFlagsCollection{ + dependencyManagerFlagsCollection: &dependencyManagerFlagsCollection{}, +} var addCommand = &command.Command{ Cmd: &cobra.Command{ @@ -43,8 +45,14 @@ var addCommand = &command.Command{ Example: "flow dependencies add testnet://0afe396ebc8eee65.FlowToken", Args: cobra.ExactArgs(1), }, - Flags: &addFlags, - RunS: add, + RunS: add, +} + +func init() { + // Add common flags. + addFlags.dependencyManagerFlagsCollection.AddToCommand(addCommand.Cmd) + // Add command-specific flags. + addCommand.Cmd.Flags().StringVar(&addFlags.name, "name", "", "Name of the dependency") } func add( @@ -58,7 +66,7 @@ func add( dep := args[0] - installer, err := NewDependencyInstaller(logger, state, addFlags.dependencyManagerFlagsCollection) + installer, err := NewDependencyInstaller(logger, state, *addFlags.dependencyManagerFlagsCollection) if err != nil { logger.Error(fmt.Sprintf("Error: %v", err)) return nil, err diff --git a/dependencyinstaller.go b/dependencyinstaller.go index 610709afd..cf0d6f412 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -26,6 +26,10 @@ import ( "os" "path/filepath" + "github.com/psiemens/sconfig" + + "github.com/spf13/cobra" + "github.com/onflow/flow-go/fvm/systemcontracts" flowGo "github.com/onflow/flow-go/model/flow" @@ -74,6 +78,17 @@ type dependencyManagerFlagsCollection struct { skipAlias bool `default:"false" flag:"skip-alias" info:"Skip prompting for an alias"` } +func (f *dependencyManagerFlagsCollection) AddToCommand(cmd *cobra.Command) { + err := sconfig.New(f). + FromEnvironment(util.EnvPrefix). + BindFlags(cmd.Flags()). + Parse() + + if err != nil { + panic(err) + } +} + type DependencyInstaller struct { Gateways map[string]gateway.Gateway Logger output.Logger From fafd18c32bdeffbfcc018b8af9efe10bcfdf972a Mon Sep 17 00:00:00 2001 From: Chase Fleming Date: Mon, 22 Apr 2024 14:01:50 -0700 Subject: [PATCH 074/101] Merge master into feature branch (#1534) * Bump codecov/codecov-action from 1 to 4 Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 1 to 4. - [Release notes](https://github.com/codecov/codecov-action/releases) - [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/codecov/codecov-action/compare/v1...v4) --- updated-dependencies: - dependency-name: codecov/codecov-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] * Bump actions/add-to-project from 0.4.1 to 0.6.1 Bumps [actions/add-to-project](https://github.com/actions/add-to-project) from 0.4.1 to 0.6.1. - [Release notes](https://github.com/actions/add-to-project/releases) - [Commits](https://github.com/actions/add-to-project/compare/v0.4.1...v0.6.1) --- updated-dependencies: - dependency-name: actions/add-to-project dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Update Flow dependencies to latest version (#1509) * Update to latest Cadence Language Server (#1513) * Bump google.golang.org/grpc from 1.63.0 to 1.63.2 (#1515) Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.63.0 to 1.63.2. - [Release notes](https://github.com/grpc/grpc-go/releases) - [Commits](https://github.com/grpc/grpc-go/compare/v1.63.0...v1.63.2) --- updated-dependencies: - dependency-name: google.golang.org/grpc dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump actions/add-to-project from 0.6.1 to 1.0.1 (#1514) Bumps [actions/add-to-project](https://github.com/actions/add-to-project) from 0.6.1 to 1.0.1. - [Release notes](https://github.com/actions/add-to-project/releases) - [Commits](https://github.com/actions/add-to-project/compare/v0.6.1...v1.0.1) --- updated-dependencies: - dependency-name: actions/add-to-project dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jordan Ribbink * Bump version to v1.17.1 * Fix embedded flags issue when running Dependency Manager flags manually (#1530) * Fix embedded flags issue * Run lint fix * Use sconfig * Run goimport fix --------- Co-authored-by: Chase Fleming <1666730+chasefleming@users.noreply.github.com> * Change flags anme --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jordan Ribbink Co-authored-by: Chase Fleming <1666730+chasefleming@users.noreply.github.com> --- add.go | 20 ++++++++++++++------ dependencyinstaller.go | 20 ++++++++++++++++++-- install.go | 2 +- 3 files changed, 33 insertions(+), 9 deletions(-) diff --git a/add.go b/add.go index 1542628f1..861895489 100644 --- a/add.go +++ b/add.go @@ -30,11 +30,13 @@ import ( ) type addFlagsCollection struct { - DependencyManagerFlagsCollection - name string `default:"" flag:"name" info:"Name of the dependency"` + *Flags + name string } -var addFlags = addFlagsCollection{} +var addFlags = addFlagsCollection{ + Flags: &Flags{}, +} var addCommand = &command.Command{ Cmd: &cobra.Command{ @@ -43,8 +45,14 @@ var addCommand = &command.Command{ Example: "flow dependencies add testnet://0afe396ebc8eee65.FlowToken", Args: cobra.ExactArgs(1), }, - Flags: &addFlags, - RunS: add, + RunS: add, +} + +func init() { + // Add common flags. + addFlags.Flags.AddToCommand(addCommand.Cmd) + // Add command-specific flags. + addCommand.Cmd.Flags().StringVar(&addFlags.name, "name", "", "Name of the dependency") } func add( @@ -58,7 +66,7 @@ func add( dep := args[0] - installer, err := NewDependencyInstaller(logger, state, true, "", addFlags.DependencyManagerFlagsCollection) + installer, err := NewDependencyInstaller(logger, state, true, "", *addFlags.Flags) if err != nil { logger.Error(fmt.Sprintf("Error: %v", err)) return nil, err diff --git a/dependencyinstaller.go b/dependencyinstaller.go index d2cee2731..b6482e7ab 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -26,7 +26,12 @@ import ( "os" "path/filepath" + "github.com/psiemens/sconfig" + "github.com/onflow/flow-cli/internal/prompt" + "github.com/onflow/flow-cli/internal/util" + + "github.com/spf13/cobra" "github.com/onflow/flow-go/fvm/systemcontracts" flowGo "github.com/onflow/flow-go/model/flow" @@ -69,11 +74,22 @@ func (cl *categorizedLogs) LogAll(logger output.Logger) { } } -type DependencyManagerFlagsCollection struct { +type Flags struct { skipDeployments bool `default:"false" flag:"skip-deployments" info:"Skip adding the dependency to deployments"` skipAlias bool `default:"false" flag:"skip-alias" info:"Skip prompting for an alias"` } +func (f *Flags) AddToCommand(cmd *cobra.Command) { + err := sconfig.New(f). + FromEnvironment(util.EnvPrefix). + BindFlags(cmd.Flags()). + Parse() + + if err != nil { + panic(err) + } +} + type DependencyInstaller struct { Gateways map[string]gateway.Gateway Logger output.Logger @@ -86,7 +102,7 @@ type DependencyInstaller struct { } // NewDependencyInstaller creates a new instance of DependencyInstaller -func NewDependencyInstaller(logger output.Logger, state *flowkit.State, saveState bool, targetDir string, flags DependencyManagerFlagsCollection) (*DependencyInstaller, error) { +func NewDependencyInstaller(logger output.Logger, state *flowkit.State, saveState bool, targetDir string, flags Flags) (*DependencyInstaller, error) { emulatorGateway, err := gateway.NewGrpcGateway(config.EmulatorNetwork) if err != nil { return nil, fmt.Errorf("error creating emulator gateway: %v", err) diff --git a/install.go b/install.go index 4f1a72500..53fbbb177 100644 --- a/install.go +++ b/install.go @@ -29,7 +29,7 @@ import ( "github.com/onflow/flow-cli/internal/command" ) -var installFlags = DependencyManagerFlagsCollection{} +var installFlags = Flags{} var installCommand = &command.Command{ Cmd: &cobra.Command{ From de54591fe2d4f6ccd2a88f49800735fbbc16baa9 Mon Sep 17 00:00:00 2001 From: Chase Fleming Date: Wed, 24 Apr 2024 11:20:11 -0700 Subject: [PATCH 075/101] Add message to clarify no updates when none to Dependency Manager (#1536) * Add message to clarify no updates when none to Dependency Manager * Make emojis conditional based on runtime os * Update internal/util/emoji.go Co-authored-by: Jordan Ribbink * Fix go error * Add license to file --------- Co-authored-by: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Co-authored-by: Jordan Ribbink --- add.go | 3 ++- dependencyinstaller.go | 12 ++++++++---- install.go | 3 ++- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/add.go b/add.go index 0270016b9..aa7ba5a96 100644 --- a/add.go +++ b/add.go @@ -20,6 +20,7 @@ package dependencymanager import ( "fmt" + "github.com/onflow/flow-cli/internal/util" "github.com/spf13/cobra" @@ -62,7 +63,7 @@ func add( flow flowkit.Services, state *flowkit.State, ) (result command.Result, err error) { - logger.Info(fmt.Sprintf("🔄 Installing dependencies for %s...", args[0])) + logger.Info(fmt.Sprintf("%s Installing dependencies for %s...", util.PrintEmoji("🔄"), args[0])) dep := args[0] diff --git a/dependencyinstaller.go b/dependencyinstaller.go index cf0d6f412..2f02673f9 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -53,13 +53,13 @@ type categorizedLogs struct { } func (cl *categorizedLogs) LogAll(logger output.Logger) { - logger.Info("📝 Dependency Manager Actions Summary") + logger.Info(util.MessageWithEmojiPrefix("📝", "Dependency Manager Actions Summary")) logger.Info("") // Add a line break after the section if len(cl.fileSystemActions) > 0 { logger.Info("🗃️ File System Actions:") for _, msg := range cl.fileSystemActions { - logger.Info(fmt.Sprintf("✅ %s", msg)) + logger.Info(util.MessageWithEmojiPrefix("✅", msg)) } logger.Info("") // Add a line break after the section } @@ -67,10 +67,14 @@ func (cl *categorizedLogs) LogAll(logger output.Logger) { if len(cl.stateUpdates) > 0 { logger.Info("💾 State Updates:") for _, msg := range cl.stateUpdates { - logger.Info(fmt.Sprintf("✅ %s", msg)) + logger.Info(util.MessageWithEmojiPrefix("✅", msg)) } logger.Info("") // Add a line break after the section } + + if len(cl.fileSystemActions) == 0 && len(cl.stateUpdates) == 0 { + logger.Info(util.MessageWithEmojiPrefix("👍", "Zero changes were made. Everything looks good.")) + } } type dependencyManagerFlagsCollection struct { @@ -305,7 +309,7 @@ func (di *DependencyInstaller) handleFoundContract(networkName, contractAddr, as // If a dependency by this name already exists and its remote source network or address does not match, then give option to stop or continue if dependency != nil && (dependency.Source.NetworkName != networkName || dependency.Source.Address.String() != contractAddr) { - di.Logger.Info(fmt.Sprintf("🚫 A dependency named %s already exists with a different remote source. Please fix the conflict and retry.", assignedName)) + di.Logger.Info(fmt.Sprintf("%s A dependency named %s already exists with a different remote source. Please fix the conflict and retry.", util.PrintEmoji("🚫"), assignedName)) os.Exit(0) return nil } diff --git a/install.go b/install.go index 25bbb1ba1..0145428dc 100644 --- a/install.go +++ b/install.go @@ -20,6 +20,7 @@ package dependencymanager import ( "fmt" + "github.com/onflow/flow-cli/internal/util" "github.com/spf13/cobra" @@ -48,7 +49,7 @@ func install( flow flowkit.Services, state *flowkit.State, ) (result command.Result, err error) { - logger.Info("🔄 Installing dependencies from flow.json...") + logger.Info(util.MessageWithEmojiPrefix("🔄", "Installing dependencies from flow.json...")) installer, err := NewDependencyInstaller(logger, state, installFlags) if err != nil { From bf8915ef2c4c65310d1f572028cddfb24f098a4d Mon Sep 17 00:00:00 2001 From: Jordan Ribbink Date: Wed, 24 Apr 2024 18:20:46 -0700 Subject: [PATCH 076/101] Patch for flags error message (#1539) --- add.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/add.go b/add.go index aa7ba5a96..1bf214326 100644 --- a/add.go +++ b/add.go @@ -20,6 +20,7 @@ package dependencymanager import ( "fmt" + "github.com/onflow/flow-cli/internal/util" "github.com/spf13/cobra" @@ -46,7 +47,8 @@ var addCommand = &command.Command{ Example: "flow dependencies add testnet://0afe396ebc8eee65.FlowToken", Args: cobra.ExactArgs(1), }, - RunS: add, + RunS: add, + Flags: &struct{}{}, } func init() { From 162656b78202858e3fbf507fb1c7f4186b8bfa7b Mon Sep 17 00:00:00 2001 From: Jordan Ribbink Date: Wed, 24 Apr 2024 23:13:07 -0700 Subject: [PATCH 077/101] Use GitHub reports for `is-validated` command (#1529) --- add.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/add.go b/add.go index 22e3a71ac..22a01c78c 100644 --- a/add.go +++ b/add.go @@ -20,6 +20,7 @@ package dependencymanager import ( "fmt" + "github.com/onflow/flow-cli/internal/util" "github.com/spf13/cobra" @@ -46,7 +47,8 @@ var addCommand = &command.Command{ Example: "flow dependencies add testnet://0afe396ebc8eee65.FlowToken", Args: cobra.ExactArgs(1), }, - RunS: add, + RunS: add, + Flags: &struct{}{}, } func init() { From d72fe1fe201278c8577209fec812ee2463d91ea3 Mon Sep 17 00:00:00 2001 From: Chase Fleming Date: Thu, 2 May 2024 11:44:28 -0700 Subject: [PATCH 078/101] Improve emojis across Windows versions in Dependency Manager output headers (#1558) Co-authored-by: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Co-authored-by: Jordan Ribbink --- dependencyinstaller.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dependencyinstaller.go b/dependencyinstaller.go index 2f02673f9..101526bf2 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -57,7 +57,7 @@ func (cl *categorizedLogs) LogAll(logger output.Logger) { logger.Info("") // Add a line break after the section if len(cl.fileSystemActions) > 0 { - logger.Info("🗃️ File System Actions:") + logger.Info(util.MessageWithEmojiPrefix("🗃️", "File System Actions:")) for _, msg := range cl.fileSystemActions { logger.Info(util.MessageWithEmojiPrefix("✅", msg)) } @@ -65,7 +65,7 @@ func (cl *categorizedLogs) LogAll(logger output.Logger) { } if len(cl.stateUpdates) > 0 { - logger.Info("💾 State Updates:") + logger.Info(util.MessageWithEmojiPrefix("💾", "State Updates:")) for _, msg := range cl.stateUpdates { logger.Info(util.MessageWithEmojiPrefix("✅", msg)) } From c88150e3de30e2f2e78dc8cd8cf9b9f7498ceec6 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Thu, 2 May 2024 13:51:36 -0700 Subject: [PATCH 079/101] Add message if conflicting contract on dependency install --- dependencyinstaller.go | 48 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 41 insertions(+), 7 deletions(-) diff --git a/dependencyinstaller.go b/dependencyinstaller.go index 101526bf2..5faebe292 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -50,6 +50,7 @@ import ( type categorizedLogs struct { fileSystemActions []string stateUpdates []string + issues []string } func (cl *categorizedLogs) LogAll(logger output.Logger) { @@ -59,7 +60,7 @@ func (cl *categorizedLogs) LogAll(logger output.Logger) { if len(cl.fileSystemActions) > 0 { logger.Info(util.MessageWithEmojiPrefix("🗃️", "File System Actions:")) for _, msg := range cl.fileSystemActions { - logger.Info(util.MessageWithEmojiPrefix("✅", msg)) + logger.Info(msg) } logger.Info("") // Add a line break after the section } @@ -67,11 +68,19 @@ func (cl *categorizedLogs) LogAll(logger output.Logger) { if len(cl.stateUpdates) > 0 { logger.Info(util.MessageWithEmojiPrefix("💾", "State Updates:")) for _, msg := range cl.stateUpdates { - logger.Info(util.MessageWithEmojiPrefix("✅", msg)) + logger.Info(msg) } logger.Info("") // Add a line break after the section } + if len(cl.issues) > 0 { + logger.Info(util.MessageWithEmojiPrefix("⚠️", "Issues:")) + for _, msg := range cl.issues { + logger.Info(msg) + } + logger.Info("") + } + if len(cl.fileSystemActions) == 0 && len(cl.stateUpdates) == 0 { logger.Info(util.MessageWithEmojiPrefix("👍", "Zero changes were made. Everything looks good.")) } @@ -280,7 +289,8 @@ func (di *DependencyInstaller) handleFileSystem(contractAddr, contractName, cont return fmt.Errorf("failed to create contract file: %w", err) } - di.logs.fileSystemActions = append(di.logs.fileSystemActions, fmt.Sprintf("%s from %s on %s installed", contractName, contractAddr, networkName)) + msg := util.MessageWithEmojiPrefix("✅️", fmt.Sprintf("Contract %s from %s on %s installed", contractName, contractAddr, networkName)) + di.logs.fileSystemActions = append(di.logs.fileSystemActions, msg) } return nil @@ -297,6 +307,20 @@ func isCoreContract(contractName string) bool { return false } +// checkForContractConflicts checks if a contract with the same name already exists in the state and adds a warning +func (di *DependencyInstaller) checkForContractConflicts(contractName string) error { + _, err := di.State.Contracts().ByName(contractName) + if err != nil { + return nil + } else { + if !isCoreContract(contractName) { + msg := util.MessageWithEmojiPrefix("❌", fmt.Sprintf("Contract named %s already exists in flow.json", contractName)) + di.logs.issues = append(di.logs.issues, msg) + } + return nil + } +} + func (di *DependencyInstaller) handleFoundContract(networkName, contractAddr, assignedName, contractName string, program *project.Program) error { hash := sha256.New() hash.Write(program.CodeWithUnprocessedImports()) @@ -324,7 +348,14 @@ func (di *DependencyInstaller) handleFoundContract(networkName, contractAddr, as } } - err := di.handleFileSystem(contractAddr, contractName, contractData, networkName) + //// This needs to happen before dependency state is updated + err := di.checkForContractConflicts(assignedName) + if err != nil { + di.Logger.Error(fmt.Sprintf("Error checking for contract conflicts: %v", err)) + return err + } + + err = di.handleFileSystem(contractAddr, contractName, contractData, networkName) if err != nil { return fmt.Errorf("error handling file system: %w", err) } @@ -343,7 +374,8 @@ func (di *DependencyInstaller) handleFoundContract(networkName, contractAddr, as return err } - di.logs.stateUpdates = append(di.logs.stateUpdates, fmt.Sprintf("%s added to emulator deployments", contractName)) + msg := util.MessageWithEmojiPrefix("✅", fmt.Sprintf("%s added to emulator deployments", contractName)) + di.logs.stateUpdates = append(di.logs.stateUpdates, msg) } // If the contract is not a core contract and the user does not want to skip aliasing, then prompt for an alias @@ -354,7 +386,8 @@ func (di *DependencyInstaller) handleFoundContract(networkName, contractAddr, as return err } - di.logs.stateUpdates = append(di.logs.stateUpdates, fmt.Sprintf("Alias added for %s on %s", contractName, networkName)) + msg := util.MessageWithEmojiPrefix("✅", fmt.Sprintf("Alias added for %s on %s", contractName, networkName)) + di.logs.stateUpdates = append(di.logs.stateUpdates, msg) } return nil @@ -424,7 +457,8 @@ func (di *DependencyInstaller) updateDependencyState(networkName, contractAddres di.State.Contracts().AddDependencyAsContract(dep, networkName) if isNewDep { - di.logs.stateUpdates = append(di.logs.stateUpdates, fmt.Sprintf("%s added to flow.json", dep.Name)) + msg := util.MessageWithEmojiPrefix("✅", fmt.Sprintf("%s added to flow.json", dep.Name)) + di.logs.stateUpdates = append(di.logs.stateUpdates, msg) } return nil From 795785e6f9aa9aeea3475bd458394216c5354d0c Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Fri, 3 May 2024 10:38:32 -0700 Subject: [PATCH 080/101] Run goimport fix --- install.go | 1 + 1 file changed, 1 insertion(+) diff --git a/install.go b/install.go index 7efad4f9f..261a5535c 100644 --- a/install.go +++ b/install.go @@ -20,6 +20,7 @@ package dependencymanager import ( "fmt" + "github.com/onflow/flow-cli/internal/util" "github.com/spf13/cobra" From 98aa2044a2c06a9efd59c92a65ceb24b534f4dc0 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Mon, 6 May 2024 15:50:26 -0700 Subject: [PATCH 081/101] Run goimports fix --- install.go | 1 + 1 file changed, 1 insertion(+) diff --git a/install.go b/install.go index 0145428dc..a5589e04f 100644 --- a/install.go +++ b/install.go @@ -20,6 +20,7 @@ package dependencymanager import ( "fmt" + "github.com/onflow/flow-cli/internal/util" "github.com/spf13/cobra" From 70849fbd58e76ce437fd3c3b0a85e9d5ad1125a8 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Tue, 14 May 2024 14:34:53 -0700 Subject: [PATCH 082/101] Upgrade deps --- install.go | 1 + 1 file changed, 1 insertion(+) diff --git a/install.go b/install.go index ebc71c9e6..ecb3a0e2e 100644 --- a/install.go +++ b/install.go @@ -20,6 +20,7 @@ package dependencymanager import ( "fmt" + "github.com/onflow/flow-cli/internal/util" "github.com/spf13/cobra" From 3498fd10df41407ef68b370139fd21ea5f14f982 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Wed, 15 May 2024 10:39:12 -0700 Subject: [PATCH 083/101] Only ask for deployments and aliases once --- dependencyinstaller.go | 99 ++++++++++++++++++++++++++++-------------- 1 file changed, 66 insertions(+), 33 deletions(-) diff --git a/dependencyinstaller.go b/dependencyinstaller.go index 5faebe292..d60b51e8f 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -102,13 +102,20 @@ func (f *dependencyManagerFlagsCollection) AddToCommand(cmd *cobra.Command) { } } +type dependency struct { + address flowsdk.Address + name string +} + type DependencyInstaller struct { - Gateways map[string]gateway.Gateway - Logger output.Logger - State *flowkit.State - SkipDeployments bool - SkipAlias bool - logs categorizedLogs + Gateways map[string]gateway.Gateway + Logger output.Logger + State *flowkit.State + SkipDeployments bool + SkipAlias bool + logs categorizedLogs + initialContractsState config.Contracts + dependencies map[string]dependency } // NewDependencyInstaller creates a new instance of DependencyInstaller @@ -135,11 +142,13 @@ func NewDependencyInstaller(logger output.Logger, state *flowkit.State, flags de } return &DependencyInstaller{ - Gateways: gateways, - Logger: logger, - State: state, - SkipDeployments: flags.skipDeployments, - SkipAlias: flags.skipAlias, + Gateways: gateways, + Logger: logger, + State: state, + SkipDeployments: flags.skipDeployments, + SkipAlias: flags.skipAlias, + initialContractsState: *state.Contracts(), // Copy at this point in time + dependencies: make(map[string]dependency), }, nil } @@ -152,6 +161,8 @@ func (di *DependencyInstaller) Install() error { } } + di.handleClosingTasks() + err := di.State.SaveDefault() if err != nil { return fmt.Errorf("error saving state: %w", err) @@ -188,6 +199,8 @@ func (di *DependencyInstaller) Add(depSource, customName string) error { return fmt.Errorf("error processing dependency: %w", err) } + di.handleClosingTasks() + err = di.State.SaveDefault() if err != nil { return fmt.Errorf("error saving state: %w", err) @@ -198,12 +211,40 @@ func (di *DependencyInstaller) Add(depSource, customName string) error { return nil } +func (di *DependencyInstaller) addDependency(dep dependency) error { + if _, exists := di.dependencies[dep.address.String()]; exists { + return nil + } + + di.dependencies[dep.address.String()] = dep + + return nil + +} + +func (di *DependencyInstaller) handleClosingTasks() { + for _, dependency := range di.dependencies { + _, err := di.initialContractsState.ByName(dependency.name) + if err != nil { + if !isCoreContract(dependency.name) { + msg := util.MessageWithEmojiPrefix("❌", fmt.Sprintf("Contract named %s already exists in flow.json", dependency.name)) + di.logs.issues = append(di.logs.issues, msg) + } + } + } +} + func (di *DependencyInstaller) processDependency(dependency config.Dependency) error { depAddress := flowsdk.HexToAddress(dependency.Source.Address.String()) return di.fetchDependencies(dependency.Source.NetworkName, depAddress, dependency.Name, dependency.Source.ContractName) } func (di *DependencyInstaller) fetchDependencies(networkName string, address flowsdk.Address, assignedName, contractName string) error { + err := di.addDependency(dependency{ + address: address, + name: assignedName, + }) + ctx := context.Background() account, err := di.Gateways[networkName].GetAccount(ctx, address) if err != nil { @@ -307,20 +348,6 @@ func isCoreContract(contractName string) bool { return false } -// checkForContractConflicts checks if a contract with the same name already exists in the state and adds a warning -func (di *DependencyInstaller) checkForContractConflicts(contractName string) error { - _, err := di.State.Contracts().ByName(contractName) - if err != nil { - return nil - } else { - if !isCoreContract(contractName) { - msg := util.MessageWithEmojiPrefix("❌", fmt.Sprintf("Contract named %s already exists in flow.json", contractName)) - di.logs.issues = append(di.logs.issues, msg) - } - return nil - } -} - func (di *DependencyInstaller) handleFoundContract(networkName, contractAddr, assignedName, contractName string, program *project.Program) error { hash := sha256.New() hash.Write(program.CodeWithUnprocessedImports()) @@ -348,14 +375,16 @@ func (di *DependencyInstaller) handleFoundContract(networkName, contractAddr, as } } - //// This needs to happen before dependency state is updated - err := di.checkForContractConflicts(assignedName) - if err != nil { - di.Logger.Error(fmt.Sprintf("Error checking for contract conflicts: %v", err)) - return err + // Needs to happen before handleFileSystem + if !di.contractFileExists(contractAddr, contractName) { + err := di.handleAdditionalDependencyTasks(networkName, contractName) + if err != nil { + di.Logger.Error(fmt.Sprintf("Error handling additional dependency tasks: %v", err)) + return err + } } - err = di.handleFileSystem(contractAddr, contractName, contractData, networkName) + err := di.handleFileSystem(contractAddr, contractName, contractData, networkName) if err != nil { return fmt.Errorf("error handling file system: %w", err) } @@ -366,9 +395,13 @@ func (di *DependencyInstaller) handleFoundContract(networkName, contractAddr, as return err } + return nil +} + +func (di *DependencyInstaller) handleAdditionalDependencyTasks(networkName, contractName string) error { // If the contract is not a core contract and the user does not want to skip deployments, then prompt for a deployment if !di.SkipDeployments && !isCoreContract(contractName) { - err = di.updateDependencyDeployment(contractName) + err := di.updateDependencyDeployment(contractName) if err != nil { di.Logger.Error(fmt.Sprintf("Error updating deployment: %v", err)) return err @@ -380,7 +413,7 @@ func (di *DependencyInstaller) handleFoundContract(networkName, contractAddr, as // If the contract is not a core contract and the user does not want to skip aliasing, then prompt for an alias if !di.SkipAlias && !isCoreContract(contractName) { - err = di.updateDependencyAlias(contractName, networkName) + err := di.updateDependencyAlias(contractName, networkName) if err != nil { di.Logger.Error(fmt.Sprintf("Error updating alias: %v", err)) return err From 28df0fc685fbdc9df70c31766345940e62d552b5 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Wed, 15 May 2024 10:44:23 -0700 Subject: [PATCH 084/101] Fix lint issue --- dependencyinstaller.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dependencyinstaller.go b/dependencyinstaller.go index d60b51e8f..3336bc0c7 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -244,6 +244,9 @@ func (di *DependencyInstaller) fetchDependencies(networkName string, address flo address: address, name: assignedName, }) + if err != nil { + return fmt.Errorf("error adding dependency: %w", err) + } ctx := context.Background() account, err := di.Gateways[networkName].GetAccount(ctx, address) From 30d59cb1edb135c9e3d65e1b0921a9fabc4b2543 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Wed, 15 May 2024 10:51:01 -0700 Subject: [PATCH 085/101] Switch to config.Dependency type --- dependencyinstaller.go | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/dependencyinstaller.go b/dependencyinstaller.go index 3336bc0c7..45ff7e55f 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -102,11 +102,6 @@ func (f *dependencyManagerFlagsCollection) AddToCommand(cmd *cobra.Command) { } } -type dependency struct { - address flowsdk.Address - name string -} - type DependencyInstaller struct { Gateways map[string]gateway.Gateway Logger output.Logger @@ -115,7 +110,7 @@ type DependencyInstaller struct { SkipAlias bool logs categorizedLogs initialContractsState config.Contracts - dependencies map[string]dependency + dependencies map[string]config.Dependency } // NewDependencyInstaller creates a new instance of DependencyInstaller @@ -148,7 +143,7 @@ func NewDependencyInstaller(logger output.Logger, state *flowkit.State, flags de SkipDeployments: flags.skipDeployments, SkipAlias: flags.skipAlias, initialContractsState: *state.Contracts(), // Copy at this point in time - dependencies: make(map[string]dependency), + dependencies: make(map[string]config.Dependency), }, nil } @@ -211,12 +206,12 @@ func (di *DependencyInstaller) Add(depSource, customName string) error { return nil } -func (di *DependencyInstaller) addDependency(dep dependency) error { - if _, exists := di.dependencies[dep.address.String()]; exists { +func (di *DependencyInstaller) addDependency(dep config.Dependency) error { + if _, exists := di.dependencies[dep.Source.Address.String()]; exists { return nil } - di.dependencies[dep.address.String()] = dep + di.dependencies[dep.Source.Address.String()] = dep return nil @@ -224,10 +219,10 @@ func (di *DependencyInstaller) addDependency(dep dependency) error { func (di *DependencyInstaller) handleClosingTasks() { for _, dependency := range di.dependencies { - _, err := di.initialContractsState.ByName(dependency.name) + _, err := di.initialContractsState.ByName(dependency.Name) if err != nil { - if !isCoreContract(dependency.name) { - msg := util.MessageWithEmojiPrefix("❌", fmt.Sprintf("Contract named %s already exists in flow.json", dependency.name)) + if !isCoreContract(dependency.Name) { + msg := util.MessageWithEmojiPrefix("❌", fmt.Sprintf("Contract named %s already exists in flow.json", dependency.Name)) di.logs.issues = append(di.logs.issues, msg) } } @@ -240,9 +235,13 @@ func (di *DependencyInstaller) processDependency(dependency config.Dependency) e } func (di *DependencyInstaller) fetchDependencies(networkName string, address flowsdk.Address, assignedName, contractName string) error { - err := di.addDependency(dependency{ - address: address, - name: assignedName, + err := di.addDependency(config.Dependency{ + Name: assignedName, + Source: config.Source{ + NetworkName: networkName, + Address: address, + ContractName: contractName, + }, }) if err != nil { return fmt.Errorf("error adding dependency: %w", err) From 3ca288be33f4c6c7c4a5f7003cb030accb036457 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Wed, 15 May 2024 11:00:58 -0700 Subject: [PATCH 086/101] Fix tests --- dependencyinstaller_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dependencyinstaller_test.go b/dependencyinstaller_test.go index 92d64427e..57be1be5c 100644 --- a/dependencyinstaller_test.go +++ b/dependencyinstaller_test.go @@ -78,6 +78,7 @@ func TestDependencyInstallerInstall(t *testing.T) { State: state, SkipDeployments: true, SkipAlias: true, + dependencies: make(map[string]config.Dependency), } err := di.Install() @@ -122,6 +123,7 @@ func TestDependencyInstallerAdd(t *testing.T) { State: state, SkipDeployments: true, SkipAlias: true, + dependencies: make(map[string]config.Dependency), } sourceStr := fmt.Sprintf("emulator://%s.%s", serviceAddress.String(), tests.ContractHelloString.Name) From 081dac50b2189f679250dd6cba63b0d1728ee61b Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Wed, 15 May 2024 11:02:16 -0700 Subject: [PATCH 087/101] Change name --- dependencyinstaller.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dependencyinstaller.go b/dependencyinstaller.go index 45ff7e55f..2c6107eda 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -156,7 +156,7 @@ func (di *DependencyInstaller) Install() error { } } - di.handleClosingTasks() + di.checkForConflictingContracts() err := di.State.SaveDefault() if err != nil { @@ -194,7 +194,7 @@ func (di *DependencyInstaller) Add(depSource, customName string) error { return fmt.Errorf("error processing dependency: %w", err) } - di.handleClosingTasks() + di.checkForConflictingContracts() err = di.State.SaveDefault() if err != nil { @@ -217,7 +217,7 @@ func (di *DependencyInstaller) addDependency(dep config.Dependency) error { } -func (di *DependencyInstaller) handleClosingTasks() { +func (di *DependencyInstaller) checkForConflictingContracts() { for _, dependency := range di.dependencies { _, err := di.initialContractsState.ByName(dependency.Name) if err != nil { From 24aef79b0ab0d4f6433565037ae74a9e3dc26f0a Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Wed, 15 May 2024 12:09:51 -0700 Subject: [PATCH 088/101] Add comment --- dependencyinstaller.go | 1 + 1 file changed, 1 insertion(+) diff --git a/dependencyinstaller.go b/dependencyinstaller.go index 2c6107eda..ad5225e87 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -217,6 +217,7 @@ func (di *DependencyInstaller) addDependency(dep config.Dependency) error { } +// checkForConflictingContracts checks if any of the dependencies conflict with contracts already in the state func (di *DependencyInstaller) checkForConflictingContracts() { for _, dependency := range di.dependencies { _, err := di.initialContractsState.ByName(dependency.Name) From 40a9702882259ba99a30bd4d3aadfb097625b49f Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Wed, 15 May 2024 13:23:49 -0700 Subject: [PATCH 089/101] Fix lint --- dependencyinstaller.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dependencyinstaller.go b/dependencyinstaller.go index 1bfa9d084..378f1b5c7 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -107,8 +107,8 @@ type DependencyInstaller struct { Gateways map[string]gateway.Gateway Logger output.Logger State *flowkit.State - SaveState bool - TargetDir string + SaveState bool + TargetDir string SkipDeployments bool SkipAlias bool logs categorizedLogs @@ -143,8 +143,8 @@ func NewDependencyInstaller(logger output.Logger, state *flowkit.State, saveStat Gateways: gateways, Logger: logger, State: state, - SaveState: saveState, - TargetDir: targetDir, + SaveState: saveState, + TargetDir: targetDir, SkipDeployments: flags.skipDeployments, SkipAlias: flags.skipAlias, initialContractsState: *state.Contracts(), // Copy at this point in time From c4449924abee0790b5f70bb342533a740a8219c6 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Wed, 15 May 2024 14:47:28 -0700 Subject: [PATCH 090/101] Fix contract conflict checking --- dependencyinstaller.go | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/dependencyinstaller.go b/dependencyinstaller.go index ad5225e87..e34fc9cb7 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -207,25 +207,24 @@ func (di *DependencyInstaller) Add(depSource, customName string) error { } func (di *DependencyInstaller) addDependency(dep config.Dependency) error { - if _, exists := di.dependencies[dep.Source.Address.String()]; exists { + sourceString := fmt.Sprintf("%s://%s.%s", dep.Source.NetworkName, dep.Source.Address.String(), dep.Source.ContractName) + + if _, exists := di.dependencies[sourceString]; exists { return nil } - di.dependencies[dep.Source.Address.String()] = dep + di.dependencies[sourceString] = dep return nil - } // checkForConflictingContracts checks if any of the dependencies conflict with contracts already in the state func (di *DependencyInstaller) checkForConflictingContracts() { for _, dependency := range di.dependencies { - _, err := di.initialContractsState.ByName(dependency.Name) - if err != nil { - if !isCoreContract(dependency.Name) { - msg := util.MessageWithEmojiPrefix("❌", fmt.Sprintf("Contract named %s already exists in flow.json", dependency.Name)) - di.logs.issues = append(di.logs.issues, msg) - } + foundContract, _ := di.initialContractsState.ByName(dependency.Name) + if foundContract != nil { + msg := util.MessageWithEmojiPrefix("❌", fmt.Sprintf("Contract named %s already exists in flow.json", dependency.Name)) + di.logs.issues = append(di.logs.issues, msg) } } } From 29821014839b1144beeffc0ffa9e865a6c065e71 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Wed, 15 May 2024 14:54:28 -0700 Subject: [PATCH 091/101] Remove initial contracts property --- dependencyinstaller.go | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/dependencyinstaller.go b/dependencyinstaller.go index e34fc9cb7..23569a4cc 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -103,14 +103,13 @@ func (f *dependencyManagerFlagsCollection) AddToCommand(cmd *cobra.Command) { } type DependencyInstaller struct { - Gateways map[string]gateway.Gateway - Logger output.Logger - State *flowkit.State - SkipDeployments bool - SkipAlias bool - logs categorizedLogs - initialContractsState config.Contracts - dependencies map[string]config.Dependency + Gateways map[string]gateway.Gateway + Logger output.Logger + State *flowkit.State + SkipDeployments bool + SkipAlias bool + logs categorizedLogs + dependencies map[string]config.Dependency } // NewDependencyInstaller creates a new instance of DependencyInstaller @@ -137,13 +136,12 @@ func NewDependencyInstaller(logger output.Logger, state *flowkit.State, flags de } return &DependencyInstaller{ - Gateways: gateways, - Logger: logger, - State: state, - SkipDeployments: flags.skipDeployments, - SkipAlias: flags.skipAlias, - initialContractsState: *state.Contracts(), // Copy at this point in time - dependencies: make(map[string]config.Dependency), + Gateways: gateways, + Logger: logger, + State: state, + SkipDeployments: flags.skipDeployments, + SkipAlias: flags.skipAlias, + dependencies: make(map[string]config.Dependency), }, nil } @@ -221,8 +219,8 @@ func (di *DependencyInstaller) addDependency(dep config.Dependency) error { // checkForConflictingContracts checks if any of the dependencies conflict with contracts already in the state func (di *DependencyInstaller) checkForConflictingContracts() { for _, dependency := range di.dependencies { - foundContract, _ := di.initialContractsState.ByName(dependency.Name) - if foundContract != nil { + foundContract, _ := di.State.Contracts().ByName(dependency.Name) + if foundContract != nil && !foundContract.IsDependency { msg := util.MessageWithEmojiPrefix("❌", fmt.Sprintf("Contract named %s already exists in flow.json", dependency.Name)) di.logs.issues = append(di.logs.issues, msg) } From 8c01af88d3f630ed3626ee2b5e52a7ecf7796e41 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Thu, 16 May 2024 09:51:09 -0700 Subject: [PATCH 092/101] Run goimports fix --- dependencyinstaller.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dependencyinstaller.go b/dependencyinstaller.go index ace34f608..7bffd52f4 100644 --- a/dependencyinstaller.go +++ b/dependencyinstaller.go @@ -107,8 +107,8 @@ type DependencyInstaller struct { Gateways map[string]gateway.Gateway Logger output.Logger State *flowkit.State - SaveState bool - TargetDir string + SaveState bool + TargetDir string SkipDeployments bool SkipAlias bool logs categorizedLogs @@ -142,8 +142,8 @@ func NewDependencyInstaller(logger output.Logger, state *flowkit.State, saveStat Gateways: gateways, Logger: logger, State: state, - SaveState: saveState, - TargetDir: targetDir, + SaveState: saveState, + TargetDir: targetDir, SkipDeployments: flags.skipDeployments, SkipAlias: flags.skipAlias, dependencies: make(map[string]config.Dependency), From 339bae3082bdab18839b2391d881dcf8309531e5 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Thu, 16 May 2024 09:59:52 -0700 Subject: [PATCH 093/101] Fix tests --- dependencyinstaller_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dependencyinstaller_test.go b/dependencyinstaller_test.go index a99932981..b99a1dc50 100644 --- a/dependencyinstaller_test.go +++ b/dependencyinstaller_test.go @@ -166,6 +166,7 @@ func TestDependencyInstallerAdd(t *testing.T) { TargetDir: "", SkipDeployments: true, SkipAlias: true, + dependencies: make(map[string]config.Dependency), } dep := config.Dependency{ @@ -237,6 +238,7 @@ func TestDependencyInstallerAddMany(t *testing.T) { TargetDir: "", SkipDeployments: true, SkipAlias: true, + dependencies: make(map[string]config.Dependency), } err := di.AddMany(dependencies) From 99d1da83dd3427f43ac30bc99a543988ff1b1e23 Mon Sep 17 00:00:00 2001 From: Chase Fleming <1666730+chasefleming@users.noreply.github.com> Date: Wed, 5 Jun 2024 16:28:49 -0700 Subject: [PATCH 094/101] Fix tests --- dependencyinstaller_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dependencyinstaller_test.go b/dependencyinstaller_test.go index 64361b27a..f1a9e56a9 100644 --- a/dependencyinstaller_test.go +++ b/dependencyinstaller_test.go @@ -222,8 +222,8 @@ func TestDependencyInstallerAddMany(t *testing.T) { assert.Equal(t, addr.String(), serviceAddress) acc := tests.NewAccountWithAddress(addr.String()) acc.Contracts = map[string][]byte{ - "ContractOne": []byte("pub contract ContractOne {}"), - "ContractTwo": []byte("pub contract ContractTwo {}"), + "ContractOne": []byte("access(all) contract ContractOne {}"), + "ContractTwo": []byte("access(all) contract ContractTwo {}"), } gw.GetAccount.Return(acc, nil) }) From 8be9b1e79c5a4b172c8f5809d0e776a7a200fb07 Mon Sep 17 00:00:00 2001 From: Bart Date: Sun, 23 Jun 2024 12:43:02 +0200 Subject: [PATCH 095/101] refactor dependency installer --- add.go | 84 ------------------ dependencies.go | 36 -------- install.go | 67 --------------- output/emoji.go | 9 +- .../dependencyinstaller.go | 85 +++++++++---------- .../dependencyinstaller_test.go | 2 +- 6 files changed, 47 insertions(+), 236 deletions(-) delete mode 100644 add.go delete mode 100644 dependencies.go delete mode 100644 install.go rename dependencyinstaller.go => project/dependencyinstaller.go (86%) rename dependencyinstaller_test.go => project/dependencyinstaller_test.go (99%) diff --git a/add.go b/add.go deleted file mode 100644 index 0bae6cf03..000000000 --- a/add.go +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Flow CLI - * - * Copyright 2019 Dapper Labs, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dependencymanager - -import ( - "fmt" - - "github.com/onflow/flow-cli/internal/util" - - "github.com/spf13/cobra" - - "github.com/onflow/flowkit/v2" - "github.com/onflow/flowkit/v2/output" - - "github.com/onflow/flow-cli/internal/command" -) - -type addFlagsCollection struct { - *Flags - name string -} - -var addFlags = addFlagsCollection{ - Flags: &Flags{}, -} - -var addCommand = &command.Command{ - Cmd: &cobra.Command{ - Use: "add ", - Short: "Add a single contract and its dependencies.", - Example: "flow dependencies add testnet://0afe396ebc8eee65.FlowToken", - Args: cobra.ExactArgs(1), - }, - RunS: add, - Flags: &struct{}{}, -} - -func init() { - // Add common flags. - addFlags.Flags.AddToCommand(addCommand.Cmd) - // Add command-specific flags. - addCommand.Cmd.Flags().StringVar(&addFlags.name, "name", "", "Name of the dependency") -} - -func add( - args []string, - _ command.GlobalFlags, - logger output.Logger, - flow flowkit.Services, - state *flowkit.State, -) (result command.Result, err error) { - logger.Info(fmt.Sprintf("%s Installing dependencies for %s...", util.PrintEmoji("🔄"), args[0])) - - dep := args[0] - - installer, err := NewDependencyInstaller(logger, state, true, "", *addFlags.Flags) - if err != nil { - logger.Error(fmt.Sprintf("Error: %v", err)) - return nil, err - } - - if err := installer.AddBySourceString(dep, addFlags.name); err != nil { - logger.Error(fmt.Sprintf("Error: %v", err)) - return nil, err - } - - return nil, nil -} diff --git a/dependencies.go b/dependencies.go deleted file mode 100644 index 7175b7e9b..000000000 --- a/dependencies.go +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Flow CLI - * - * Copyright 2019 Dapper Labs, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dependencymanager - -import ( - "github.com/spf13/cobra" -) - -var Cmd = &cobra.Command{ - Use: "dependencies", - Short: "Manage contracts and dependencies", - TraverseChildren: true, - GroupID: "manager", - Aliases: []string{"deps"}, -} - -func init() { - addCommand.AddToParent(Cmd) - installCommand.AddToParent(Cmd) -} diff --git a/install.go b/install.go deleted file mode 100644 index a73abf53c..000000000 --- a/install.go +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Flow CLI - * - * Copyright 2019 Dapper Labs, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dependencymanager - -import ( - "fmt" - - "github.com/onflow/flow-cli/internal/util" - - "github.com/spf13/cobra" - - "github.com/onflow/flowkit/v2" - "github.com/onflow/flowkit/v2/output" - - "github.com/onflow/flow-cli/internal/command" -) - -var installFlags = Flags{} - -var installCommand = &command.Command{ - Cmd: &cobra.Command{ - Use: "install", - Short: "Install contract and dependencies.", - Example: "flow dependencies install", - }, - Flags: &installFlags, - RunS: install, -} - -func install( - _ []string, - _ command.GlobalFlags, - logger output.Logger, - flow flowkit.Services, - state *flowkit.State, -) (result command.Result, err error) { - logger.Info(util.MessageWithEmojiPrefix("🔄", "Installing dependencies from flow.json...")) - - installer, err := NewDependencyInstaller(logger, state, true, "", installFlags) - if err != nil { - logger.Error(fmt.Sprintf("Error: %v", err)) - return nil, err - } - - if err := installer.Install(); err != nil { - logger.Error(fmt.Sprintf("Error: %v", err)) - return nil, err - } - - return nil, nil -} diff --git a/output/emoji.go b/output/emoji.go index 0dc5035eb..f27c8e87a 100644 --- a/output/emoji.go +++ b/output/emoji.go @@ -18,7 +18,10 @@ package output -import "runtime" +import ( + "fmt" + "runtime" +) func printEmoji(emoji string) string { if runtime.GOOS == "windows" { @@ -59,3 +62,7 @@ func OkEmoji() string { func SuccessEmoji() string { return printEmoji("🎉") } + +func MessageWithEmojiPrefix(emoji string, message string) string { + return fmt.Sprintf("%s%s", printEmoji(emoji+" "), message) +} diff --git a/dependencyinstaller.go b/project/dependencyinstaller.go similarity index 86% rename from dependencyinstaller.go rename to project/dependencyinstaller.go index ab54c6655..5d748a0f7 100644 --- a/dependencyinstaller.go +++ b/project/dependencyinstaller.go @@ -16,35 +16,27 @@ * limitations under the License. */ -package dependencymanager +package project import ( "context" "crypto/sha256" "encoding/hex" "fmt" - "os" - "path/filepath" - - "github.com/psiemens/sconfig" - - "github.com/onflow/flow-cli/internal/prompt" - "github.com/onflow/flow-cli/internal/util" + "github.com/onflow/flowkit/v2" + "github.com/onflow/flowkit/v2/accounts" - "github.com/spf13/cobra" + "path/filepath" "github.com/onflow/flow-go/fvm/systemcontracts" flowGo "github.com/onflow/flow-go/model/flow" "github.com/onflow/flowkit/v2/gateway" - "github.com/onflow/flowkit/v2/project" - flowsdk "github.com/onflow/flow-go-sdk" "github.com/onflow/flowkit/v2/config" - "github.com/onflow/flowkit/v2" "github.com/onflow/flowkit/v2/output" ) @@ -55,11 +47,11 @@ type categorizedLogs struct { } func (cl *categorizedLogs) LogAll(logger output.Logger) { - logger.Info(util.MessageWithEmojiPrefix("📝", "Dependency Manager Actions Summary")) + logger.Info(output.MessageWithEmojiPrefix("📝", "Dependency Manager Actions Summary")) logger.Info("") // Add a line break after the section if len(cl.fileSystemActions) > 0 { - logger.Info(util.MessageWithEmojiPrefix("🗃️", "File System Actions:")) + logger.Info(output.MessageWithEmojiPrefix("🗃️", "File System Actions:")) for _, msg := range cl.fileSystemActions { logger.Info(msg) } @@ -67,7 +59,7 @@ func (cl *categorizedLogs) LogAll(logger output.Logger) { } if len(cl.stateUpdates) > 0 { - logger.Info(util.MessageWithEmojiPrefix("💾", "State Updates:")) + logger.Info(output.MessageWithEmojiPrefix("💾", "State Updates:")) for _, msg := range cl.stateUpdates { logger.Info(msg) } @@ -75,7 +67,7 @@ func (cl *categorizedLogs) LogAll(logger output.Logger) { } if len(cl.issues) > 0 { - logger.Info(util.MessageWithEmojiPrefix("⚠️", "Issues:")) + logger.Info(output.MessageWithEmojiPrefix("⚠️", "Issues:")) for _, msg := range cl.issues { logger.Info(msg) } @@ -83,23 +75,7 @@ func (cl *categorizedLogs) LogAll(logger output.Logger) { } if len(cl.fileSystemActions) == 0 && len(cl.stateUpdates) == 0 { - logger.Info(util.MessageWithEmojiPrefix("👍", "Zero changes were made. Everything looks good.")) - } -} - -type Flags struct { - skipDeployments bool `default:"false" flag:"skip-deployments" info:"Skip adding the dependency to deployments"` - skipAlias bool `default:"false" flag:"skip-alias" info:"Skip prompting for an alias"` -} - -func (f *Flags) AddToCommand(cmd *cobra.Command) { - err := sconfig.New(f). - FromEnvironment(util.EnvPrefix). - BindFlags(cmd.Flags()). - Parse() - - if err != nil { - panic(err) + logger.Info(output.MessageWithEmojiPrefix("👍", "Zero changes were made. Everything looks good.")) } } @@ -113,6 +89,24 @@ type DependencyInstaller struct { SkipAlias bool logs categorizedLogs dependencies map[string]config.Dependency + prompter Prompter +} + +type DeploymentData struct { + Network string + Account string + Contracts []string +} + +type Prompter interface { + ShouldUpdateDependency(contractName string) bool + AddContractToDeployment(networkName string, accounts accounts.Accounts, contractName string) *DeploymentData + AddressPromptOrEmpty(label, errorMessage string) string +} + +type Flags struct { + skipDeployments bool + skipAlias bool } // NewDependencyInstaller creates a new instance of DependencyInstaller @@ -273,7 +267,7 @@ func (di *DependencyInstaller) checkForConflictingContracts() { for _, dependency := range di.dependencies { foundContract, _ := di.State.Contracts().ByName(dependency.Name) if foundContract != nil && !foundContract.IsDependency { - msg := util.MessageWithEmojiPrefix("❌", fmt.Sprintf("Contract named %s already exists in flow.json", dependency.Name)) + msg := output.MessageWithEmojiPrefix("❌", fmt.Sprintf("Contract named %s already exists in flow.json", dependency.Name)) di.logs.issues = append(di.logs.issues, msg) } } @@ -313,7 +307,7 @@ func (di *DependencyInstaller) fetchDependencies(networkName string, address flo found := false for _, contract := range account.Contracts { - program, err := project.NewProgram(contract, nil, "") + program, err := NewProgram(contract, nil, "") if err != nil { return fmt.Errorf("failed to parse program: %w", err) } @@ -382,7 +376,7 @@ func (di *DependencyInstaller) handleFileSystem(contractAddr, contractName, cont return fmt.Errorf("failed to create contract file: %w", err) } - msg := util.MessageWithEmojiPrefix("✅️", fmt.Sprintf("Contract %s from %s on %s installed", contractName, contractAddr, networkName)) + msg := output.MessageWithEmojiPrefix("✅️", fmt.Sprintf("Contract %s from %s on %s installed", contractName, contractAddr, networkName)) di.logs.fileSystemActions = append(di.logs.fileSystemActions, msg) } @@ -400,7 +394,7 @@ func isCoreContract(contractName string) bool { return false } -func (di *DependencyInstaller) handleFoundContract(networkName, contractAddr, assignedName, contractName string, program *project.Program) error { +func (di *DependencyInstaller) handleFoundContract(networkName, contractAddr, assignedName, contractName string, program *Program) error { hash := sha256.New() hash.Write(program.CodeWithUnprocessedImports()) originalContractDataHash := hex.EncodeToString(hash.Sum(nil)) @@ -412,17 +406,14 @@ func (di *DependencyInstaller) handleFoundContract(networkName, contractAddr, as // If a dependency by this name already exists and its remote source network or address does not match, then give option to stop or continue if dependency != nil && (dependency.Source.NetworkName != networkName || dependency.Source.Address.String() != contractAddr) { - di.Logger.Info(fmt.Sprintf("%s A dependency named %s already exists with a different remote source. Please fix the conflict and retry.", util.PrintEmoji("🚫"), assignedName)) - os.Exit(0) - return nil + return fmt.Errorf("dependency named %s already exists with a different remote source, please fix the conflict and retry", assignedName) } // Check if remote source version is different from local version // If it is, ask if they want to update // If no hash, ignore if dependency != nil && dependency.Hash != "" && dependency.Hash != originalContractDataHash { - msg := fmt.Sprintf("The latest version of %s is different from the one you have locally. Do you want to update it?", contractName) - if !prompt.GenericBoolPrompt(msg) { + if !di.prompter.ShouldUpdateDependency(contractName) { return nil } } @@ -459,7 +450,7 @@ func (di *DependencyInstaller) handleAdditionalDependencyTasks(networkName, cont return err } - msg := util.MessageWithEmojiPrefix("✅", fmt.Sprintf("%s added to emulator deployments", contractName)) + msg := output.MessageWithEmojiPrefix("✅", fmt.Sprintf("%s added to emulator deployments", contractName)) di.logs.stateUpdates = append(di.logs.stateUpdates, msg) } @@ -471,7 +462,7 @@ func (di *DependencyInstaller) handleAdditionalDependencyTasks(networkName, cont return err } - msg := util.MessageWithEmojiPrefix("✅", fmt.Sprintf("Alias added for %s on %s", contractName, networkName)) + msg := output.MessageWithEmojiPrefix("✅", fmt.Sprintf("Alias added for %s on %s", contractName, networkName)) di.logs.stateUpdates = append(di.logs.stateUpdates, msg) } @@ -481,7 +472,7 @@ func (di *DependencyInstaller) handleAdditionalDependencyTasks(networkName, cont func (di *DependencyInstaller) updateDependencyDeployment(contractName string) error { // Add to deployments // If a deployment already exists for that account, contract, and network, then ignore - raw := prompt.AddContractToDeploymentPrompt("emulator", *di.State.Accounts(), contractName) + raw := di.prompter.AddContractToDeployment("emulator", *di.State.Accounts(), contractName) if raw != nil { deployment := di.State.Deployments().ByAccountAndNetwork(raw.Account, raw.Network) @@ -511,7 +502,7 @@ func (di *DependencyInstaller) updateDependencyAlias(contractName, aliasNetwork } label := fmt.Sprintf("Enter an alias address for %s on %s if you have one, otherwise leave blank", contractName, missingNetwork) - raw := prompt.AddressPromptOrEmpty(label, "Invalid alias address") + raw := di.prompter.AddressPromptOrEmpty(label, "Invalid alias address") if raw != "" { contract, err := di.State.Contracts().ByName(contractName) @@ -542,7 +533,7 @@ func (di *DependencyInstaller) updateDependencyState(networkName, contractAddres di.State.Contracts().AddDependencyAsContract(dep, networkName) if isNewDep { - msg := util.MessageWithEmojiPrefix("✅", fmt.Sprintf("%s added to flow.json", dep.Name)) + msg := output.MessageWithEmojiPrefix("✅", fmt.Sprintf("%s added to flow.json", dep.Name)) di.logs.stateUpdates = append(di.logs.stateUpdates, msg) } diff --git a/dependencyinstaller_test.go b/project/dependencyinstaller_test.go similarity index 99% rename from dependencyinstaller_test.go rename to project/dependencyinstaller_test.go index f1a9e56a9..fa3a56475 100644 --- a/dependencyinstaller_test.go +++ b/project/dependencyinstaller_test.go @@ -16,7 +16,7 @@ * limitations under the License. */ -package dependencymanager +package project import ( "fmt" From 664d194413817c432bf52da7427738bf1e43c9f1 Mon Sep 17 00:00:00 2001 From: Bart Date: Sun, 23 Jun 2024 12:50:35 +0200 Subject: [PATCH 096/101] fix tests --- {project => deps}/dependencyinstaller.go | 7 +++--- {project => deps}/dependencyinstaller_test.go | 10 ++++---- tests/resources.go | 24 ++++++++++++++++--- 3 files changed, 29 insertions(+), 12 deletions(-) rename {project => deps}/dependencyinstaller.go (98%) rename {project => deps}/dependencyinstaller_test.go (97%) diff --git a/project/dependencyinstaller.go b/deps/dependencyinstaller.go similarity index 98% rename from project/dependencyinstaller.go rename to deps/dependencyinstaller.go index 5d748a0f7..f72edf626 100644 --- a/project/dependencyinstaller.go +++ b/deps/dependencyinstaller.go @@ -16,7 +16,7 @@ * limitations under the License. */ -package project +package deps import ( "context" @@ -25,6 +25,7 @@ import ( "fmt" "github.com/onflow/flowkit/v2" "github.com/onflow/flowkit/v2/accounts" + "github.com/onflow/flowkit/v2/project" "path/filepath" @@ -307,7 +308,7 @@ func (di *DependencyInstaller) fetchDependencies(networkName string, address flo found := false for _, contract := range account.Contracts { - program, err := NewProgram(contract, nil, "") + program, err := project.NewProgram(contract, nil, "") if err != nil { return fmt.Errorf("failed to parse program: %w", err) } @@ -394,7 +395,7 @@ func isCoreContract(contractName string) bool { return false } -func (di *DependencyInstaller) handleFoundContract(networkName, contractAddr, assignedName, contractName string, program *Program) error { +func (di *DependencyInstaller) handleFoundContract(networkName, contractAddr, assignedName, contractName string, program *project.Program) error { hash := sha256.New() hash.Write(program.CodeWithUnprocessedImports()) originalContractDataHash := hex.EncodeToString(hash.Sum(nil)) diff --git a/project/dependencyinstaller_test.go b/deps/dependencyinstaller_test.go similarity index 97% rename from project/dependencyinstaller_test.go rename to deps/dependencyinstaller_test.go index fa3a56475..ef87d88c5 100644 --- a/project/dependencyinstaller_test.go +++ b/deps/dependencyinstaller_test.go @@ -16,7 +16,7 @@ * limitations under the License. */ -package project +package deps import ( "fmt" @@ -31,14 +31,12 @@ import ( "github.com/onflow/flowkit/v2/gateway/mocks" "github.com/onflow/flowkit/v2/output" "github.com/onflow/flowkit/v2/tests" - - "github.com/onflow/flow-cli/internal/util" ) func TestDependencyInstallerInstall(t *testing.T) { logger := output.NewStdoutLogger(output.NoneLog) - _, state, _ := util.TestMocks(t) + _, state, _ := tests.TestMocks(t) serviceAcc, _ := state.EmulatorServiceAccount() serviceAddress := serviceAcc.Address @@ -97,7 +95,7 @@ func TestDependencyInstallerInstall(t *testing.T) { func TestDependencyInstallerAdd(t *testing.T) { logger := output.NewStdoutLogger(output.NoneLog) - _, state, _ := util.TestMocks(t) + _, state, _ := tests.TestMocks(t) serviceAcc, _ := state.EmulatorServiceAccount() serviceAddress := serviceAcc.Address @@ -191,7 +189,7 @@ func TestDependencyInstallerAdd(t *testing.T) { func TestDependencyInstallerAddMany(t *testing.T) { logger := output.NewStdoutLogger(output.NoneLog) - _, state, _ := util.TestMocks(t) + _, state, _ := tests.TestMocks(t) serviceAcc, _ := state.EmulatorServiceAccount() serviceAddress := serviceAcc.Address.String() diff --git a/tests/resources.go b/tests/resources.go index e05f340db..61eb7eb1f 100644 --- a/tests/resources.go +++ b/tests/resources.go @@ -20,6 +20,11 @@ package tests import ( "fmt" + "github.com/onflow/flowkit/v2" + "github.com/onflow/flowkit/v2/accounts" + "github.com/onflow/flowkit/v2/mocks" + "github.com/stretchr/testify/require" + "testing" "github.com/onflow/cadence" "github.com/onflow/cadence/runtime/common" @@ -571,20 +576,20 @@ func HashAlgos() []crypto.HashAlgorithm { return hashAlgos } -var accounts = test.AccountGenerator() +var accountGenerator = test.AccountGenerator() var transactions = test.TransactionGenerator() var transactionResults = test.TransactionResultGenerator(entities.EventEncodingVersion_CCF_V0) func NewAccountWithAddress(address string) *flow.Account { - account := accounts.New() + account := accountGenerator.New() account.Address = flow.HexToAddress(address) return account } func NewAccountWithContracts(address string, contracts ...Resource) *flow.Account { - account := accounts.New() + account := accountGenerator.New() account.Address = flow.HexToAddress(address) if account.Contracts == nil { @@ -663,3 +668,16 @@ func NewAccountCreateResult(address flow.Address) *flow.TransactionResult { return NewTransactionResult(events) } + +// TestMocks creates mock flowkit services, an empty state and a mock reader writer +func TestMocks(t *testing.T) (*mocks.MockServices, *flowkit.State, flowkit.ReaderWriter) { + services := mocks.DefaultMockServices() + rw, _ := ReaderWriter() + state, err := flowkit.Init(rw) + require.NoError(t, err) + + emulatorAccount, _ := accounts.NewEmulatorAccount(rw, crypto.ECDSA_P256, crypto.SHA3_256, "") + state.Accounts().AddOrUpdate(emulatorAccount) + + return services, state, rw +} From c0604188301b9f11f6868b58c24fa1160f22af98 Mon Sep 17 00:00:00 2001 From: Bart Date: Sun, 23 Jun 2024 12:57:44 +0200 Subject: [PATCH 097/101] nit: lowercase function name --- deps/dependencyinstaller.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/deps/dependencyinstaller.go b/deps/dependencyinstaller.go index f72edf626..9a250fd1c 100644 --- a/deps/dependencyinstaller.go +++ b/deps/dependencyinstaller.go @@ -47,7 +47,7 @@ type categorizedLogs struct { issues []string } -func (cl *categorizedLogs) LogAll(logger output.Logger) { +func (cl *categorizedLogs) logAll(logger output.Logger) { logger.Info(output.MessageWithEmojiPrefix("📝", "Dependency Manager Actions Summary")) logger.Info("") // Add a line break after the section @@ -177,7 +177,7 @@ func (di *DependencyInstaller) Install() error { return fmt.Errorf("error saving state: %w", err) } - di.logs.LogAll(di.Logger) + di.logs.logAll(di.Logger) return nil } @@ -214,7 +214,7 @@ func (di *DependencyInstaller) AddBySourceString(depSource, customName string) e return err } - di.logs.LogAll(di.Logger) + di.logs.logAll(di.Logger) return nil } @@ -229,7 +229,7 @@ func (di *DependencyInstaller) Add(dep config.Dependency) error { return err } - di.logs.LogAll(di.Logger) + di.logs.logAll(di.Logger) return nil } @@ -246,7 +246,7 @@ func (di *DependencyInstaller) AddMany(dependencies []config.Dependency) error { return err } - di.logs.LogAll(di.Logger) + di.logs.logAll(di.Logger) return nil } From 1b9106852e5eb8b27a94de88daaa70e07c0a9242 Mon Sep 17 00:00:00 2001 From: Bart Date: Mon, 24 Jun 2024 13:40:59 +0200 Subject: [PATCH 098/101] refactor api, fix tests --- deps/dependencyinstaller.go | 59 ++++++++++++++++++++++++++------ deps/dependencyinstaller_test.go | 34 +++++++++++++----- tests/resources.go | 19 ---------- 3 files changed, 75 insertions(+), 37 deletions(-) diff --git a/deps/dependencyinstaller.go b/deps/dependencyinstaller.go index 9a250fd1c..76949995f 100644 --- a/deps/dependencyinstaller.go +++ b/deps/dependencyinstaller.go @@ -106,12 +106,44 @@ type Prompter interface { } type Flags struct { - skipDeployments bool - skipAlias bool + SkipDeployments bool + SkipAlias bool +} + +type Option func(*DependencyInstaller) + +func WithLogger(logger output.Logger) Option { + return func(installer *DependencyInstaller) { + installer.Logger = logger + } +} + +func WithSaveState() Option { + return func(installer *DependencyInstaller) { + installer.SaveState = true + } +} + +func WithTargetDir(targetDir string) Option { + return func(installer *DependencyInstaller) { + installer.TargetDir = targetDir + } +} + +func WithSkippedDeployments() Option { + return func(installer *DependencyInstaller) { + installer.SkipDeployments = true + } +} + +func WithSkippedAlias() Option { + return func(installer *DependencyInstaller) { + installer.SkipAlias = true + } } // NewDependencyInstaller creates a new instance of DependencyInstaller -func NewDependencyInstaller(logger output.Logger, state *flowkit.State, saveState bool, targetDir string, flags Flags) (*DependencyInstaller, error) { +func NewDependencyInstaller(state *flowkit.State, prompter Prompter, options ...Option) (*DependencyInstaller, error) { emulatorGateway, err := gateway.NewGrpcGateway(config.EmulatorNetwork) if err != nil { return nil, fmt.Errorf("error creating emulator gateway: %v", err) @@ -139,16 +171,23 @@ func NewDependencyInstaller(logger output.Logger, state *flowkit.State, saveStat config.PreviewnetNetwork.Name: previewnetGateway, } - return &DependencyInstaller{ + installer := &DependencyInstaller{ Gateways: gateways, - Logger: logger, + Logger: output.NewStdoutLogger(output.InfoLog), State: state, - SaveState: saveState, - TargetDir: targetDir, - SkipDeployments: flags.skipDeployments, - SkipAlias: flags.skipAlias, + SaveState: false, + TargetDir: "", + SkipDeployments: false, + SkipAlias: false, dependencies: make(map[string]config.Dependency), - }, nil + prompter: prompter, + } + + for _, opt := range options { + opt(installer) + } + + return installer, nil } // saveState checks the SaveState flag and saves the state if set to true. diff --git a/deps/dependencyinstaller_test.go b/deps/dependencyinstaller_test.go index ef87d88c5..01ab10188 100644 --- a/deps/dependencyinstaller_test.go +++ b/deps/dependencyinstaller_test.go @@ -20,6 +20,10 @@ package deps import ( "fmt" + "github.com/onflow/flow-go-sdk/crypto" + "github.com/onflow/flowkit/v2" + "github.com/onflow/flowkit/v2/accounts" + "github.com/stretchr/testify/require" "testing" "github.com/onflow/flow-go-sdk" @@ -28,7 +32,8 @@ import ( "github.com/onflow/flowkit/v2/config" "github.com/onflow/flowkit/v2/gateway" - "github.com/onflow/flowkit/v2/gateway/mocks" + gatewayMocks "github.com/onflow/flowkit/v2/gateway/mocks" + "github.com/onflow/flowkit/v2/mocks" "github.com/onflow/flowkit/v2/output" "github.com/onflow/flowkit/v2/tests" ) @@ -36,7 +41,7 @@ import ( func TestDependencyInstallerInstall(t *testing.T) { logger := output.NewStdoutLogger(output.NoneLog) - _, state, _ := tests.TestMocks(t) + _, state, _ := newTestMocks(t) serviceAcc, _ := state.EmulatorServiceAccount() serviceAddress := serviceAcc.Address @@ -53,7 +58,7 @@ func TestDependencyInstallerInstall(t *testing.T) { state.Dependencies().AddOrUpdate(dep) t.Run("Success", func(t *testing.T) { - gw := mocks.DefaultMockGateway() + gw := gatewayMocks.DefaultMockGateway() gw.GetAccount.Run(func(args mock.Arguments) { addr := args.Get(1).(flow.Address) @@ -95,13 +100,13 @@ func TestDependencyInstallerInstall(t *testing.T) { func TestDependencyInstallerAdd(t *testing.T) { logger := output.NewStdoutLogger(output.NoneLog) - _, state, _ := tests.TestMocks(t) + _, state, _ := newTestMocks(t) serviceAcc, _ := state.EmulatorServiceAccount() serviceAddress := serviceAcc.Address t.Run("Success", func(t *testing.T) { - gw := mocks.DefaultMockGateway() + gw := gatewayMocks.DefaultMockGateway() gw.GetAccount.Run(func(args mock.Arguments) { addr := args.Get(1).(flow.Address) @@ -141,7 +146,7 @@ func TestDependencyInstallerAdd(t *testing.T) { }) t.Run("Success", func(t *testing.T) { - gw := mocks.DefaultMockGateway() + gw := gatewayMocks.DefaultMockGateway() gw.GetAccount.Run(func(args mock.Arguments) { addr := args.Get(1).(flow.Address) @@ -189,7 +194,7 @@ func TestDependencyInstallerAdd(t *testing.T) { func TestDependencyInstallerAddMany(t *testing.T) { logger := output.NewStdoutLogger(output.NoneLog) - _, state, _ := tests.TestMocks(t) + _, state, _ := newTestMocks(t) serviceAcc, _ := state.EmulatorServiceAccount() serviceAddress := serviceAcc.Address.String() @@ -214,7 +219,7 @@ func TestDependencyInstallerAddMany(t *testing.T) { } t.Run("AddMultipleDependencies", func(t *testing.T) { - gw := mocks.DefaultMockGateway() + gw := gatewayMocks.DefaultMockGateway() gw.GetAccount.Run(func(args mock.Arguments) { addr := args.Get(1).(flow.Address) assert.Equal(t, addr.String(), serviceAddress) @@ -251,3 +256,16 @@ func TestDependencyInstallerAddMany(t *testing.T) { } }) } + +// newTestMocks creates mock flowkit services, an empty state and a mock reader writer +func newTestMocks(t *testing.T) (*mocks.MockServices, *flowkit.State, flowkit.ReaderWriter) { + services := mocks.DefaultMockServices() + rw, _ := tests.ReaderWriter() + state, err := flowkit.Init(rw) + require.NoError(t, err) + + emulatorAccount, _ := accounts.NewEmulatorAccount(rw, crypto.ECDSA_P256, crypto.SHA3_256, "") + state.Accounts().AddOrUpdate(emulatorAccount) + + return services, state, rw +} diff --git a/tests/resources.go b/tests/resources.go index 61eb7eb1f..26583f5b1 100644 --- a/tests/resources.go +++ b/tests/resources.go @@ -20,12 +20,6 @@ package tests import ( "fmt" - "github.com/onflow/flowkit/v2" - "github.com/onflow/flowkit/v2/accounts" - "github.com/onflow/flowkit/v2/mocks" - "github.com/stretchr/testify/require" - "testing" - "github.com/onflow/cadence" "github.com/onflow/cadence/runtime/common" "github.com/onflow/flow-go-sdk" @@ -668,16 +662,3 @@ func NewAccountCreateResult(address flow.Address) *flow.TransactionResult { return NewTransactionResult(events) } - -// TestMocks creates mock flowkit services, an empty state and a mock reader writer -func TestMocks(t *testing.T) (*mocks.MockServices, *flowkit.State, flowkit.ReaderWriter) { - services := mocks.DefaultMockServices() - rw, _ := ReaderWriter() - state, err := flowkit.Init(rw) - require.NoError(t, err) - - emulatorAccount, _ := accounts.NewEmulatorAccount(rw, crypto.ECDSA_P256, crypto.SHA3_256, "") - state.Accounts().AddOrUpdate(emulatorAccount) - - return services, state, rw -} From 0cb26ff12ce9d827e1bef10cfaae18a6cc634332 Mon Sep 17 00:00:00 2001 From: Bart Date: Tue, 25 Jun 2024 15:14:43 +0200 Subject: [PATCH 099/101] add WithGateways option --- deps/dependencyinstaller.go | 57 ++++++++++++++++++++++++------------- 1 file changed, 37 insertions(+), 20 deletions(-) diff --git a/deps/dependencyinstaller.go b/deps/dependencyinstaller.go index 76949995f..aba7c679c 100644 --- a/deps/dependencyinstaller.go +++ b/deps/dependencyinstaller.go @@ -142,8 +142,43 @@ func WithSkippedAlias() Option { } } +func WithGateways(gateways map[string]gateway.Gateway) Option { + return func(installer *DependencyInstaller) { + installer.Gateways = gateways + } +} + // NewDependencyInstaller creates a new instance of DependencyInstaller func NewDependencyInstaller(state *flowkit.State, prompter Prompter, options ...Option) (*DependencyInstaller, error) { + installer := &DependencyInstaller{ + Gateways: nil, + Logger: output.NewStdoutLogger(output.InfoLog), + State: state, + SaveState: false, + TargetDir: "", + SkipDeployments: false, + SkipAlias: false, + dependencies: make(map[string]config.Dependency), + prompter: prompter, + } + + for _, opt := range options { + opt(installer) + } + + // If custom gateway option wasn't provided, use default gateways + if installer.Gateways == nil { + gateways, err := getDefaultGateways() + if err != nil { + return nil, err + } + installer.Gateways = gateways + } + + return installer, nil +} + +func getDefaultGateways() (map[string]gateway.Gateway, error) { emulatorGateway, err := gateway.NewGrpcGateway(config.EmulatorNetwork) if err != nil { return nil, fmt.Errorf("error creating emulator gateway: %v", err) @@ -164,30 +199,12 @@ func NewDependencyInstaller(state *flowkit.State, prompter Prompter, options ... return nil, fmt.Errorf("error creating previewnet gateway: %v", err) } - gateways := map[string]gateway.Gateway{ + return map[string]gateway.Gateway{ config.EmulatorNetwork.Name: emulatorGateway, config.TestnetNetwork.Name: testnetGateway, config.MainnetNetwork.Name: mainnetGateway, config.PreviewnetNetwork.Name: previewnetGateway, - } - - installer := &DependencyInstaller{ - Gateways: gateways, - Logger: output.NewStdoutLogger(output.InfoLog), - State: state, - SaveState: false, - TargetDir: "", - SkipDeployments: false, - SkipAlias: false, - dependencies: make(map[string]config.Dependency), - prompter: prompter, - } - - for _, opt := range options { - opt(installer) - } - - return installer, nil + }, nil } // saveState checks the SaveState flag and saves the state if set to true. From b6a7c3aab74e2eab720a469df3156b35d7b21ce6 Mon Sep 17 00:00:00 2001 From: Bart Date: Tue, 25 Jun 2024 15:17:46 +0200 Subject: [PATCH 100/101] nit: rename function --- deps/dependencyinstaller.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deps/dependencyinstaller.go b/deps/dependencyinstaller.go index aba7c679c..4945c8160 100644 --- a/deps/dependencyinstaller.go +++ b/deps/dependencyinstaller.go @@ -168,7 +168,7 @@ func NewDependencyInstaller(state *flowkit.State, prompter Prompter, options ... // If custom gateway option wasn't provided, use default gateways if installer.Gateways == nil { - gateways, err := getDefaultGateways() + gateways, err := defaultGateways() if err != nil { return nil, err } @@ -178,7 +178,7 @@ func NewDependencyInstaller(state *flowkit.State, prompter Prompter, options ... return installer, nil } -func getDefaultGateways() (map[string]gateway.Gateway, error) { +func defaultGateways() (map[string]gateway.Gateway, error) { emulatorGateway, err := gateway.NewGrpcGateway(config.EmulatorNetwork) if err != nil { return nil, fmt.Errorf("error creating emulator gateway: %v", err) From 50e389c0b3cccef2092f6a933b568d8be4af985a Mon Sep 17 00:00:00 2001 From: Bart Date: Sat, 29 Jun 2024 15:18:59 +0200 Subject: [PATCH 101/101] refactor AddressPromptOrEmpty, add comments --- deps/dependencyinstaller.go | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/deps/dependencyinstaller.go b/deps/dependencyinstaller.go index 4945c8160..67800ac17 100644 --- a/deps/dependencyinstaller.go +++ b/deps/dependencyinstaller.go @@ -100,11 +100,16 @@ type DeploymentData struct { } type Prompter interface { + // ShouldUpdateDependency prompts the user if the dependency should be updated in flow configuration ShouldUpdateDependency(contractName string) bool + // AddContractToDeployment prompts the user to select an account to deploy a given contract on a given network AddContractToDeployment(networkName string, accounts accounts.Accounts, contractName string) *DeploymentData - AddressPromptOrEmpty(label, errorMessage string) string + // AddressPromptOrEmpty prompts the user to enter a flow address + AddressPromptOrEmpty(label string, validate InputValidator) string } +type InputValidator func(string) error + type Flags struct { SkipDeployments bool SkipAlias bool @@ -529,7 +534,7 @@ func (di *DependencyInstaller) handleAdditionalDependencyTasks(networkName, cont func (di *DependencyInstaller) updateDependencyDeployment(contractName string) error { // Add to deployments // If a deployment already exists for that account, contract, and network, then ignore - raw := di.prompter.AddContractToDeployment("emulator", *di.State.Accounts(), contractName) + raw := di.prompter.AddContractToDeployment(config.EmulatorNetwork.Name, *di.State.Accounts(), contractName) if raw != nil { deployment := di.State.Deployments().ByAccountAndNetwork(raw.Account, raw.Network) @@ -559,7 +564,7 @@ func (di *DependencyInstaller) updateDependencyAlias(contractName, aliasNetwork } label := fmt.Sprintf("Enter an alias address for %s on %s if you have one, otherwise leave blank", contractName, missingNetwork) - raw := di.prompter.AddressPromptOrEmpty(label, "Invalid alias address") + raw := di.prompter.AddressPromptOrEmpty(label, addressValidator) if raw != "" { contract, err := di.State.Contracts().ByName(contractName) @@ -573,6 +578,16 @@ func (di *DependencyInstaller) updateDependencyAlias(contractName, aliasNetwork return nil } +func addressValidator(address string) error { + if address == "" { + return nil + } + if flowsdk.HexToAddress(address) == flowsdk.EmptyAddress { + return fmt.Errorf("invalid alias address") + } + return nil +} + func (di *DependencyInstaller) updateDependencyState(networkName, contractAddress, assignedName, contractName, contractHash string) error { dep := config.Dependency{ Name: assignedName,