Repository: onflow/flow-cli
Pull request #1601 (2024-05-16 16:46:16)

Update feature branch with master

______

For contributor use:

- [ ] Targeted PR against `master` branch
- [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work
- [ ] Code follows the [standards mentioned here](https://github.com/onflow/flow-cli/blob/master/CONTRIBUTING.md#styleguides)
- [ ] Updated relevant documentation
- [ ] Re-reviewed `Files changed` in the Github PR explorer
- [ ] Added appropriate labels



Patch:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 338909b4..23960785 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -54,7 +54,7 @@ jobs:
           go-version: "1.20"
       - name: generate
         run: make generate
-      - uses: golangci/golangci-lint-action@v5.3.0
+      - uses: golangci/golangci-lint-action@v6.0.1
         with:
           version: v1.52.2
           only-new-issues: true
diff --git a/go.mod b/go.mod
index 02bbf45b..a242caa9 100644
--- a/go.mod
+++ b/go.mod
@@ -12,16 +12,16 @@ require (
 	github.com/logrusorgru/aurora/v4 v4.0.0
 	github.com/manifoldco/promptui v0.9.0
 	github.com/onflow/cadence v0.42.10
-	github.com/onflow/cadence-tools/languageserver v0.33.5
+	github.com/onflow/cadence-tools/languageserver v0.33.6
 	github.com/onflow/cadence-tools/lint v0.14.2
 	github.com/onflow/cadence-tools/test v0.14.7
 	github.com/onflow/fcl-dev-wallet v0.7.4
-	github.com/onflow/flixkit-go v1.1.4-0.20240507174933-7a1de7bbf70f
+	github.com/onflow/flixkit-go v1.2.0
 	github.com/onflow/flow-core-contracts/lib/go/templates v1.2.4-0.20231016154253-a00dbf7c061f
 	github.com/onflow/flow-emulator v0.62.1
 	github.com/onflow/flow-go v0.33.2-0.20240412174857-015156b297b5
 	github.com/onflow/flow-go-sdk v0.46.3
-	github.com/onflow/flowkit v1.17.4-0.20240507180449-b565ca87f6b8
+	github.com/onflow/flowkit v1.18.0
 	github.com/onflowser/flowser/v3 v3.1.3
 	github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c
 	github.com/pkg/errors v0.9.1
diff --git a/go.sum b/go.sum
index a94ffa91..f86939fd 100644
--- a/go.sum
+++ b/go.sum
@@ -926,8 +926,8 @@ github.com/onflow/atree v0.6.0/go.mod h1:gBHU0M05qCbv9NN0kijLWMgC47gHVNBIp4KmsVF
 github.com/onflow/cadence v0.20.1/go.mod h1:7mzUvPZUIJztIbr9eTvs+fQjWWHTF8veC+yk4ihcNIA=
 github.com/onflow/cadence v0.42.10 h1:3oC5ceeXhdCrhHcf9H0yYXQKW3Tw/vkSXLe+PUZa4i0=
 github.com/onflow/cadence v0.42.10/go.mod h1:1wFd+LiNiN6qoZXof3MBdpM6d8BsxbVIxOA77LbIYmE=
-github.com/onflow/cadence-tools/languageserver v0.33.5 h1:Tg2YniU+ZJPI9RlTOuguqkLriUaFXue6FNXM+Ewijgo=
-github.com/onflow/cadence-tools/languageserver v0.33.5/go.mod h1:euGucPAVixPrlTyYGnsZTHg65u7C6zdmfRJlVwRgMaI=
+github.com/onflow/cadence-tools/languageserver v0.33.6 h1:BN26zUk+nBDMOX/VuTNYj6AjHUSeDfz4Ee5fnE1aeJY=
+github.com/onflow/cadence-tools/languageserver v0.33.6/go.mod h1:QTsSKm+w5NrwEE7g51NMMqanVV0BZzocGh5PQDTuolQ=
 github.com/onflow/cadence-tools/lint v0.14.2 h1:WGh6ARN9MRVeYID3OnlalPtDTeYkliteHHR+ITCh/J4=
 github.com/onflow/cadence-tools/lint v0.14.2/go.mod h1:PlYwSF4wwpCtQJKs1cQAb80AG90a4rhADTitCogQ4UE=
 github.com/onflow/cadence-tools/test v0.14.7 h1:o4tHQLvxLGlG6mFyDl2vFYFtoTLCFJVxuJQ16ab+3u4=
@@ -936,8 +936,8 @@ github.com/onflow/crypto v0.25.1 h1:0txy2PKPMM873JbpxQNbJmuOJtD56bfs48RQfm0ts5A=
 github.com/onflow/crypto v0.25.1/go.mod h1:C8FbaX0x8y+FxWjbkHy0Q4EASCDR9bSPWZqlpCLYyVI=
 github.com/onflow/fcl-dev-wallet v0.7.4 h1:vI6t3U0AO88R/Iitn5KsnniSpbN9Lqsqwvi9EJT4C0k=
 github.com/onflow/fcl-dev-wallet v0.7.4/go.mod h1:kc42jkiuoPJmxMRFjfbRO9XvnR/3XLheaOerxVMDTiw=
-github.com/onflow/flixkit-go v1.1.4-0.20240507174933-7a1de7bbf70f h1:8UEBHYC6mgc2c7U3p2ZoC3R6gupn1oqU61/jURZTsjI=
-github.com/onflow/flixkit-go v1.1.4-0.20240507174933-7a1de7bbf70f/go.mod h1:KUk8ODCdwNYF8PBYdu+VBTTrZ1IPWKvVJsdsGsEAtA0=
+github.com/onflow/flixkit-go v1.2.0 h1:JCT0g+amG+j3JjuT4lMkIp1FSpCfiI9xM5CmwXuYVZ8=
+github.com/onflow/flixkit-go v1.2.0/go.mod h1:gtQu0C3U/8t6gN8jgdSJLYEytIcq788pKHA2XNr/uRQ=
 github.com/onflow/flow-core-contracts/lib/go/contracts v1.2.4-0.20231016154253-a00dbf7c061f h1:S8yIZw9LFXfYD1V5H9BiixihHw3GrXVPrmfplSzYaww=
 github.com/onflow/flow-core-contracts/lib/go/contracts v1.2.4-0.20231016154253-a00dbf7c061f/go.mod h1:jM6GMAL+m0hjusUgiYDNrixPQ6b9s8xjoJQoEu5bHQI=
 github.com/onflow/flow-core-contracts/lib/go/templates v1.2.4-0.20231016154253-a00dbf7c061f h1:Ep+Mpo2miWMe4pjPGIaEvEzshRep30dvNgxqk+//FrQ=
@@ -957,8 +957,8 @@ github.com/onflow/flow-nft/lib/go/contracts v1.1.0/go.mod h1:YsvzYng4htDgRB9sa9j
 github.com/onflow/flow/protobuf/go/flow v0.2.2/go.mod h1:gQxYqCfkI8lpnKsmIjwtN2mV/N2PIwc1I+RUK4HPIc8=
 github.com/onflow/flow/protobuf/go/flow v0.4.0 h1:5TGmPwRmnSt7aawgtPGF9ehoGHHir9Cy9LVoAiU9t/E=
 github.com/onflow/flow/protobuf/go/flow v0.4.0/go.mod h1:NA2pX2nw8zuaxfKphhKsk00kWLwfd+tv8mS23YXO4Sk=
-github.com/onflow/flowkit v1.17.4-0.20240507180449-b565ca87f6b8 h1:59gqw1cXdvyV+jYbItoqULLxcA1MWrTSzcSsgRIXEto=
-github.com/onflow/flowkit v1.17.4-0.20240507180449-b565ca87f6b8/go.mod h1:laapt1diM4Pbqt0dotKMH+LbUAOEqgugpH1p4+sPhcw=
+github.com/onflow/flowkit v1.18.0 h1:8FmnLcfc5lUuUrKPHr9Z1YQVh50P33l+Ac7DhUNbiaw=
+github.com/onflow/flowkit v1.18.0/go.mod h1:laapt1diM4Pbqt0dotKMH+LbUAOEqgugpH1p4+sPhcw=
 github.com/onflow/go-ethereum v1.13.4 h1:iNO86fm8RbBbhZ87ZulblInqCdHnAQVY8okBrNsTevc=
 github.com/onflow/go-ethereum v1.13.4/go.mod h1:cE/gEUkAffhwbVmMJYz+t1dAfVNHNwZCgc3BWtZxBGY=
 github.com/onflow/nft-storefront/lib/go/contracts v0.0.0-20221222181731-14b90207cead h1:2j1Unqs76Z1b95Gu4C3Y28hzNUHBix7wL490e61SMSw=
diff --git a/internal/config/init.go b/internal/config/init.go
index 50c48eda..a03fd288 100644
--- a/internal/config/init.go
+++ b/internal/config/init.go
@@ -22,30 +22,14 @@ import (
 	"fmt"
 	"os"
 
-	"github.com/onflow/flow-go-sdk/crypto"
 	"github.com/onflow/flowkit"
+	"github.com/onflow/flowkit/accounts"
+
+	"github.com/onflow/flow-go-sdk/crypto"
+
 	"github.com/onflow/flowkit/config"
 )
 
-//type flagsInit struct {
-//	ServicePrivateKey  string `flag:"service-private-key" info:"Service account private key"`
-//	ServiceKeySigAlgo  string `default:"ECDSA_P256" flag:"service-sig-algo" info:"Service account key signature algorithm"`
-//	ServiceKeyHashAlgo string `default:"SHA3_256" flag:"service-hash-algo" info:"Service account key hash algorithm"`
-//	Reset              bool   `default:"false" flag:"reset" info:"Reset configuration file"`
-//	Global             bool   `default:"false" flag:"global" info:"Initialize global user configuration"`
-//}
-//
-//var InitFlag = flagsInit{}
-
-//var initCommand = &command.Command{
-//	Cmd: &cobra.Command{
-//		Use:   "init",
-//		Short: "Initialize a new configuration",
-//	},
-//	Flags: &InitFlag,
-//	Run:   Initialise,
-//}
-
 // InitConfigParameters holds all necessary parameters for initializing the configuration.
 type InitConfigParameters struct {
 	ServicePrivateKey  string
@@ -86,11 +70,18 @@ func InitializeConfiguration(params InitConfigParameters, readerWriter flowkit.R
 		return nil, fmt.Errorf("invalid hash algorithm: %s", params.ServiceKeyHashAlgo)
 	}
 
-	state, err := flowkit.Init(readerWriter, sigAlgo, hashAlgo, params.TargetDirectory)
+	state, err := flowkit.Init(readerWriter)
 	if err != nil {
 		return nil, err
 	}
 
+	emulatorAccount, err := accounts.NewEmulatorAccount(readerWriter, crypto.ECDSA_P256, crypto.SHA3_256, "")
+	if err != nil {
+		return nil, err
+	}
+
+	state.Accounts().AddOrUpdate(emulatorAccount)
+
 	if params.ServicePrivateKey != "" {
 		privateKey, err := crypto.DecodePrivateKeyHex(sigAlgo, params.ServicePrivateKey)
 		if err != nil {
diff --git a/internal/dependencymanager/dependencyinstaller.go b/internal/dependencymanager/dependencyinstaller.go
index c2a27f01..7bffd52f 100644
--- a/internal/dependencymanager/dependencyinstaller.go
+++ b/internal/dependencymanager/dependencyinstaller.go
@@ -112,6 +112,7 @@ type DependencyInstaller struct {
 	SkipDeployments bool
 	SkipAlias       bool
 	logs            categorizedLogs
+	dependencies    map[string]config.Dependency
 }
 
 // NewDependencyInstaller creates a new instance of DependencyInstaller
@@ -145,6 +146,7 @@ func NewDependencyInstaller(logger output.Logger, state *flowkit.State, saveStat
 		TargetDir:       targetDir,
 		SkipDeployments: flags.skipDeployments,
 		SkipAlias:       flags.skipAlias,
+		dependencies:    make(map[string]config.Dependency),
 	}, nil
 }
 
@@ -168,8 +170,10 @@ func (di *DependencyInstaller) Install() error {
 		}
 	}
 
+	di.checkForConflictingContracts()
+
 	if err := di.saveState(); err != nil {
-		return err
+		return fmt.Errorf("error saving state: %w", err)
 	}
 
 	di.logs.LogAll(di.Logger)
@@ -203,6 +207,8 @@ func (di *DependencyInstaller) AddBySourceString(depSource, customName string) e
 		return fmt.Errorf("error processing dependency: %w", err)
 	}
 
+	di.checkForConflictingContracts()
+
 	if err := di.saveState(); err != nil {
 		return err
 	}
@@ -244,12 +250,47 @@ func (di *DependencyInstaller) AddMany(dependencies []config.Dependency) error {
 	return nil
 }
 
+func (di *DependencyInstaller) addDependency(dep config.Dependency) error {
+	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[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 {
+		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)
+		}
+	}
+}
+
 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(config.Dependency{
+		Name: assignedName,
+		Source: config.Source{
+			NetworkName:  networkName,
+			Address:      address,
+			ContractName: contractName,
+		},
+	})
+	if err != nil {
+		return fmt.Errorf("error adding dependency: %w", err)
+	}
+
 	ctx := context.Background()
 	account, err := di.Gateways[networkName].GetAccount(ctx, address)
 	if err != nil {
@@ -353,20 +394,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())
@@ -394,14 +421,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)
 	}
@@ -412,9 +441,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
@@ -426,7 +459,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
diff --git a/internal/emulator/start.go b/internal/emulator/start.go
index 38420aad..dce19ff7 100644
--- a/internal/emulator/start.go
+++ b/internal/emulator/start.go
@@ -62,7 +62,7 @@ func configuredServiceKey(
 			hashAlgo = emulator.DefaultServiceKeyHashAlgo
 		}
 
-		state, err = flowkit.Init(loader, sigAlgo, hashAlgo, "")
+		state, err = flowkit.Init(loader)
 		if err != nil {
 			exitf(1, err.Error())
 		} else {
diff --git a/internal/version/version.go b/internal/version/version.go
index c7b09fe2..cf93d761 100644
--- a/internal/version/version.go
+++ b/internal/version/version.go
@@ -30,6 +30,12 @@ import (
 	"github.com/onflow/flow-cli/internal/command"
 )
 
+var verboseFlag bool
+
+func init() {
+	Cmd.Flags().BoolVarP(&verboseFlag, "verbose", "v", false, "Show detailed dependency information")
+}
+
 type versionCmd struct {
 	Version      string
 	Commit       string
@@ -44,9 +50,11 @@ func (c versionCmd) Print(format string) error {
 		txtBuilder.WriteString(fmt.Sprintf("Version: %s\n", c.Version))
 		txtBuilder.WriteString(fmt.Sprintf("Commit: %s\n", c.Commit))
 
-		txtBuilder.WriteString("\nFlow Package Dependencies \n")
-		for _, dep := range c.Dependencies {
-			txtBuilder.WriteString(fmt.Sprintf("%s %s\n", dep.Path, dep.Version))
+		if verboseFlag {
+			txtBuilder.WriteString("\nFlow Package Dependencies \n")
+			for _, dep := range c.Dependencies {
+				txtBuilder.WriteString(fmt.Sprintf("%s %s\n", dep.Path, dep.Version))
+			}
 		}
 
 		fmt.Println(txtBuilder.String())


Test patch:
diff --git a/internal/cadence/lint_test.go b/internal/cadence/lint_test.go
index 0759c6f6..d8f4c79d 100644
--- a/internal/cadence/lint_test.go
+++ b/internal/cadence/lint_test.go
@@ -24,7 +24,6 @@ import (
 	"github.com/onflow/cadence/runtime/ast"
 	"github.com/onflow/cadence/runtime/common"
 	"github.com/onflow/cadence/tools/analysis"
-	"github.com/onflow/flow-go-sdk/crypto"
 	"github.com/onflow/flowkit"
 	"github.com/onflow/flowkit/config"
 	"github.com/spf13/afero"
@@ -311,7 +310,7 @@ func setupMockState(t *testing.T) *flowkit.State {
 	}`), 0644)
 
 	rw := afero.Afero{Fs: mockFs}
-	state, err := flowkit.Init(rw, crypto.ECDSA_P256, crypto.SHA3_256, "")
+	state, err := flowkit.Init(rw)
 	require.NoError(t, err)
 
 	// Mock flowkit contracts
diff --git a/internal/dependencymanager/dependencyinstaller_test.go b/internal/dependencymanager/dependencyinstaller_test.go
index dd1941bb..b99a1dc5 100644
--- a/internal/dependencymanager/dependencyinstaller_test.go
+++ b/internal/dependencymanager/dependencyinstaller_test.go
@@ -80,6 +80,7 @@ func TestDependencyInstallerInstall(t *testing.T) {
 			TargetDir:       "",
 			SkipDeployments: true,
 			SkipAlias:       true,
+			dependencies:    make(map[string]config.Dependency),
 		}
 
 		err := di.Install()
@@ -126,6 +127,7 @@ func TestDependencyInstallerAdd(t *testing.T) {
 			TargetDir:       "",
 			SkipDeployments: true,
 			SkipAlias:       true,
+			dependencies:    make(map[string]config.Dependency),
 		}
 
 		sourceStr := fmt.Sprintf("emulator://%s.%s", serviceAddress.String(), tests.ContractHelloString.Name)
@@ -164,6 +166,7 @@ func TestDependencyInstallerAdd(t *testing.T) {
 			TargetDir:       "",
 			SkipDeployments: true,
 			SkipAlias:       true,
+			dependencies:    make(map[string]config.Dependency),
 		}
 
 		dep := config.Dependency{
@@ -235,6 +238,7 @@ func TestDependencyInstallerAddMany(t *testing.T) {
 			TargetDir:       "",
 			SkipDeployments: true,
 			SkipAlias:       true,
+			dependencies:    make(map[string]config.Dependency),
 		}
 
 		err := di.AddMany(dependencies)
diff --git a/internal/super/flix_test.go b/internal/super/flix_test.go
index 4a5e8325..ca1b5729 100644
--- a/internal/super/flix_test.go
+++ b/internal/super/flix_test.go
@@ -27,8 +27,6 @@ import (
 	"github.com/stretchr/testify/mock"
 
 	"github.com/onflow/flixkit-go/flixkit"
-	"github.com/onflow/flow-go-sdk/crypto"
-
 	"github.com/onflow/flowkit"
 	"github.com/onflow/flowkit/config"
 	"github.com/onflow/flowkit/mocks"
@@ -221,7 +219,7 @@ func Test_GenerateFlixPrefill(t *testing.T) {
 	var rw = afero.Afero{Fs: mockFS}
 	err := rw.WriteFile(cadenceFile, []byte(CADENCE_SCRIPT), 0644)
 	assert.NoError(t, err)
-	state, _ := flowkit.Init(rw, crypto.ECDSA_P256, crypto.SHA3_256, "")
+	state, _ := flowkit.Init(rw)
 
 	mockFlixService := new(MockFlixService)
 	ctx := context.Background()
diff --git a/internal/util/test.go b/internal/util/test.go
index 189b4f1c..4eba15d7 100644
--- a/internal/util/test.go
+++ b/internal/util/test.go
@@ -21,8 +21,10 @@ package util
 import (
 	"testing"
 
-	"github.com/onflow/flow-go-sdk"
 	"github.com/onflow/flow-go-sdk/crypto"
+	"github.com/onflow/flowkit/accounts"
+
+	"github.com/onflow/flow-go-sdk"
 	"github.com/stretchr/testify/require"
 
 	"github.com/onflow/flowkit"
@@ -39,8 +41,11 @@ var TestID = flow.HexToID("24993fc99f81641c45c0afa307e683b4f08d407d90041aa9439f4
 func TestMocks(t *testing.T) (*mocks.MockServices, *flowkit.State, flowkit.ReaderWriter) {
 	services := mocks.DefaultMockServices()
 	rw, _ := tests.ReaderWriter()
-	state, err := flowkit.Init(rw, crypto.ECDSA_P256, crypto.SHA3_256, "")
+	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
 }