├── CHANGELOG.md ├── .gitignore ├── CODEOWNERS ├── cmd ├── commands │ ├── channel │ │ ├── testdata │ │ │ └── channel.tx │ │ ├── channel.go │ │ ├── list.go │ │ ├── join.go │ │ ├── update.go │ │ ├── create.go │ │ ├── config.go │ │ ├── channel_test.go │ │ └── list_test.go │ ├── network │ │ ├── network.go │ │ ├── list.go │ │ ├── view.go │ │ ├── network_test.go │ │ ├── delete.go │ │ ├── set.go │ │ ├── list_test.go │ │ ├── view_test.go │ │ ├── delete_test.go │ │ └── set_test.go │ ├── plugin │ │ ├── plugin.go │ │ ├── plugin_test.go │ │ ├── list.go │ │ ├── uninstall.go │ │ ├── install.go │ │ ├── install_test.go │ │ ├── list_test.go │ │ └── uninstall_test.go │ ├── chaincode │ │ ├── testdata │ │ │ └── chaincode │ │ │ │ └── example │ │ │ │ └── example.go │ │ ├── chaincode.go │ │ ├── events.go │ │ ├── package.go │ │ ├── query.go │ │ ├── list.go │ │ ├── invoke.go │ │ ├── install.go │ │ ├── chaincode_test.go │ │ ├── package_test.go │ │ ├── query_test.go │ │ ├── upgrade.go │ │ ├── instantiate.go │ │ ├── invoke_test.go │ │ └── events_test.go │ ├── lifecycle │ │ ├── testdata │ │ │ └── chaincode │ │ │ │ └── example │ │ │ │ └── example.go │ │ ├── package.go │ │ ├── install.go │ │ ├── lifecycle.go │ │ ├── getinstalledpkg.go │ │ ├── queryinstalled.go │ │ ├── lifecycle_test.go │ │ ├── querycommitted.go │ │ ├── package_test.go │ │ └── queryapproved.go │ ├── context │ │ ├── context.go │ │ ├── view.go │ │ ├── list.go │ │ ├── delete.go │ │ ├── context_test.go │ │ ├── use.go │ │ ├── set.go │ │ ├── list_test.go │ │ ├── view_test.go │ │ ├── delete_test.go │ │ └── use_test.go │ ├── commands_test.go │ ├── commands.go │ ├── common │ │ ├── common_test.go │ │ └── common.go │ └── version │ │ └── version.go ├── common │ ├── command.go │ └── command_test.go └── fabric.go ├── pkg ├── plugin │ ├── testdata │ │ └── plugins │ │ │ ├── echo │ │ │ └── plugin.yaml │ │ │ ├── home │ │ │ ├── plugin.yaml │ │ │ ├── Makefile │ │ │ └── cmd │ │ │ │ └── home.go │ │ │ ├── cryptogen │ │ │ └── plugin.yaml │ │ │ └── echogoplugin │ │ │ ├── plugin.yaml │ │ │ ├── Makefile │ │ │ └── cmd │ │ │ └── echogoplugin.go │ └── plugin.go ├── environment │ ├── streams.go │ ├── home.go │ ├── home_test.go │ ├── actions.go │ ├── actions_test.go │ └── environment.go └── fabric │ ├── fabric_test.go │ └── fabric.go ├── tools └── tools.go ├── .github ├── settings.yml └── workflows │ └── build.yml ├── CODE_OF_CONDUCT.md ├── .golangci.yml ├── go.mod ├── common └── metadata │ └── metadata.go ├── CONTRIBUTING.md ├── MAINTAINERS.md ├── SECURITY.md ├── Makefile └── README.md /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | bin/ 3 | vendor/ 4 | _vendor* 5 | .gobincache 6 | .idea -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | # Fabric CLI Maintainers 4 | * @hyperledger/fabric-cli-maintainers 5 | -------------------------------------------------------------------------------- /cmd/commands/channel/testdata/channel.tx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyperledger/fabric-cli/HEAD/cmd/commands/channel/testdata/channel.tx -------------------------------------------------------------------------------- /pkg/plugin/testdata/plugins/echo/plugin.yaml: -------------------------------------------------------------------------------- 1 | # Copyright State Street Corp. All Rights Reserved. 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | name: echo 6 | usage: echo 7 | description: writes Hello to the console 8 | command: echo Hello -------------------------------------------------------------------------------- /tools/tools.go: -------------------------------------------------------------------------------- 1 | // +build tools 2 | 3 | /* 4 | Copyright State Street Corp. All Rights Reserved. 5 | 6 | SPDX-License-Identifier: Apache-2.0 7 | */ 8 | 9 | package tools 10 | 11 | import ( 12 | _ "github.com/maxbrunsfeld/counterfeiter/v6" 13 | ) 14 | -------------------------------------------------------------------------------- /pkg/plugin/testdata/plugins/home/plugin.yaml: -------------------------------------------------------------------------------- 1 | # Copyright State Street Corp. All Rights Reserved. 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | name: home 6 | usage: home 7 | description: output the current fabric home directory 8 | command: ${FABRIC_HOME}/plugins/home/bin/home -------------------------------------------------------------------------------- /pkg/plugin/testdata/plugins/home/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright State Street Corp. All Rights Reserved. 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | GO_CMD := go 6 | 7 | all: clean build 8 | 9 | clean: 10 | rm -rf ./bin 11 | 12 | build: 13 | $(GO_CMD) build -o ./bin/home ./cmd/home.go -------------------------------------------------------------------------------- /pkg/plugin/testdata/plugins/cryptogen/plugin.yaml: -------------------------------------------------------------------------------- 1 | # Copyright State Street Corp. All Rights Reserved. 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | name: cryptogen 6 | usage: cryptogen [] [ ...] 7 | description: Utility for generating Hyperledger Fabric key material 8 | command: cryptogen -------------------------------------------------------------------------------- /pkg/plugin/testdata/plugins/echogoplugin/plugin.yaml: -------------------------------------------------------------------------------- 1 | # Copyright SecureKey Technologies Inc. All Rights Reserved. 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | name: echogoplugin 6 | usage: echogoplugin 7 | description: demonstrates Go plugins 8 | command: ${FABRIC_HOME}/plugins/echogoplugin/bin/echogoplugin -------------------------------------------------------------------------------- /pkg/plugin/testdata/plugins/echogoplugin/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright SecureKey Technologies Inc. All Rights Reserved. 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | GO_CMD := go 6 | 7 | all: clean build 8 | 9 | clean: 10 | rm -rf ./bin 11 | 12 | build: 13 | $(GO_CMD) build -buildmode=plugin -o ./bin/echogoplugin ./cmd/echogoplugin.go -------------------------------------------------------------------------------- /.github/settings.yml: -------------------------------------------------------------------------------- 1 | repository: 2 | name: fabric-cli 3 | description: null 4 | homepage: https://wiki.hyperledger.org/display/fabric 5 | default_branch: main 6 | has_downloads: true 7 | has_issues: false 8 | has_projects: false 9 | has_wiki: false 10 | archived: false 11 | private: false 12 | allow_squash_merge: true 13 | allow_merge_commit: false 14 | allow_rebase_merge: true 15 | -------------------------------------------------------------------------------- /pkg/environment/streams.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package environment 8 | 9 | import ( 10 | "io" 11 | "os" 12 | ) 13 | 14 | // DefaultStreams contains the default io streams 15 | var DefaultStreams = Streams{ 16 | In: os.Stdin, 17 | Out: os.Stdout, 18 | Err: os.Stderr, 19 | } 20 | 21 | // Streams contains io stream configuration 22 | type Streams struct { 23 | In io.Reader 24 | Out io.Writer 25 | Err io.Writer 26 | } 27 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | Code of Conduct Guidelines 2 | ========================== 3 | 4 | Please review the Hyperledger [Code of 5 | Conduct](https://wiki.hyperledger.org/community/hyperledger-project-code-of-conduct) 6 | before participating. It is important that we keep things civil. 7 | 8 | Creative Commons License
This work is licensed under a Creative Commons Attribution 4.0 International License. 9 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | # Copyright State Street Corp. All Rights Reserved. 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | run: 6 | deadline: 2m 7 | 8 | linters: 9 | disable-all: true 10 | enable: 11 | - gocyclo 12 | - gofmt 13 | - golint 14 | - govet 15 | - ineffassign 16 | - interfacer 17 | - lll 18 | - misspell 19 | - nakedret 20 | - structcheck 21 | - unparam 22 | - varcheck 23 | 24 | linters-settings: 25 | lll: 26 | line-length: 150 27 | 28 | issues: 29 | exclude-rules: 30 | # Exclude lll issues for long lines with go:generate 31 | - linters: 32 | - lll 33 | source: "^//go:generate " -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | // Copyright State Street Corp. All Rights Reserved. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | module github.com/hyperledger/fabric-cli 6 | 7 | go 1.12 8 | 9 | require ( 10 | github.com/hyperledger/fabric-protos-go v0.0.0-20200707132912-fee30f3ccd23 11 | github.com/hyperledger/fabric-sdk-go v1.0.0-beta3.0.20201002210629-a64e1ef9f926 12 | github.com/maxbrunsfeld/counterfeiter/v6 v6.2.3 13 | github.com/onsi/ginkgo v1.8.0 14 | github.com/onsi/gomega v1.9.0 15 | github.com/pkg/errors v0.8.1 16 | github.com/spf13/cobra v0.0.4 17 | github.com/spf13/pflag v1.0.5 18 | github.com/spf13/viper v1.4.0 // indirect 19 | github.com/stretchr/testify v1.5.1 20 | gopkg.in/yaml.v2 v2.3.0 21 | ) 22 | -------------------------------------------------------------------------------- /common/metadata/metadata.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2019 TopJohn 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package metadata 17 | 18 | // assigned in Makefile. 19 | var ( 20 | Version string 21 | CommitSHA string 22 | ) 23 | -------------------------------------------------------------------------------- /cmd/commands/network/network.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package network 8 | 9 | import ( 10 | "github.com/hyperledger/fabric-cli/pkg/environment" 11 | "github.com/spf13/cobra" 12 | ) 13 | 14 | // NewNetworkCommand creates a new "fabric network" command 15 | func NewNetworkCommand(settings *environment.Settings) *cobra.Command { 16 | cmd := &cobra.Command{ 17 | Use: "network", 18 | Short: "Manage networks", 19 | Long: "Network indicates the Fabric Go SDK' config path", 20 | } 21 | 22 | cmd.AddCommand( 23 | NewNetworkViewCommand(settings), 24 | NewNetworkListCommand(settings), 25 | NewNetworkSetCommand(settings), 26 | NewNetworkDeleteCommand(settings), 27 | ) 28 | 29 | cmd.SetOutput(settings.Streams.Out) 30 | 31 | return cmd 32 | } 33 | -------------------------------------------------------------------------------- /cmd/commands/plugin/plugin.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package plugin 8 | 9 | import ( 10 | "github.com/spf13/cobra" 11 | 12 | "github.com/hyperledger/fabric-cli/pkg/environment" 13 | ) 14 | 15 | // NewPluginCommand creates a new "fabric plugin" command 16 | func NewPluginCommand(settings *environment.Settings) *cobra.Command { 17 | cmd := &cobra.Command{ 18 | Use: "plugin", 19 | Short: "Manage plugins", 20 | Long: "Plugin used to install|list|uninstall Go Plugins or custom cmds into fabric command", 21 | } 22 | 23 | cmd.AddCommand( 24 | NewPluginListCommand(settings), 25 | NewPluginInstallCommand(settings), 26 | NewPluginUninstallCommand(settings), 27 | ) 28 | 29 | cmd.SetOutput(settings.Streams.Out) 30 | 31 | return cmd 32 | } 33 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | name: Verify Build 4 | 5 | on: 6 | push: 7 | branches: 8 | - main 9 | pull_request: 10 | branches: 11 | - main 12 | 13 | env: 14 | GOPATH: /opt/go 15 | PATH: /opt/go/bin:/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin 16 | GO_VER: 1.14.4 17 | 18 | jobs: 19 | unit-tests: 20 | name: Unit Tests 21 | runs-on: ubuntu-20.04 22 | timeout-minutes: 60 23 | steps: 24 | - name: Install Go 25 | uses: actions/setup-go@v3 26 | with: 27 | go-version: ${{ env.GO_VER }} 28 | - name: Install gobin 29 | run: GO111MODULE=off go get -u github.com/myitcv/gobin 30 | - name: Checkout Fabric Code 31 | uses: actions/checkout@v3 32 | - name: Run lint 33 | run: make lint 34 | - name: Run tests 35 | run: make test 36 | -------------------------------------------------------------------------------- /cmd/commands/chaincode/testdata/chaincode/example/example.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package main 8 | 9 | import ( 10 | "fmt" 11 | 12 | "github.com/hyperledger/fabric/core/chaincode/shim" 13 | pb "github.com/hyperledger/fabric/protos/peer" 14 | ) 15 | 16 | // Chaincode is a simple chaincode implementation 17 | type Chaincode struct{} 18 | 19 | // Init - Initializes the chaincode 20 | func (cc *Chaincode) Init(stub shim.ChaincodeStubInterface) pb.Response { 21 | return shim.Success(nil) 22 | } 23 | 24 | // Invoke - invokes the chaincode 25 | func (cc *Chaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response { 26 | return shim.Success(nil) 27 | } 28 | 29 | func main() { 30 | err := shim.Start(new(Chaincode)) 31 | if err != nil { 32 | fmt.Printf("Error starting chaincode: %s", err) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /cmd/commands/lifecycle/testdata/chaincode/example/example.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package main 8 | 9 | import ( 10 | "fmt" 11 | 12 | "github.com/hyperledger/fabric/core/chaincode/shim" 13 | pb "github.com/hyperledger/fabric/protos/peer" 14 | ) 15 | 16 | // Chaincode is a simple chaincode implementation 17 | type Chaincode struct{} 18 | 19 | // Init - Initializes the chaincode 20 | func (cc *Chaincode) Init(stub shim.ChaincodeStubInterface) pb.Response { 21 | return shim.Success(nil) 22 | } 23 | 24 | // Invoke - invokes the chaincode 25 | func (cc *Chaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response { 26 | return shim.Success(nil) 27 | } 28 | 29 | func main() { 30 | err := shim.Start(new(Chaincode)) 31 | if err != nil { 32 | fmt.Printf("Error starting chaincode: %s", err) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /cmd/commands/context/context.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package context 8 | 9 | import ( 10 | "github.com/hyperledger/fabric-cli/pkg/environment" 11 | "github.com/spf13/cobra" 12 | ) 13 | 14 | // NewContextCommand creates a new "fabric context" command 15 | func NewContextCommand(settings *environment.Settings) *cobra.Command { 16 | cmd := &cobra.Command{ 17 | Use: "context", 18 | Short: "Manage contexts", 19 | Long: "Context indicates the Network|Organization|User|Channel|Orderers|Peers info", 20 | } 21 | 22 | cmd.AddCommand( 23 | NewContextViewCommand(settings), 24 | NewContextUseCommand(settings), 25 | NewContextListCommand(settings), 26 | NewContextSetCommand(settings), 27 | NewContextDeleteCommand(settings), 28 | ) 29 | 30 | cmd.SetOutput(settings.Streams.Out) 31 | 32 | return cmd 33 | } 34 | -------------------------------------------------------------------------------- /cmd/commands/commands_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package commands_test 8 | 9 | import ( 10 | "testing" 11 | 12 | "github.com/spf13/cobra" 13 | 14 | "github.com/hyperledger/fabric-cli/cmd/commands" 15 | "github.com/hyperledger/fabric-cli/pkg/environment" 16 | . "github.com/onsi/ginkgo" 17 | . "github.com/onsi/gomega" 18 | ) 19 | 20 | func TestCommands(t *testing.T) { 21 | RegisterFailHandler(Fail) 22 | 23 | RunSpecs(t, "Commands Suite") 24 | } 25 | 26 | var _ = Describe("Commands", func() { 27 | var ( 28 | cmds []*cobra.Command 29 | ) 30 | 31 | JustBeforeEach(func() { 32 | cmds = commands.All(&environment.Settings{}) 33 | }) 34 | 35 | It("should not be nil", func() { 36 | Expect(cmds).NotTo(BeNil()) 37 | }) 38 | 39 | It("should contain built in commands", func() { 40 | Expect(len(cmds)).To(BeNumerically(">", 0)) 41 | }) 42 | }) 43 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Contributing 2 | 3 | We welcome contributions to the Hyperledger Fabric Project in many forms, and 4 | there's always plenty to do! 5 | 6 | Please visit the 7 | [contributors guide](http://hyperledger-fabric.readthedocs.io/en/latest/CONTRIBUTING.html) in the 8 | docs to learn how to make contributions to this exciting project. 9 | 10 | ## Code of Conduct Guidelines 11 | 12 | See our [Code of Conduct Guidelines](./CODE_OF_CONDUCT.md). 13 | 14 | ## Maintainers 15 | 16 | Should you have any questions or concerns, please reach out to one of the project's [Maintainers](./MAINTAINERS.md). 17 | 18 | Creative Commons License
This work is licensed under a Creative Commons Attribution 4.0 International License. 19 | -------------------------------------------------------------------------------- /MAINTAINERS.md: -------------------------------------------------------------------------------- 1 | Maintainers 2 | =========== 3 | 4 | fabric-cli uses a non-author code review policy, requiring a single approval from a non-author maintainer. 5 | 6 | **Active maintainers** 7 | 8 | | Name | GitHub | Chat | email | 9 | |------|--------|------|-------| 10 | | Arnaud Le Hors | [lehors](https://github.com/lehors) | lehors | | 11 | | Troy Ronda | [troyronda](https://github.com/troyronda) | troyronda | | 12 | 13 | **Emeritus maintainers** 14 | 15 | | Name | GitHub | Chat | email | 16 | |------|--------|------|-------| 17 | | Brian Buchanan | [bpbuch](https://github.com/bpbuch) | bpbuch | | 18 | 19 | Creative Commons License
This work is licensed under a Creative Commons Attribution 4.0 International License. 20 | -------------------------------------------------------------------------------- /cmd/common/command.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package common 8 | 9 | import ( 10 | "github.com/hyperledger/fabric-cli/pkg/environment" 11 | "github.com/spf13/cobra" 12 | ) 13 | 14 | // Command implements common command functions 15 | type Command struct { 16 | Settings *environment.Settings 17 | Args []*string 18 | } 19 | 20 | // AddArg makes the command aware that it is expecting an argument 21 | // The order that args are added is important 22 | func (c *Command) AddArg(arg *string) { 23 | if arg == nil { 24 | return 25 | } 26 | 27 | c.Args = append(c.Args, arg) 28 | } 29 | 30 | // ParseArgs writes the arg values to the specified locations. 31 | func (c *Command) ParseArgs() cobra.PositionalArgs { 32 | return func(_ *cobra.Command, args []string) error { 33 | for i, arg := range c.Args { 34 | if len(args) < i+1 { 35 | return nil 36 | } 37 | 38 | *arg = args[i] 39 | } 40 | 41 | return nil 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Hyperledger Security Policy 2 | 3 | ## Reporting a Security Bug 4 | 5 | If you think you have discovered a security issue in any of the Hyperledger projects, we'd love to hear from you. We will take all security bugs seriously and if confirmed upon investigation we will patch it within a reasonable amount of time and release a public security bulletin discussing the impact and credit the discoverer. 6 | 7 | There are two ways to report a security bug. The easiest is to email a description of the flaw and any related information (e.g. reproduction steps, version) to [security at hyperledger dot org](mailto:security@hyperledger.org). 8 | 9 | The other way is to file a confidential security bug in our [JIRA bug tracking system](https://jira.hyperledger.org). Be sure to set the “Security Level” to “Security issue”. 10 | 11 | The process by which the Hyperledger Security Team handles security bugs is documented further in our [Defect Response page](https://wiki.hyperledger.org/display/HYP/Defect+Response) on our [wiki](https://wiki.hyperledger.org). 12 | 13 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Copyright State Street Corp. All Rights Reserved. 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | PROJECT_VERSION=dev 6 | 7 | GO_CMD ?= go 8 | LINT_CMD ?= gobin -run github.com/golangci/golangci-lint/cmd/golangci-lint@v1.19.1 9 | 10 | BIN_DIR := $(CURDIR)/bin 11 | CMD_DIR := $(CURDIR)/cmd 12 | 13 | PROJECT_NAME = hyperledger/fabric-cli 14 | PKGNAME = github.com/$(PROJECT_NAME) 15 | 16 | EXTRA_VERSION ?= $(shell git rev-parse --short HEAD) 17 | 18 | # defined in common/metadata/metadata.go 19 | METADATA_VAR = Version=$(PROJECT_VERSION) 20 | METADATA_VAR += CommitSHA=$(EXTRA_VERSION) 21 | 22 | GO_LDFLAGS = $(patsubst %,-X $(PKGNAME)/common/metadata.%,$(METADATA_VAR)) 23 | 24 | export GO111MODULE := on 25 | 26 | all: clean build 27 | 28 | .PHONY: clean 29 | clean: 30 | rm -rf $(BIN_DIR) 31 | find . -name "mocks" -type d -print0 | xargs -0 /bin/rm -rf 32 | 33 | .PHONY: generate 34 | generate: 35 | $(GO_CMD) generate ./... 36 | 37 | .PHONY: lint 38 | lint: generate 39 | $(LINT_CMD) run 40 | 41 | .PHONY: test 42 | test: generate 43 | $(GO_CMD) test -cover ./... 44 | 45 | .PHONY: build 46 | build: 47 | $(GO_CMD) build -o $(BIN_DIR)/fabric -ldflags "$(GO_LDFLAGS)" $(CMD_DIR)/fabric.go 48 | -------------------------------------------------------------------------------- /pkg/plugin/plugin.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package plugin 8 | 9 | import ( 10 | "strings" 11 | ) 12 | 13 | // DefaultFilename is the filename for the plugin metadata 14 | const DefaultFilename = "plugin.yaml" 15 | 16 | // Plugin is an installed, third-party command 17 | // Consider using "github.com/mitchellh/mapstructure" when the yaml structure 18 | // gets more complex 19 | type Plugin struct { 20 | Name string `yaml:"name"` 21 | Usage string `yaml:"usage"` 22 | Description string `yaml:"description"` 23 | Command *Command `yaml:"command"` 24 | 25 | Path string `yaml:"-"` 26 | } 27 | 28 | // Command is a parsed plugin command 29 | type Command struct { 30 | Base string 31 | Args []string 32 | } 33 | 34 | // UnmarshalYAML implements the yaml unmarshaller interface 35 | // This function deconstructs the command to base command and args 36 | func (c *Command) UnmarshalYAML(unmarshal func(interface{}) error) error { 37 | var cmd string 38 | err := unmarshal(&cmd) 39 | if err != nil { 40 | return err 41 | } 42 | 43 | parts := strings.Split(cmd, " ") 44 | 45 | if len(parts) > 0 { 46 | c.Base = parts[0] 47 | c.Args = parts[1:] 48 | } 49 | 50 | return nil 51 | } 52 | -------------------------------------------------------------------------------- /pkg/environment/home.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package environment 8 | 9 | import ( 10 | "os" 11 | "path/filepath" 12 | ) 13 | 14 | // DefaultHome is the default cli home directory 15 | const DefaultHome = Home("${HOME}/.fabric") 16 | 17 | // Home is the location of the configuration files 18 | // By default, the files are stored in ~/.fabric 19 | type Home string 20 | 21 | // String resolves variables and returns home as a string 22 | func (h Home) String() string { 23 | return os.ExpandEnv(string(h)) 24 | } 25 | 26 | // Path appends compoenents to home and returns it as a string 27 | func (h Home) Path(components ...string) string { 28 | return filepath.Join(append([]string{h.String()}, components...)...) 29 | } 30 | 31 | // Plugins returns the path to the plugins directory 32 | func (h Home) Plugins() string { 33 | return h.Path("plugins") 34 | } 35 | 36 | // Init creates a home directory if it does not already exist 37 | func (h Home) Init() error { 38 | // continue if the home directory already exists 39 | if _, err := os.Stat(h.String()); os.IsNotExist(err) { 40 | // create a new home directory 41 | if err = os.MkdirAll(h.String(), 0755); err != nil { 42 | return err 43 | } 44 | } 45 | 46 | return nil 47 | } 48 | -------------------------------------------------------------------------------- /pkg/plugin/testdata/plugins/home/cmd/home.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package main 8 | 9 | import ( 10 | "fmt" 11 | "os" 12 | 13 | "github.com/spf13/cobra" 14 | "github.com/spf13/pflag" 15 | 16 | "github.com/hyperledger/fabric-cli/cmd/common" 17 | "github.com/hyperledger/fabric-cli/pkg/environment" 18 | ) 19 | 20 | // NewHomeCommand is a fabric plugin for "fabric home" 21 | func NewHomeCommand() *cobra.Command { 22 | c := &HomeCommand{} 23 | 24 | cmd := &cobra.Command{ 25 | Use: "home", 26 | Short: "output the current fabric home directory", 27 | PreRunE: func(_ *cobra.Command, _ []string) error { 28 | settings := environment.NewDefaultSettings() 29 | 30 | if err := settings.Init(&pflag.FlagSet{}); err != nil { 31 | fmt.Fprintln(os.Stderr, err) 32 | return err 33 | } 34 | 35 | c.Settings = settings 36 | 37 | return nil 38 | }, 39 | Run: func(_ *cobra.Command, _ []string) { 40 | c.run() 41 | }, 42 | } 43 | 44 | return cmd 45 | } 46 | 47 | // HomeCommand implements a home command 48 | type HomeCommand struct { 49 | common.Command 50 | } 51 | 52 | func (c *HomeCommand) run() { 53 | fmt.Fprintln(c.Settings.Streams.Out, c.Settings.Home) 54 | } 55 | 56 | func main() { 57 | cmd := NewHomeCommand() 58 | 59 | if err := cmd.Execute(); err != nil { 60 | fmt.Fprintln(os.Stderr, err) 61 | os.Exit(1) 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /cmd/commands/commands.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package commands 8 | 9 | import ( 10 | "github.com/spf13/cobra" 11 | 12 | "github.com/hyperledger/fabric-cli/cmd/commands/chaincode" 13 | "github.com/hyperledger/fabric-cli/cmd/commands/channel" 14 | "github.com/hyperledger/fabric-cli/cmd/commands/context" 15 | "github.com/hyperledger/fabric-cli/cmd/commands/lifecycle" 16 | "github.com/hyperledger/fabric-cli/cmd/commands/network" 17 | "github.com/hyperledger/fabric-cli/cmd/commands/plugin" 18 | "github.com/hyperledger/fabric-cli/cmd/commands/version" 19 | "github.com/hyperledger/fabric-cli/pkg/environment" 20 | ) 21 | 22 | // All returns all subcommands that will be added to the root command 23 | // Settings can be leveraged here to disable commands 24 | func All(settings *environment.Settings) []*cobra.Command { 25 | return []*cobra.Command{ 26 | // fabric plugin [subcommand] 27 | plugin.NewPluginCommand(settings), 28 | 29 | // fabric network [subcommand] 30 | network.NewNetworkCommand(settings), 31 | 32 | // fabric context [subcommand] 33 | context.NewContextCommand(settings), 34 | 35 | // fabric channel [subcommand] 36 | channel.NewChannelCommand(settings), 37 | 38 | // fabric channel [subcommand] 39 | chaincode.NewChaincodeCommand(settings), 40 | 41 | // fabric version 42 | version.NewVersionCommand(settings), 43 | 44 | // fabric lifecycle [subcommand] 45 | lifecycle.NewCommand(settings), 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /cmd/commands/context/view.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package context 8 | 9 | import ( 10 | "fmt" 11 | 12 | "github.com/hyperledger/fabric-cli/cmd/common" 13 | "github.com/hyperledger/fabric-cli/pkg/environment" 14 | "github.com/spf13/cobra" 15 | ) 16 | 17 | // NewContextViewCommand creates a new "fabric context view" command 18 | func NewContextViewCommand(settings *environment.Settings) *cobra.Command { 19 | c := ViewCommand{} 20 | 21 | c.Settings = settings 22 | 23 | cmd := &cobra.Command{ 24 | Use: "view [context-name]", 25 | Short: "View a context", 26 | Long: "View a context, default view current context", 27 | Args: c.ParseArgs(), 28 | RunE: func(_ *cobra.Command, _ []string) error { 29 | return c.Run() 30 | }, 31 | } 32 | 33 | c.AddArg(&c.Name) 34 | 35 | cmd.SetOutput(c.Settings.Streams.Out) 36 | 37 | return cmd 38 | } 39 | 40 | // ViewCommand implements the current command 41 | type ViewCommand struct { 42 | common.Command 43 | 44 | Name string 45 | } 46 | 47 | // Run executes the command 48 | func (c *ViewCommand) Run() error { 49 | if len(c.Name) == 0 { 50 | c.Name = c.Settings.Config.CurrentContext 51 | } 52 | 53 | context, ok := c.Settings.Config.Contexts[c.Name] 54 | if !ok { 55 | return fmt.Errorf("context '%s' does not exist", c.Name) 56 | } 57 | 58 | fmt.Fprintln(c.Settings.Streams.Out, "Name: ", c.Name) 59 | fmt.Fprintln(c.Settings.Streams.Out, context) 60 | 61 | return nil 62 | } 63 | -------------------------------------------------------------------------------- /cmd/commands/context/list.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package context 8 | 9 | import ( 10 | "errors" 11 | "fmt" 12 | "sort" 13 | 14 | "github.com/hyperledger/fabric-cli/cmd/common" 15 | "github.com/hyperledger/fabric-cli/pkg/environment" 16 | "github.com/spf13/cobra" 17 | ) 18 | 19 | // NewContextListCommand creates a new "fabric context list" command 20 | func NewContextListCommand(settings *environment.Settings) *cobra.Command { 21 | c := ListCommand{} 22 | 23 | c.Settings = settings 24 | 25 | cmd := &cobra.Command{ 26 | Use: "list", 27 | Short: "List all contexts", 28 | Long: "List all contexts in config.yaml", 29 | RunE: func(_ *cobra.Command, _ []string) error { 30 | return c.Run() 31 | }, 32 | } 33 | 34 | cmd.SetOutput(c.Settings.Streams.Out) 35 | 36 | return cmd 37 | } 38 | 39 | // ListCommand implements the list context command 40 | type ListCommand struct { 41 | common.Command 42 | } 43 | 44 | // Run executes the command 45 | func (c *ListCommand) Run() error { 46 | if len(c.Settings.Config.Contexts) == 0 { 47 | return errors.New("No context currently exists") 48 | } 49 | 50 | var names []string 51 | for name := range c.Settings.Config.Contexts { 52 | if name == c.Settings.Config.CurrentContext { 53 | name += " (current)" 54 | } 55 | names = append(names, name) 56 | } 57 | 58 | sort.Strings(names) 59 | 60 | for _, name := range names { 61 | fmt.Fprintln(c.Settings.Streams.Out, name) 62 | } 63 | 64 | return nil 65 | } 66 | -------------------------------------------------------------------------------- /cmd/common/command_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package common_test 8 | 9 | import ( 10 | "testing" 11 | 12 | . "github.com/onsi/ginkgo" 13 | . "github.com/onsi/gomega" 14 | "github.com/spf13/cobra" 15 | 16 | "github.com/hyperledger/fabric-cli/cmd/common" 17 | ) 18 | 19 | func TestCommands(t *testing.T) { 20 | RegisterFailHandler(Fail) 21 | 22 | RunSpecs(t, "Command Suite") 23 | } 24 | 25 | var _ = Describe("Command", func() { 26 | var ( 27 | c *common.Command 28 | ) 29 | 30 | BeforeEach(func() { 31 | c = &common.Command{} 32 | }) 33 | 34 | Describe("AddArg", func() { 35 | It("should not add nil arg", func() { 36 | c.AddArg(nil) 37 | Expect(len(c.Args)).To(BeZero()) 38 | }) 39 | 40 | It("should add arg", func() { 41 | var foo string 42 | c.AddArg(&foo) 43 | Expect(len(c.Args)).To(Equal(1)) 44 | }) 45 | }) 46 | 47 | Describe("ParseArgs", func() { 48 | var ( 49 | f cobra.PositionalArgs 50 | ) 51 | 52 | JustBeforeEach(func() { 53 | f = c.ParseArgs() 54 | }) 55 | 56 | It("should do nothing when Args are nil", func() { 57 | f := c.ParseArgs() 58 | f(nil, []string{"foo"}) 59 | }) 60 | 61 | It("should do nothing when input args are nil", func() { 62 | var foo string 63 | c.AddArg(&foo) 64 | f(nil, nil) 65 | Expect(len(foo)).To(BeZero()) 66 | }) 67 | 68 | It("should set variable", func() { 69 | var foo string 70 | c.AddArg(&foo) 71 | f(nil, []string{"foo"}) 72 | Expect(foo).To(Equal("foo")) 73 | }) 74 | }) 75 | }) 76 | -------------------------------------------------------------------------------- /cmd/commands/network/list.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package network 8 | 9 | import ( 10 | "errors" 11 | "fmt" 12 | "sort" 13 | 14 | "github.com/hyperledger/fabric-cli/cmd/common" 15 | "github.com/hyperledger/fabric-cli/pkg/environment" 16 | "github.com/spf13/cobra" 17 | ) 18 | 19 | // NewNetworkListCommand creates a new "fabric network list" command 20 | func NewNetworkListCommand(settings *environment.Settings) *cobra.Command { 21 | c := ListCommand{} 22 | 23 | c.Settings = settings 24 | 25 | cmd := &cobra.Command{ 26 | Use: "list", 27 | Short: "List all networks", 28 | Long: "List all networks in config.yaml", 29 | RunE: func(_ *cobra.Command, _ []string) error { 30 | return c.Run() 31 | }, 32 | } 33 | 34 | cmd.SetOutput(c.Settings.Streams.Out) 35 | 36 | return cmd 37 | } 38 | 39 | // ListCommand implements the network list command 40 | type ListCommand struct { 41 | common.Command 42 | } 43 | 44 | // Run executes the command 45 | func (c *ListCommand) Run() error { 46 | if len(c.Settings.Config.Networks) == 0 { 47 | return errors.New("no networks currently exist") 48 | } 49 | 50 | context, _ := c.Settings.Config.GetCurrentContext() 51 | 52 | var names []string 53 | for name := range c.Settings.Config.Networks { 54 | if context != nil && name == context.Network { 55 | name += " (current)" 56 | } 57 | names = append(names, name) 58 | } 59 | 60 | sort.Strings(names) 61 | 62 | for _, name := range names { 63 | fmt.Fprintln(c.Settings.Streams.Out, name) 64 | } 65 | 66 | return nil 67 | } 68 | -------------------------------------------------------------------------------- /cmd/commands/plugin/plugin_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package plugin_test 8 | 9 | import ( 10 | "bytes" 11 | "fmt" 12 | "os" 13 | "testing" 14 | 15 | . "github.com/onsi/ginkgo" 16 | . "github.com/onsi/gomega" 17 | "github.com/spf13/cobra" 18 | 19 | "github.com/hyperledger/fabric-cli/cmd/commands/plugin" 20 | "github.com/hyperledger/fabric-cli/pkg/environment" 21 | ) 22 | 23 | func TestPlugin(t *testing.T) { 24 | RegisterFailHandler(Fail) 25 | RunSpecs(t, "Plugin Suite") 26 | } 27 | 28 | var _ = Describe("PluginCommand", func() { 29 | var ( 30 | cmd *cobra.Command 31 | settings *environment.Settings 32 | out *bytes.Buffer 33 | ) 34 | 35 | Context("when creating a command from settings", func() { 36 | BeforeEach(func() { 37 | out = new(bytes.Buffer) 38 | 39 | settings = &environment.Settings{ 40 | Home: environment.Home(os.TempDir()), 41 | Streams: environment.Streams{ 42 | Out: out, 43 | }, 44 | } 45 | }) 46 | 47 | JustBeforeEach(func() { 48 | cmd = plugin.NewPluginCommand(settings) 49 | }) 50 | 51 | It("should create a plugin command", func() { 52 | Expect(cmd.Name()).To(Equal("plugin")) 53 | Expect(cmd.HasSubCommands()).To(BeTrue()) 54 | Expect(cmd.Execute()).Should(Succeed()) 55 | Expect(fmt.Sprint(out)).To(ContainSubstring("plugin [command]")) 56 | Expect(fmt.Sprint(out)).To(ContainSubstring("list")) 57 | Expect(fmt.Sprint(out)).To(ContainSubstring("install")) 58 | Expect(fmt.Sprint(out)).To(ContainSubstring("uninstall")) 59 | }) 60 | }) 61 | }) 62 | -------------------------------------------------------------------------------- /pkg/environment/home_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package environment_test 8 | 9 | import ( 10 | "os" 11 | "path/filepath" 12 | 13 | "github.com/hyperledger/fabric-cli/pkg/environment" 14 | . "github.com/onsi/ginkgo" 15 | . "github.com/onsi/gomega" 16 | ) 17 | 18 | var _ = Describe("Home", func() { 19 | var ( 20 | home environment.Home 21 | ) 22 | 23 | BeforeEach(func() { 24 | home = environment.Home(TestPath) 25 | }) 26 | 27 | Describe("String", func() { 28 | var path string 29 | 30 | JustBeforeEach(func() { 31 | path = home.String() 32 | }) 33 | 34 | It("should equal test path", func() { 35 | Expect(path).To(Equal(TestPath)) 36 | }) 37 | }) 38 | 39 | Describe("Path", func() { 40 | var path string 41 | 42 | JustBeforeEach(func() { 43 | path = home.Path("test") 44 | }) 45 | 46 | It("should append to home path", func() { 47 | Expect(path).To(Equal(filepath.Join(TestPath, "test"))) 48 | }) 49 | }) 50 | 51 | Describe("Plugins", func() { 52 | var path string 53 | 54 | JustBeforeEach(func() { 55 | path = home.Plugins() 56 | }) 57 | 58 | It("should return plugins path", func() { 59 | Expect(path).To(Equal(filepath.Join(TestPath, "plugins"))) 60 | }) 61 | }) 62 | 63 | Describe("Init", func() { 64 | var err error 65 | 66 | JustBeforeEach(func() { 67 | err = home.Init() 68 | }) 69 | 70 | JustAfterEach(func() { 71 | os.RemoveAll(TestPath) 72 | }) 73 | 74 | It("should initialize home path", func() { 75 | Expect(err).To(BeNil()) 76 | }) 77 | }) 78 | }) 79 | -------------------------------------------------------------------------------- /cmd/commands/channel/channel.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package channel 8 | 9 | import ( 10 | "github.com/spf13/cobra" 11 | 12 | "github.com/hyperledger/fabric-cli/cmd/common" 13 | "github.com/hyperledger/fabric-cli/pkg/environment" 14 | "github.com/hyperledger/fabric-cli/pkg/fabric" 15 | ) 16 | 17 | // NewChannelCommand creates a new "fabric channel" command 18 | func NewChannelCommand(settings *environment.Settings) *cobra.Command { 19 | cmd := &cobra.Command{ 20 | Use: "channel", 21 | Short: "Manage channels", 22 | Long: "Manage channels with config|create|join|list|update", 23 | } 24 | 25 | cmd.AddCommand( 26 | NewChannelCreateCommand(settings), 27 | NewChannelJoinCommand(settings), 28 | NewChannelUpdateCommand(settings), 29 | NewChannelListCommand(settings), 30 | NewChannelConfigCommand(settings), 31 | ) 32 | 33 | cmd.SetOutput(settings.Streams.Out) 34 | 35 | return cmd 36 | } 37 | 38 | // BaseCommand implements common channel command functions 39 | type BaseCommand struct { 40 | common.Command 41 | 42 | Factory fabric.Factory 43 | ResourceManagement fabric.ResourceManagement 44 | } 45 | 46 | // Complete initializes all clients needed for Run 47 | func (c *BaseCommand) Complete() error { 48 | var err error 49 | 50 | if c.Factory == nil { 51 | c.Factory, err = fabric.NewFactory(c.Settings.Config) 52 | if err != nil { 53 | return err 54 | } 55 | } 56 | 57 | c.ResourceManagement, err = c.Factory.ResourceManagement() 58 | if err != nil { 59 | return err 60 | } 61 | 62 | return nil 63 | } 64 | -------------------------------------------------------------------------------- /cmd/commands/common/common_test.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | const sampleCollectionsConfigGood = `[ 10 | { 11 | "name": "foo", 12 | "policy": "OR('A.member', 'B.member')", 13 | "requiredPeerCount": 3, 14 | "maxPeerCount": 483279847, 15 | "blockToLive":10, 16 | "memberOnlyRead": true, 17 | "memberOnlyWrite": true 18 | } 19 | ]` 20 | 21 | const sampleCollectionsConfigBad = `[ 22 | { 23 | "name": "foo", 24 | "policy": "barf", 25 | "requiredPeerCount": 3, 26 | "maxPeerCount": 483279847 27 | } 28 | ]` 29 | 30 | func TestGetCollectionsConfigFromBytes(t *testing.T) { 31 | config, err := GetCollectionsConfigFromBytes([]byte(sampleCollectionsConfigGood)) 32 | assert.Nil(t, err) 33 | assert.NotNil(t, config) 34 | } 35 | 36 | func TestGetCollectionsConfigFromBytesError(t *testing.T) { 37 | config, err := GetCollectionsConfigFromBytes([]byte(sampleCollectionsConfigBad)) 38 | assert.NotNil(t, err) 39 | assert.Nil(t, config) 40 | } 41 | 42 | func TestGetChaincodePolicy(t *testing.T) { 43 | policy, err := GetChaincodePolicy("OR('MSP.member', 'MSP.WITH.DOTS.member', 'MSP-WITH-DASHES.member')") 44 | assert.Nil(t, err) 45 | assert.NotNil(t, policy) 46 | } 47 | 48 | func TestGetChaincodePolicyError(t *testing.T) { 49 | policy, err := GetChaincodePolicy("NOT A VALID POLICY)") 50 | assert.NotNil(t, err) 51 | assert.Nil(t, policy) 52 | } 53 | 54 | func TestAsByteArgs(t *testing.T) { 55 | args := AsByteArgs([]string{"arg1", "arg2"}) 56 | assert.Len(t, args, 2) 57 | assert.Equal(t, "arg1", string(args[0])) 58 | assert.Equal(t, "arg2", string(args[1])) 59 | } 60 | -------------------------------------------------------------------------------- /cmd/commands/network/view.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package network 8 | 9 | import ( 10 | "fmt" 11 | 12 | "github.com/hyperledger/fabric-cli/cmd/common" 13 | "github.com/hyperledger/fabric-cli/pkg/environment" 14 | "github.com/spf13/cobra" 15 | ) 16 | 17 | // NewNetworkViewCommand creates a new "fabric network view" command 18 | func NewNetworkViewCommand(settings *environment.Settings) *cobra.Command { 19 | c := ViewCommand{} 20 | 21 | c.Settings = settings 22 | 23 | cmd := &cobra.Command{ 24 | Use: "view [network-name]", 25 | Short: "View a network", 26 | Long: "View a network, to show the Fabric Go SDK config path, default current context's network", 27 | Args: c.ParseArgs(), 28 | RunE: func(_ *cobra.Command, _ []string) error { 29 | return c.Run() 30 | }, 31 | } 32 | 33 | c.AddArg(&c.Name) 34 | 35 | cmd.SetOutput(c.Settings.Streams.Out) 36 | 37 | return cmd 38 | } 39 | 40 | // ViewCommand implements the current command 41 | type ViewCommand struct { 42 | common.Command 43 | 44 | Name string 45 | } 46 | 47 | // Run executes the command 48 | func (c *ViewCommand) Run() error { 49 | if len(c.Name) == 0 { 50 | context, err := c.Settings.Config.GetCurrentContext() 51 | if err != nil { 52 | return err 53 | } 54 | 55 | c.Name = context.Network 56 | } 57 | 58 | network, ok := c.Settings.Config.Networks[c.Name] 59 | if !ok { 60 | return fmt.Errorf("network '%s' does not exist", c.Name) 61 | } 62 | 63 | fmt.Fprintln(c.Settings.Streams.Out, "Name: ", c.Name) 64 | fmt.Fprintln(c.Settings.Streams.Out, network) 65 | 66 | return nil 67 | } 68 | -------------------------------------------------------------------------------- /cmd/commands/network/network_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package network_test 8 | 9 | import ( 10 | "bytes" 11 | "fmt" 12 | "os" 13 | "testing" 14 | 15 | . "github.com/onsi/ginkgo" 16 | . "github.com/onsi/gomega" 17 | "github.com/spf13/cobra" 18 | 19 | "github.com/hyperledger/fabric-cli/cmd/commands/network" 20 | "github.com/hyperledger/fabric-cli/pkg/environment" 21 | ) 22 | 23 | func TestNetwork(t *testing.T) { 24 | RegisterFailHandler(Fail) 25 | RunSpecs(t, "Network Suite") 26 | } 27 | 28 | var _ = Describe("NetworkCommand", func() { 29 | var ( 30 | cmd *cobra.Command 31 | settings *environment.Settings 32 | out *bytes.Buffer 33 | ) 34 | 35 | Context("when creating a command from settings", func() { 36 | BeforeEach(func() { 37 | out = new(bytes.Buffer) 38 | 39 | settings = &environment.Settings{ 40 | Home: environment.Home(os.TempDir()), 41 | Streams: environment.Streams{ 42 | Out: out, 43 | }, 44 | } 45 | }) 46 | 47 | JustBeforeEach(func() { 48 | cmd = network.NewNetworkCommand(settings) 49 | }) 50 | 51 | It("should create a network command", func() { 52 | Expect(cmd.Name()).To(Equal("network")) 53 | Expect(cmd.HasSubCommands()).To(BeTrue()) 54 | Expect(cmd.Execute()).Should(Succeed()) 55 | Expect(fmt.Sprint(out)).To(ContainSubstring("network [command]")) 56 | Expect(fmt.Sprint(out)).To(ContainSubstring("view")) 57 | Expect(fmt.Sprint(out)).To(ContainSubstring("list")) 58 | Expect(fmt.Sprint(out)).To(ContainSubstring("set")) 59 | Expect(fmt.Sprint(out)).To(ContainSubstring("delete")) 60 | }) 61 | }) 62 | }) 63 | -------------------------------------------------------------------------------- /cmd/commands/context/delete.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package context 8 | 9 | import ( 10 | "errors" 11 | "fmt" 12 | 13 | "github.com/hyperledger/fabric-cli/cmd/common" 14 | "github.com/hyperledger/fabric-cli/pkg/environment" 15 | "github.com/spf13/cobra" 16 | ) 17 | 18 | // NewContextDeleteCommand creates a new "fabric context delete" command 19 | func NewContextDeleteCommand(settings *environment.Settings) *cobra.Command { 20 | c := DeleteCommand{} 21 | 22 | c.Settings = settings 23 | 24 | cmd := &cobra.Command{ 25 | Use: "delete ", 26 | Short: "Delete a context", 27 | Long: "Delete a context in config.yaml", 28 | Args: c.ParseArgs(), 29 | PreRunE: func(_ *cobra.Command, _ []string) error { 30 | return c.Validate() 31 | }, 32 | RunE: func(_ *cobra.Command, _ []string) error { 33 | return c.Run() 34 | }, 35 | } 36 | 37 | c.AddArg(&c.Name) 38 | 39 | cmd.SetOutput(c.Settings.Streams.Out) 40 | 41 | return cmd 42 | } 43 | 44 | // DeleteCommand implements the delete context command 45 | type DeleteCommand struct { 46 | common.Command 47 | 48 | Name string 49 | } 50 | 51 | // Validate checks the required parameters for run 52 | func (c *DeleteCommand) Validate() error { 53 | if len(c.Name) == 0 { 54 | return errors.New("context name not specified") 55 | } 56 | 57 | return nil 58 | } 59 | 60 | // Run executes the command 61 | func (c *DeleteCommand) Run() error { 62 | err := c.Settings.ModifyConfig(environment.DeleteContext(c.Name)) 63 | if err != nil { 64 | return err 65 | } 66 | 67 | fmt.Fprintf(c.Settings.Streams.Out, "successfully deleted context '%s'\n", c.Name) 68 | 69 | return nil 70 | } 71 | -------------------------------------------------------------------------------- /cmd/commands/channel/list.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package channel 8 | 9 | import ( 10 | "fmt" 11 | 12 | "github.com/hyperledger/fabric-sdk-go/pkg/client/resmgmt" 13 | "github.com/spf13/cobra" 14 | 15 | "github.com/hyperledger/fabric-cli/pkg/environment" 16 | ) 17 | 18 | // NewChannelListCommand creates a new "fabric channel list" command 19 | func NewChannelListCommand(settings *environment.Settings) *cobra.Command { 20 | c := ListCommand{} 21 | 22 | c.Settings = settings 23 | 24 | cmd := &cobra.Command{ 25 | Use: "list", 26 | Short: "List all joined channels", 27 | Long: "List all joined channels, peer is the current context's peer", 28 | PreRunE: func(_ *cobra.Command, _ []string) error { 29 | return c.Complete() 30 | }, 31 | RunE: func(_ *cobra.Command, _ []string) error { 32 | return c.Run() 33 | }, 34 | } 35 | 36 | cmd.SetOutput(c.Settings.Streams.Out) 37 | 38 | return cmd 39 | } 40 | 41 | // ListCommand implements the channel list command 42 | type ListCommand struct { 43 | BaseCommand 44 | } 45 | 46 | // Run executes the command 47 | func (c *ListCommand) Run() error { 48 | context, err := c.Settings.Config.GetCurrentContext() 49 | if err != nil { 50 | return err 51 | } 52 | 53 | options := []resmgmt.RequestOption{ 54 | resmgmt.WithTargetEndpoints(context.Peers...), 55 | } 56 | 57 | resp, err := c.ResourceManagement.QueryChannels(options...) 58 | if err != nil { 59 | return err 60 | } 61 | 62 | fmt.Fprintln(c.Settings.Streams.Out, "Channels Joined:") 63 | for _, channel := range resp.Channels { 64 | fmt.Fprintf(c.Settings.Streams.Out, " - %s\n", channel.ChannelId) 65 | } 66 | 67 | return nil 68 | } 69 | -------------------------------------------------------------------------------- /cmd/commands/context/context_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package context_test 8 | 9 | import ( 10 | "bytes" 11 | "fmt" 12 | "os" 13 | "testing" 14 | 15 | . "github.com/onsi/ginkgo" 16 | . "github.com/onsi/gomega" 17 | "github.com/spf13/cobra" 18 | 19 | "github.com/hyperledger/fabric-cli/cmd/commands/context" 20 | "github.com/hyperledger/fabric-cli/pkg/environment" 21 | ) 22 | 23 | func TestContext(t *testing.T) { 24 | RegisterFailHandler(Fail) 25 | RunSpecs(t, "Context Suite") 26 | } 27 | 28 | var _ = Describe("ContextCommand", func() { 29 | var ( 30 | cmd *cobra.Command 31 | settings *environment.Settings 32 | out *bytes.Buffer 33 | ) 34 | 35 | Context("when creating a command from settings", func() { 36 | BeforeEach(func() { 37 | out = new(bytes.Buffer) 38 | 39 | settings = &environment.Settings{ 40 | Home: environment.Home(os.TempDir()), 41 | Streams: environment.Streams{ 42 | Out: out, 43 | }, 44 | } 45 | }) 46 | 47 | JustBeforeEach(func() { 48 | cmd = context.NewContextCommand(settings) 49 | }) 50 | 51 | It("should create a context command", func() { 52 | Expect(cmd.Name()).To(Equal("context")) 53 | Expect(cmd.HasSubCommands()).To(BeTrue()) 54 | Expect(cmd.Execute()).Should(Succeed()) 55 | Expect(fmt.Sprint(out)).To(ContainSubstring("context [command]")) 56 | Expect(fmt.Sprint(out)).To(ContainSubstring("view")) 57 | Expect(fmt.Sprint(out)).To(ContainSubstring("use")) 58 | Expect(fmt.Sprint(out)).To(ContainSubstring("list")) 59 | Expect(fmt.Sprint(out)).To(ContainSubstring("set")) 60 | Expect(fmt.Sprint(out)).To(ContainSubstring("delete")) 61 | }) 62 | }) 63 | }) 64 | -------------------------------------------------------------------------------- /cmd/commands/context/use.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package context 8 | 9 | import ( 10 | "errors" 11 | "fmt" 12 | 13 | "github.com/hyperledger/fabric-cli/cmd/common" 14 | "github.com/hyperledger/fabric-cli/pkg/environment" 15 | "github.com/spf13/cobra" 16 | ) 17 | 18 | // NewContextUseCommand creates a new "fabric context use" command 19 | func NewContextUseCommand(settings *environment.Settings) *cobra.Command { 20 | c := UseCommand{} 21 | 22 | c.Settings = settings 23 | 24 | cmd := &cobra.Command{ 25 | Use: "use ", 26 | Short: "Change current context", 27 | Long: "Change current context to context-name", 28 | Args: c.ParseArgs(), 29 | PreRunE: func(_ *cobra.Command, _ []string) error { 30 | return c.Validate() 31 | }, 32 | RunE: func(_ *cobra.Command, _ []string) error { 33 | return c.Run() 34 | }, 35 | } 36 | 37 | c.AddArg(&c.Name) 38 | 39 | cmd.SetOutput(c.Settings.Streams.Out) 40 | 41 | return cmd 42 | } 43 | 44 | // UseCommand implements the use context command 45 | type UseCommand struct { 46 | common.Command 47 | 48 | Name string 49 | } 50 | 51 | // Validate checks the required parameters for run 52 | func (c *UseCommand) Validate() error { 53 | if len(c.Name) == 0 { 54 | return errors.New("context id not specified") 55 | } 56 | 57 | if _, ok := c.Settings.Config.Contexts[c.Name]; !ok { 58 | return fmt.Errorf("context '%s' does not exist", c.Name) 59 | } 60 | 61 | return nil 62 | } 63 | 64 | // Run executes the command 65 | func (c *UseCommand) Run() error { 66 | err := c.Settings.ModifyConfig(environment.SetCurrentContext(c.Name)) 67 | if err != nil { 68 | return err 69 | } 70 | 71 | fmt.Fprintf(c.Settings.Streams.Out, "successfully set current context to '%s'\n", c.Name) 72 | 73 | return nil 74 | } 75 | -------------------------------------------------------------------------------- /pkg/environment/actions.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package environment 8 | 9 | // Action is used to modify config 10 | type Action func(c *Config) 11 | 12 | // SetCurrentContext updates the current context 13 | func SetCurrentContext(context string) Action { 14 | return func(c *Config) { 15 | c.CurrentContext = context 16 | } 17 | } 18 | 19 | // SetContext adds or updates the specified context 20 | func SetContext(name string, context *Context) Action { 21 | return func(c *Config) { 22 | current, ok := c.Contexts[name] 23 | if !ok { 24 | c.Contexts[name] = context 25 | return 26 | } 27 | 28 | // override existing keys if context already exists 29 | 30 | if len(context.Network) > 0 { 31 | current.Network = context.Network 32 | } 33 | 34 | if len(context.Organization) > 0 { 35 | current.Organization = context.Organization 36 | } 37 | 38 | if len(context.User) > 0 { 39 | current.User = context.User 40 | } 41 | 42 | if len(context.Channel) > 0 { 43 | current.Channel = context.Channel 44 | } 45 | 46 | if len(context.Orderers) > 0 { 47 | current.Orderers = context.Orderers 48 | } 49 | 50 | if len(context.Peers) > 0 { 51 | current.Peers = context.Peers 52 | } 53 | } 54 | } 55 | 56 | // DeleteContext deletes a specified context 57 | func DeleteContext(name string) Action { 58 | return func(c *Config) { 59 | delete(c.Contexts, name) 60 | } 61 | } 62 | 63 | // SetNetwork adds or updates the specified network 64 | func SetNetwork(name string, network *Network) Action { 65 | return func(c *Config) { 66 | c.Networks[name] = network 67 | } 68 | } 69 | 70 | // DeleteNetwork deletes the specified network 71 | func DeleteNetwork(name string) Action { 72 | return func(c *Config) { 73 | delete(c.Networks, name) 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /cmd/commands/plugin/list.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package plugin 8 | 9 | import ( 10 | "fmt" 11 | 12 | "github.com/spf13/cobra" 13 | 14 | "github.com/hyperledger/fabric-cli/cmd/common" 15 | "github.com/hyperledger/fabric-cli/pkg/environment" 16 | "github.com/hyperledger/fabric-cli/pkg/plugin" 17 | ) 18 | 19 | // NewPluginListCommand creates a new "fabric plugin list" command 20 | func NewPluginListCommand(settings *environment.Settings) *cobra.Command { 21 | c := ListCommand{} 22 | 23 | c.Settings = settings 24 | 25 | cmd := &cobra.Command{ 26 | Use: "list", 27 | Short: "List all installed plugins", 28 | Long: "List all installed plugins in the home/plugins dir", 29 | PreRunE: func(cmd *cobra.Command, args []string) error { 30 | return c.Complete() 31 | }, 32 | RunE: func(_ *cobra.Command, _ []string) error { 33 | return c.Run() 34 | }, 35 | } 36 | 37 | cmd.SetOutput(c.Settings.Streams.Out) 38 | 39 | return cmd 40 | } 41 | 42 | // ListCommand implements the plugin list command 43 | type ListCommand struct { 44 | common.Command 45 | Handler plugin.Handler 46 | } 47 | 48 | // Run executes the command 49 | func (c *ListCommand) Run() error { 50 | plugins, err := c.Handler.GetPlugins() 51 | if err != nil { 52 | return err 53 | } 54 | 55 | if len(plugins) == 0 { 56 | fmt.Fprintln(c.Settings.Streams.Out, "no plugins currently exist") 57 | return nil 58 | } 59 | 60 | for _, plugin := range plugins { 61 | fmt.Fprint(c.Settings.Streams.Out, plugin.Name, "\n") 62 | } 63 | 64 | return nil 65 | } 66 | 67 | // Complete initializes the plugin handler 68 | func (c *ListCommand) Complete() error { 69 | c.Handler = &plugin.DefaultHandler{ 70 | Dir: c.Settings.Home.Plugins(), 71 | Filename: plugin.DefaultFilename, 72 | } 73 | return nil 74 | } 75 | -------------------------------------------------------------------------------- /cmd/commands/version/version.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2019 TopJohn 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package version 17 | 18 | import ( 19 | "fmt" 20 | "github.com/hyperledger/fabric-cli/common/metadata" 21 | "github.com/hyperledger/fabric-cli/pkg/environment" 22 | "github.com/spf13/cobra" 23 | "runtime" 24 | ) 25 | 26 | //Program name 27 | const ProgramName = "fabric" 28 | 29 | //NewVersionCommand creates a new "fabric version" command 30 | func NewVersionCommand(settings *environment.Settings) *cobra.Command { 31 | cmd := &cobra.Command{ 32 | Use: "version", 33 | Short: "Print fabric cmd version", 34 | Long: "Print current version of fabric command line tool", 35 | RunE: func(cmd *cobra.Command, args []string) error { 36 | if len(args) != 0 { 37 | return fmt.Errorf("trailing args detected") 38 | } 39 | cmd.SilenceUsage = true 40 | fmt.Print(GetMetaInfo()) 41 | return nil 42 | }, 43 | } 44 | cmd.SetOutput(settings.Streams.Out) 45 | return cmd 46 | } 47 | 48 | //GetMetaInfo returns version information for the fabric cmd. 49 | func GetMetaInfo() string { 50 | return fmt.Sprintf("%s:\n Version: %s\n Commit SHA: %s\n Go Version: %s\n"+ 51 | " OS/Arch: %s\n", 52 | ProgramName, metadata.Version, metadata.CommitSHA, runtime.Version(), 53 | fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH)) 54 | } 55 | -------------------------------------------------------------------------------- /cmd/commands/network/delete.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package network 8 | 9 | import ( 10 | "errors" 11 | "fmt" 12 | "github.com/hyperledger/fabric-cli/cmd/common" 13 | "github.com/hyperledger/fabric-cli/pkg/environment" 14 | "github.com/spf13/cobra" 15 | ) 16 | 17 | // NewNetworkDeleteCommand creates a new "fabric network delete" command 18 | func NewNetworkDeleteCommand(settings *environment.Settings) *cobra.Command { 19 | c := DeleteCommand{} 20 | 21 | c.Settings = settings 22 | 23 | cmd := &cobra.Command{ 24 | Use: "delete ", 25 | Short: "Delete a network", 26 | Long: "Delete a network in config.yaml", 27 | Args: c.ParseArgs(), 28 | PreRunE: func(_ *cobra.Command, _ []string) error { 29 | return c.Validate() 30 | }, 31 | RunE: func(_ *cobra.Command, _ []string) error { 32 | return c.Run() 33 | }, 34 | } 35 | 36 | c.AddArg(&c.Name) 37 | 38 | cmd.SetOutput(c.Settings.Streams.Out) 39 | 40 | return cmd 41 | } 42 | 43 | // DeleteCommand implements the network delete command 44 | type DeleteCommand struct { 45 | common.Command 46 | 47 | Name string 48 | } 49 | 50 | // Validate checks the required parameters for run 51 | func (c *DeleteCommand) Validate() error { 52 | if len(c.Name) == 0 { 53 | return errors.New("network name not specified") 54 | } 55 | 56 | return nil 57 | } 58 | 59 | // Run executes the command 60 | func (c *DeleteCommand) Run() error { 61 | 62 | if _, ok := c.Settings.Config.Networks[c.Name]; !ok { 63 | err := fmt.Sprintf("network %s doesn't exist", c.Name) 64 | return errors.New(err) 65 | } 66 | 67 | err := c.Settings.ModifyConfig(environment.DeleteNetwork(c.Name)) 68 | if err != nil { 69 | return err 70 | } 71 | 72 | fmt.Fprintf(c.Settings.Streams.Out, "successfully deleted network '%s'\n", c.Name) 73 | 74 | return nil 75 | } 76 | -------------------------------------------------------------------------------- /cmd/commands/chaincode/chaincode.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package chaincode 8 | 9 | import ( 10 | "github.com/spf13/cobra" 11 | 12 | "github.com/hyperledger/fabric-cli/cmd/common" 13 | "github.com/hyperledger/fabric-cli/pkg/environment" 14 | "github.com/hyperledger/fabric-cli/pkg/fabric" 15 | ) 16 | 17 | // NewChaincodeCommand creates a new "fabric chaincode" command 18 | func NewChaincodeCommand(settings *environment.Settings) *cobra.Command { 19 | cmd := &cobra.Command{ 20 | Use: "chaincode", 21 | Short: "Manage chaincode", 22 | Long: "Manage chaincode with events|install|instantiate|invoke|list|package|query|upgrade", 23 | } 24 | 25 | cmd.AddCommand( 26 | NewChaincodeListCommand(settings), 27 | NewChaincodePackageCommand(settings), 28 | NewChaincodeInstallCommand(settings), 29 | NewChaincodeInstantiateCommand(settings), 30 | NewChaincodeUpgradeCommand(settings), 31 | NewChaincodeQueryCommand(settings), 32 | NewChaincodeInvokeCommand(settings), 33 | NewChaincodeEventsCommand(settings), 34 | ) 35 | 36 | cmd.SetOutput(settings.Streams.Out) 37 | 38 | return cmd 39 | } 40 | 41 | // BaseCommand implements common channel command functions 42 | type BaseCommand struct { 43 | common.Command 44 | 45 | Factory fabric.Factory 46 | Channel fabric.Channel 47 | ResourceManagement fabric.ResourceManagement 48 | } 49 | 50 | // Complete initializes all clients needed for Run 51 | func (c *BaseCommand) Complete() error { 52 | var err error 53 | 54 | if c.Factory == nil { 55 | c.Factory, err = fabric.NewFactory(c.Settings.Config) 56 | if err != nil { 57 | return err 58 | } 59 | } 60 | 61 | c.Channel, err = c.Factory.Channel() 62 | if err != nil { 63 | return err 64 | } 65 | 66 | c.ResourceManagement, err = c.Factory.ResourceManagement() 67 | if err != nil { 68 | return err 69 | } 70 | 71 | return nil 72 | } 73 | -------------------------------------------------------------------------------- /cmd/commands/chaincode/events.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package chaincode 8 | 9 | import ( 10 | "errors" 11 | "fmt" 12 | 13 | "github.com/spf13/cobra" 14 | 15 | "github.com/hyperledger/fabric-cli/pkg/environment" 16 | ) 17 | 18 | // NewChaincodeEventsCommand creates a new "fabric chaincode events" command 19 | func NewChaincodeEventsCommand(settings *environment.Settings) *cobra.Command { 20 | c := EventsCommand{} 21 | 22 | c.Settings = settings 23 | 24 | cmd := &cobra.Command{ 25 | Use: "events ", 26 | Short: "Listen for chaincode events", 27 | Long: "Listen for chaincode-name events", 28 | Args: c.ParseArgs(), 29 | PreRunE: func(_ *cobra.Command, _ []string) error { 30 | if err := c.Complete(); err != nil { 31 | return err 32 | } 33 | 34 | if err := c.Validate(); err != nil { 35 | return err 36 | } 37 | 38 | return nil 39 | }, 40 | RunE: func(_ *cobra.Command, _ []string) error { 41 | return c.Run() 42 | }, 43 | } 44 | 45 | c.AddArg(&c.ChaincodeName) 46 | 47 | cmd.SetOutput(c.Settings.Streams.Out) 48 | 49 | return cmd 50 | } 51 | 52 | // EventsCommand implements the chaincode events command 53 | type EventsCommand struct { 54 | BaseCommand 55 | 56 | ChaincodeName string 57 | } 58 | 59 | // Validate checks the required parameters for run 60 | func (c *EventsCommand) Validate() error { 61 | if len(c.ChaincodeName) == 0 { 62 | return errors.New("chaincode name not specified") 63 | } 64 | 65 | return nil 66 | } 67 | 68 | // Run executes the command 69 | func (c *EventsCommand) Run() error { 70 | registration, eventCh, err := c.Channel.RegisterChaincodeEvent(c.ChaincodeName, "") 71 | if err != nil { 72 | return err 73 | } 74 | 75 | defer c.Channel.UnregisterChaincodeEvent(registration) 76 | 77 | for event := range eventCh { 78 | fmt.Fprintln(c.Settings.Streams.Out, string(event.Payload)) 79 | } 80 | 81 | return nil 82 | } 83 | -------------------------------------------------------------------------------- /cmd/commands/chaincode/package.go: -------------------------------------------------------------------------------- 1 | package chaincode 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "io/ioutil" 7 | 8 | "github.com/hyperledger/fabric-cli/pkg/environment" 9 | "github.com/hyperledger/fabric-sdk-go/pkg/fab/ccpackager/gopackager" 10 | "github.com/spf13/cobra" 11 | ) 12 | 13 | // NewChaincodePackageCommand creates a new "fabric chaincode package" command 14 | func NewChaincodePackageCommand(settings *environment.Settings) *cobra.Command { 15 | c := PackageCommand{} 16 | 17 | c.Settings = settings 18 | 19 | cmd := &cobra.Command{ 20 | Use: "package ", 21 | Short: "Package a chaincode (only golang supported)", 22 | Long: "Package a chaincode into .tgz (only golang supported)", 23 | Args: c.ParseArgs(), 24 | PreRunE: func(_ *cobra.Command, _ []string) error { 25 | return c.Validate() 26 | }, 27 | RunE: func(_ *cobra.Command, _ []string) error { 28 | return c.Run() 29 | }, 30 | } 31 | 32 | c.AddArg(&c.ChaincodeName) 33 | c.AddArg(&c.ChaincodePath) 34 | 35 | cmd.SetOutput(c.Settings.Streams.Out) 36 | 37 | return cmd 38 | } 39 | 40 | // PackageCommand implements the chaincode package command 41 | type PackageCommand struct { 42 | BaseCommand 43 | 44 | ChaincodeName string 45 | ChaincodePath string 46 | } 47 | 48 | // Validate checks the required parameters for run 49 | func (c *PackageCommand) Validate() error { 50 | if len(c.ChaincodeName) == 0 { 51 | return errors.New("chaincode name not specified") 52 | } 53 | 54 | if len(c.ChaincodePath) == 0 { 55 | return errors.New("chaincode path not specified") 56 | } 57 | 58 | return nil 59 | } 60 | 61 | // Run executes the command 62 | func (c *PackageCommand) Run() error { 63 | pkg, err := gopackager.NewCCPackage(c.ChaincodePath, "") 64 | if err != nil { 65 | return err 66 | } 67 | 68 | if err := ioutil.WriteFile(fmt.Sprintf("./%s.tgz", c.ChaincodeName), pkg.Code, 0644); err != nil { 69 | return err 70 | } 71 | 72 | fmt.Fprintf(c.Settings.Streams.Out, "successfully packaged chaincode '%s'\n", c.ChaincodeName) 73 | 74 | return nil 75 | } 76 | -------------------------------------------------------------------------------- /cmd/commands/channel/join.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package channel 8 | 9 | import ( 10 | "errors" 11 | "fmt" 12 | 13 | "github.com/hyperledger/fabric-sdk-go/pkg/client/resmgmt" 14 | "github.com/spf13/cobra" 15 | 16 | "github.com/hyperledger/fabric-cli/pkg/environment" 17 | ) 18 | 19 | // NewChannelJoinCommand creates a new "fabric channel join" command 20 | func NewChannelJoinCommand(settings *environment.Settings) *cobra.Command { 21 | c := JoinCommand{} 22 | 23 | c.Settings = settings 24 | 25 | cmd := &cobra.Command{ 26 | Use: "join ", 27 | Short: "Join a channel", 28 | Long: "Join Peers to a created channel which is in current context", 29 | Args: c.ParseArgs(), 30 | PreRunE: func(_ *cobra.Command, _ []string) error { 31 | if err := c.Complete(); err != nil { 32 | return err 33 | } 34 | 35 | if err := c.Validate(); err != nil { 36 | return err 37 | } 38 | 39 | return nil 40 | }, 41 | RunE: func(_ *cobra.Command, _ []string) error { 42 | return c.Run() 43 | }, 44 | } 45 | 46 | c.AddArg(&c.ChannelID) 47 | 48 | cmd.SetOutput(c.Settings.Streams.Out) 49 | 50 | return cmd 51 | } 52 | 53 | // JoinCommand implements the channel join command 54 | type JoinCommand struct { 55 | BaseCommand 56 | 57 | ChannelID string 58 | } 59 | 60 | // Validate checks the required parameters for run 61 | func (c *JoinCommand) Validate() error { 62 | if len(c.ChannelID) == 0 { 63 | return errors.New("channel id not specified") 64 | } 65 | 66 | return nil 67 | } 68 | 69 | // Run executes the command 70 | func (c *JoinCommand) Run() error { 71 | context, err := c.Settings.Config.GetCurrentContext() 72 | if err != nil { 73 | return err 74 | } 75 | 76 | options := []resmgmt.RequestOption{ 77 | resmgmt.WithTargetEndpoints(context.Peers...), 78 | } 79 | 80 | if err := c.ResourceManagement.JoinChannel(c.ChannelID, options...); err != nil { 81 | return err 82 | } 83 | 84 | fmt.Fprintf(c.Settings.Streams.Out, "successfully joined channel '%s'\n", c.ChannelID) 85 | 86 | return nil 87 | } 88 | -------------------------------------------------------------------------------- /cmd/commands/network/set.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package network 8 | 9 | import ( 10 | "errors" 11 | "fmt" 12 | 13 | "github.com/hyperledger/fabric-cli/cmd/common" 14 | "github.com/hyperledger/fabric-cli/pkg/environment" 15 | "github.com/spf13/cobra" 16 | ) 17 | 18 | // NewNetworkSetCommand creates a new "fabric network set" command 19 | func NewNetworkSetCommand(settings *environment.Settings) *cobra.Command { 20 | c := SetCommand{ 21 | Network: new(environment.Network), 22 | } 23 | 24 | c.Settings = settings 25 | 26 | cmd := &cobra.Command{ 27 | Use: "set ", 28 | Short: "Set a network", 29 | Long: "Set a network, path indicates the Fabric Go SDK' config path", 30 | Args: c.ParseArgs(), 31 | PreRunE: func(_ *cobra.Command, _ []string) error { 32 | return c.Validate() 33 | }, 34 | RunE: func(_ *cobra.Command, _ []string) error { 35 | return c.Run() 36 | }, 37 | } 38 | 39 | c.AddArg(&c.Name) 40 | c.AddArg(&c.Network.ConfigPath) 41 | 42 | cmd.SetOutput(c.Settings.Streams.Out) 43 | 44 | return cmd 45 | } 46 | 47 | // SetCommand implements the network set command 48 | type SetCommand struct { 49 | common.Command 50 | 51 | Name string 52 | Network *environment.Network 53 | } 54 | 55 | // Validate checks the required parameters for run 56 | func (c *SetCommand) Validate() error { 57 | if len(c.Name) == 0 { 58 | return errors.New("network name not specified") 59 | } 60 | 61 | if c.Network == nil || len(c.Network.ConfigPath) == 0 { 62 | return errors.New("network configuration path not specified") 63 | } 64 | 65 | return nil 66 | } 67 | 68 | // Run executes the command 69 | func (c *SetCommand) Run() error { 70 | err := c.Settings.ModifyConfig(environment.SetNetwork(c.Name, c.Network)) 71 | if err != nil { 72 | return err 73 | } 74 | 75 | fmt.Fprintf(c.Settings.Streams.Out, "successfully set network '%s'\n", c.Name) 76 | fmt.Fprintln(c.Settings.Streams.Out, "") 77 | fmt.Fprintln(c.Settings.Streams.Out, c.Settings.Config.Networks[c.Name]) 78 | 79 | return nil 80 | } 81 | -------------------------------------------------------------------------------- /cmd/commands/plugin/uninstall.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package plugin 8 | 9 | import ( 10 | "errors" 11 | "fmt" 12 | 13 | "github.com/spf13/cobra" 14 | 15 | "github.com/hyperledger/fabric-cli/cmd/common" 16 | "github.com/hyperledger/fabric-cli/pkg/environment" 17 | "github.com/hyperledger/fabric-cli/pkg/plugin" 18 | ) 19 | 20 | // NewPluginUninstallCommand creates a new "fabric plugin uninstall" command 21 | func NewPluginUninstallCommand(settings *environment.Settings) *cobra.Command { 22 | c := UninstallCommand{} 23 | 24 | c.Settings = settings 25 | 26 | cmd := &cobra.Command{ 27 | Use: "uninstall ", 28 | Short: "Uninstall a plugin", 29 | Long: "Uninstall remove a plugin in home/plugin dir", 30 | Args: c.ParseArgs(), 31 | PreRunE: func(_ *cobra.Command, _ []string) error { 32 | if err := c.Complete(); err != nil { 33 | return err 34 | } 35 | 36 | return c.Validate() 37 | }, 38 | RunE: func(_ *cobra.Command, _ []string) error { 39 | return c.Run() 40 | }, 41 | } 42 | 43 | c.AddArg(&c.Name) 44 | 45 | cmd.SetOutput(c.Settings.Streams.Out) 46 | 47 | return cmd 48 | } 49 | 50 | // UninstallCommand implements the plugin uninstall command 51 | type UninstallCommand struct { 52 | common.Command 53 | Handler plugin.Handler 54 | 55 | Name string 56 | } 57 | 58 | // Validate checks the required parameters for run 59 | func (c *UninstallCommand) Validate() error { 60 | if len(c.Name) == 0 { 61 | return errors.New("plugin name not specified") 62 | } 63 | 64 | return nil 65 | } 66 | 67 | // Run executes the command 68 | func (c *UninstallCommand) Run() error { 69 | err := c.Handler.UninstallPlugin(c.Name) 70 | if err != nil { 71 | return err 72 | } 73 | 74 | fmt.Fprintln(c.Settings.Streams.Out, "successfully uninstalled the plugin") 75 | 76 | return nil 77 | } 78 | 79 | // Complete initializes the plugin handler 80 | func (c *UninstallCommand) Complete() error { 81 | c.Handler = &plugin.DefaultHandler{ 82 | Dir: c.Settings.Home.Plugins(), 83 | Filename: plugin.DefaultFilename, 84 | } 85 | return nil 86 | } 87 | -------------------------------------------------------------------------------- /cmd/commands/plugin/install.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package plugin 8 | 9 | import ( 10 | "errors" 11 | "fmt" 12 | 13 | "github.com/spf13/cobra" 14 | 15 | "github.com/hyperledger/fabric-cli/cmd/common" 16 | "github.com/hyperledger/fabric-cli/pkg/environment" 17 | "github.com/hyperledger/fabric-cli/pkg/plugin" 18 | ) 19 | 20 | // NewPluginInstallCommand creates a new "fabric plugin install" command 21 | func NewPluginInstallCommand(settings *environment.Settings) *cobra.Command { 22 | c := InstallCommand{} 23 | 24 | c.Settings = settings 25 | 26 | cmd := &cobra.Command{ 27 | Use: "install ", 28 | Short: "Install a plugin from the local filesystem", 29 | Long: "Install a Go Plugin or custom cmd from the local filesystem", 30 | Args: c.ParseArgs(), 31 | PreRunE: func(_ *cobra.Command, _ []string) error { 32 | if err := c.Complete(); err != nil { 33 | return err 34 | } 35 | 36 | return c.Validate() 37 | }, 38 | RunE: func(_ *cobra.Command, _ []string) error { 39 | return c.Run() 40 | }, 41 | } 42 | 43 | c.AddArg(&c.Path) 44 | 45 | cmd.SetOutput(c.Settings.Streams.Out) 46 | 47 | return cmd 48 | } 49 | 50 | // InstallCommand implements the plugin install command 51 | type InstallCommand struct { 52 | common.Command 53 | Handler plugin.Handler 54 | 55 | Path string 56 | } 57 | 58 | // Validate checks the required parameters for run 59 | func (c *InstallCommand) Validate() error { 60 | if len(c.Path) == 0 { 61 | return errors.New("plugin path not specified") 62 | } 63 | 64 | return nil 65 | } 66 | 67 | // Run executes the command 68 | func (c *InstallCommand) Run() error { 69 | err := c.Handler.InstallPlugin(c.Path) 70 | if err != nil { 71 | return err 72 | } 73 | 74 | fmt.Fprintln(c.Settings.Streams.Out, "successfully installed the plugin") 75 | 76 | return nil 77 | } 78 | 79 | // Complete initializes the plugin handler 80 | func (c *InstallCommand) Complete() error { 81 | c.Handler = &plugin.DefaultHandler{ 82 | Dir: c.Settings.Home.Plugins(), 83 | Filename: plugin.DefaultFilename, 84 | } 85 | return nil 86 | } 87 | -------------------------------------------------------------------------------- /cmd/commands/channel/update.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package channel 8 | 9 | import ( 10 | "errors" 11 | "fmt" 12 | "os" 13 | 14 | "github.com/hyperledger/fabric-sdk-go/pkg/client/resmgmt" 15 | "github.com/spf13/cobra" 16 | 17 | "github.com/hyperledger/fabric-cli/pkg/environment" 18 | ) 19 | 20 | // NewChannelUpdateCommand creates a new "fabric channel update" command 21 | func NewChannelUpdateCommand(settings *environment.Settings) *cobra.Command { 22 | c := UpdateCommand{} 23 | 24 | c.Settings = settings 25 | 26 | cmd := &cobra.Command{ 27 | Use: "update ", 28 | Short: "Update a channel", 29 | Long: "Update a channel with channel-id and channel tx", 30 | PreRunE: func(_ *cobra.Command, _ []string) error { 31 | if err := c.Complete(); err != nil { 32 | return err 33 | } 34 | 35 | if err := c.Validate(); err != nil { 36 | return err 37 | } 38 | 39 | return nil 40 | }, 41 | RunE: func(_ *cobra.Command, _ []string) error { 42 | return c.Run() 43 | }, 44 | } 45 | 46 | cmd.SetOutput(c.Settings.Streams.Out) 47 | 48 | return cmd 49 | } 50 | 51 | // UpdateCommand implements the channel update command 52 | type UpdateCommand struct { 53 | BaseCommand 54 | 55 | ChannelID string 56 | ChannelTX string 57 | } 58 | 59 | // Validate checks the required parameters for run 60 | func (c *UpdateCommand) Validate() error { 61 | if len(c.ChannelID) == 0 { 62 | return errors.New("channel id not specified") 63 | } 64 | 65 | if len(c.ChannelTX) == 0 { 66 | return errors.New("channel tx path not specified") 67 | } 68 | 69 | return nil 70 | } 71 | 72 | // Run executes the command 73 | func (c *UpdateCommand) Run() error { 74 | r, err := os.Open(c.ChannelTX) 75 | if err != nil { 76 | return err 77 | } 78 | 79 | defer r.Close() 80 | 81 | if _, err := c.ResourceManagement.SaveChannel(resmgmt.SaveChannelRequest{ 82 | ChannelID: c.ChannelID, 83 | ChannelConfig: r, 84 | }); err != nil { 85 | return err 86 | } 87 | 88 | fmt.Fprintf(c.Settings.Streams.Out, "successfully updated channel '%s'\n", c.ChannelID) 89 | 90 | return nil 91 | } 92 | -------------------------------------------------------------------------------- /pkg/plugin/testdata/plugins/echogoplugin/cmd/echogoplugin.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright SecureKey Technologies Inc. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package main 8 | 9 | import ( 10 | "fmt" 11 | 12 | "github.com/hyperledger/fabric-cli/cmd/common" 13 | "github.com/hyperledger/fabric-cli/pkg/environment" 14 | "github.com/spf13/cobra" 15 | ) 16 | 17 | const ( 18 | usage = "echogoplugin --message " 19 | 20 | shortDesc = "Echos back the message provided by the --message flag" 21 | 22 | longDesc = ` 23 | The echogoplugin command demonstrates the addition of new commands to fabric-cli using Go plugins. Commands defined 24 | as Go plugins can contain custom flags, long descriptions and examples. 25 | 26 | The echogoplugin command is a simple command that echos back the message provided by the --message flag.` 27 | 28 | example = ` 29 | > fabric help echogoplugin 30 | 31 | ... prints out a long description of the echogoplugin command along with example usages 32 | 33 | > fabric echogoplugin --message "Hello World!" 34 | 35 | ... prints out: 36 | 37 | Hello World! 38 | ` 39 | ) 40 | 41 | // newCmd returns the command 42 | func newCmd(settings *environment.Settings) *cobra.Command { 43 | c := &echoCommand{} 44 | c.Settings = settings 45 | 46 | cmd := &cobra.Command{ 47 | Use: usage, 48 | Short: shortDesc, 49 | Long: longDesc, 50 | Example: example, 51 | PreRunE: func(cmd *cobra.Command, _ []string) error { 52 | return c.validate() 53 | }, 54 | Run: func(cmd *cobra.Command, args []string) { 55 | c.run() 56 | }, 57 | } 58 | cmd.Flags().StringVar(&c.message, "message", "", "sets the message to echo") 59 | return cmd 60 | } 61 | 62 | // New returns a new command 63 | func New(settings *environment.Settings) *cobra.Command { 64 | return newCmd(settings) 65 | } 66 | 67 | // echoCommand implements a Go plugin command 68 | type echoCommand struct { 69 | common.Command 70 | 71 | message string 72 | } 73 | 74 | func (c *echoCommand) validate() error { 75 | if c.message == "" { 76 | return fmt.Errorf("no message specified") 77 | } 78 | return nil 79 | } 80 | 81 | func (c *echoCommand) run() { 82 | _, err := fmt.Fprintln(c.Settings.Streams.Out, c.message) 83 | if err != nil { 84 | panic(err.Error()) 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /cmd/commands/channel/create.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package channel 8 | 9 | import ( 10 | "errors" 11 | "fmt" 12 | "os" 13 | 14 | "github.com/hyperledger/fabric-sdk-go/pkg/client/resmgmt" 15 | "github.com/spf13/cobra" 16 | 17 | "github.com/hyperledger/fabric-cli/pkg/environment" 18 | ) 19 | 20 | // NewChannelCreateCommand creates a new "fabric channel create" command 21 | func NewChannelCreateCommand(settings *environment.Settings) *cobra.Command { 22 | c := &CreateCommand{} 23 | 24 | c.Settings = settings 25 | 26 | cmd := &cobra.Command{ 27 | Use: "create ", 28 | Short: "Create a new channel", 29 | Long: "Create a new channel using the specified channel tx", 30 | Args: c.ParseArgs(), 31 | PreRunE: func(_ *cobra.Command, args []string) error { 32 | if err := c.Complete(); err != nil { 33 | return err 34 | } 35 | 36 | if err := c.Validate(); err != nil { 37 | return err 38 | } 39 | 40 | return nil 41 | }, 42 | RunE: func(_ *cobra.Command, _ []string) error { 43 | return c.Run() 44 | }, 45 | } 46 | 47 | c.AddArg(&c.ChannelID) 48 | c.AddArg(&c.ChannelTX) 49 | 50 | cmd.SetOutput(c.Settings.Streams.Out) 51 | 52 | return cmd 53 | } 54 | 55 | // CreateCommand implements the channel create command 56 | type CreateCommand struct { 57 | BaseCommand 58 | 59 | ChannelID string 60 | ChannelTX string 61 | } 62 | 63 | // Validate checks the required parameters for run 64 | func (c *CreateCommand) Validate() error { 65 | if len(c.ChannelID) == 0 { 66 | return errors.New("channel id not specified") 67 | } 68 | 69 | if len(c.ChannelTX) == 0 { 70 | return errors.New("channel tx path not specified") 71 | } 72 | 73 | return nil 74 | } 75 | 76 | // Run executes the command 77 | func (c *CreateCommand) Run() error { 78 | r, err := os.Open(c.ChannelTX) 79 | if err != nil { 80 | return err 81 | } 82 | 83 | defer r.Close() 84 | 85 | if _, err := c.ResourceManagement.SaveChannel(resmgmt.SaveChannelRequest{ 86 | ChannelID: c.ChannelID, 87 | ChannelConfig: r, 88 | }); err != nil { 89 | return err 90 | } 91 | 92 | fmt.Fprintf(c.Settings.Streams.Out, "successfully created channel '%s'\n", c.ChannelID) 93 | 94 | return nil 95 | } 96 | -------------------------------------------------------------------------------- /cmd/commands/channel/config.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package channel 8 | 9 | import ( 10 | "errors" 11 | "fmt" 12 | 13 | "github.com/spf13/cobra" 14 | 15 | "github.com/hyperledger/fabric-cli/pkg/environment" 16 | ) 17 | 18 | // NewChannelConfigCommand creates a new "fabric channel config" command 19 | func NewChannelConfigCommand(settings *environment.Settings) *cobra.Command { 20 | c := ConfigCommand{} 21 | 22 | c.Settings = settings 23 | 24 | cmd := &cobra.Command{ 25 | Use: "config ", 26 | Short: "Get the channel configuration", 27 | Long: "Get the channel-id channel configuration", 28 | Args: c.ParseArgs(), 29 | PreRunE: func(_ *cobra.Command, _ []string) error { 30 | if err := c.Complete(); err != nil { 31 | return err 32 | } 33 | 34 | if err := c.Validate(); err != nil { 35 | return err 36 | } 37 | 38 | return nil 39 | }, 40 | RunE: func(_ *cobra.Command, _ []string) error { 41 | return c.Run() 42 | }, 43 | } 44 | 45 | c.AddArg(&c.ChannelID) 46 | 47 | cmd.SetOutput(c.Settings.Streams.Out) 48 | 49 | return cmd 50 | } 51 | 52 | // ConfigCommand implements the channel config command 53 | type ConfigCommand struct { 54 | BaseCommand 55 | 56 | ChannelID string 57 | } 58 | 59 | // Validate checks the required parameters for run 60 | func (c *ConfigCommand) Validate() error { 61 | if len(c.ChannelID) == 0 { 62 | return errors.New("channel id not specified") 63 | } 64 | 65 | return nil 66 | } 67 | 68 | // Run executes the command 69 | func (c *ConfigCommand) Run() error { 70 | resp, err := c.ResourceManagement.QueryConfigFromOrderer(c.ChannelID) 71 | if err != nil { 72 | return err 73 | } 74 | 75 | fmt.Fprintf(c.Settings.Streams.Out, "ID: %s\n", resp.ID()) 76 | fmt.Fprintf(c.Settings.Streams.Out, "Latest Block Number: %d\n", resp.BlockNumber()) 77 | 78 | if len(resp.Orderers()) > 0 { 79 | fmt.Fprintln(c.Settings.Streams.Out, "Orderers:") 80 | for _, orderer := range resp.Orderers() { 81 | fmt.Fprintf(c.Settings.Streams.Out, " - %s\n", orderer) 82 | } 83 | } 84 | 85 | if len(resp.AnchorPeers()) > 0 { 86 | fmt.Fprintln(c.Settings.Streams.Out, "Anchor Peers:") 87 | for _, anchor := range resp.AnchorPeers() { 88 | fmt.Fprintf(c.Settings.Streams.Out, " - %s:%d (%s)\n", anchor.Host, anchor.Port, anchor.Org) 89 | } 90 | } 91 | 92 | return nil 93 | } 94 | -------------------------------------------------------------------------------- /cmd/commands/chaincode/query.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package chaincode 8 | 9 | import ( 10 | "errors" 11 | "fmt" 12 | 13 | "github.com/hyperledger/fabric-sdk-go/pkg/client/channel" 14 | "github.com/hyperledger/fabric-sdk-go/pkg/common/errors/retry" 15 | "github.com/spf13/cobra" 16 | 17 | "github.com/hyperledger/fabric-cli/cmd/commands/common" 18 | "github.com/hyperledger/fabric-cli/pkg/environment" 19 | ) 20 | 21 | // NewChaincodeQueryCommand creates a new "fabric chaincode query" command 22 | func NewChaincodeQueryCommand(settings *environment.Settings) *cobra.Command { 23 | c := QueryCommand{} 24 | 25 | c.Settings = settings 26 | 27 | cmd := &cobra.Command{ 28 | Use: "query ", 29 | Short: "Query a chaincode", 30 | Long: "Query a chaincode with args and function", 31 | Args: c.ParseArgs(), 32 | PreRunE: func(_ *cobra.Command, _ []string) error { 33 | if err := c.Complete(); err != nil { 34 | return err 35 | } 36 | 37 | if err := c.Validate(); err != nil { 38 | return err 39 | } 40 | 41 | return nil 42 | }, 43 | RunE: func(_ *cobra.Command, _ []string) error { 44 | return c.Run() 45 | }, 46 | } 47 | 48 | c.AddArg(&c.ChaincodeName) 49 | 50 | flags := cmd.Flags() 51 | flags.StringVar(&c.ChaincodeFcn, "fcn", "", "Set the invoke function") 52 | flags.StringArrayVar(&c.ChaincodeArgs, "args", []string{}, "Set the invoke arguments") 53 | 54 | cmd.SetOutput(c.Settings.Streams.Out) 55 | 56 | return cmd 57 | } 58 | 59 | // QueryCommand implements the chaincode query command 60 | type QueryCommand struct { 61 | BaseCommand 62 | 63 | ChaincodeName string 64 | 65 | ChaincodeFcn string 66 | ChaincodeArgs []string 67 | } 68 | 69 | // Validate checks the required parameters for run 70 | func (c *QueryCommand) Validate() error { 71 | if len(c.ChaincodeName) == 0 { 72 | return errors.New("chaincode name not specified") 73 | } 74 | 75 | return nil 76 | } 77 | 78 | // Run executes the command 79 | func (c *QueryCommand) Run() error { 80 | req := channel.Request{ 81 | ChaincodeID: c.ChaincodeName, 82 | Fcn: c.ChaincodeFcn, 83 | Args: common.AsByteArgs(c.ChaincodeArgs), 84 | } 85 | 86 | resp, err := c.Channel.Query(req, channel.WithRetry(retry.DefaultChannelOpts)) 87 | if err != nil { 88 | return err 89 | } 90 | 91 | fmt.Fprintln(c.Settings.Streams.Out, string(resp.Payload)) 92 | 93 | return nil 94 | } 95 | -------------------------------------------------------------------------------- /cmd/commands/chaincode/list.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package chaincode 8 | 9 | import ( 10 | "fmt" 11 | 12 | "github.com/hyperledger/fabric-sdk-go/pkg/client/resmgmt" 13 | "github.com/spf13/cobra" 14 | 15 | "github.com/hyperledger/fabric-cli/pkg/environment" 16 | ) 17 | 18 | // NewChaincodeListCommand creates a new "fabric chaincode list" command 19 | func NewChaincodeListCommand(settings *environment.Settings) *cobra.Command { 20 | c := ListCommand{} 21 | 22 | c.Settings = settings 23 | 24 | cmd := &cobra.Command{ 25 | Use: "list", 26 | Short: "List all chaincodes", 27 | Long: "List all chaincodes in current context's peers", 28 | PreRunE: func(_ *cobra.Command, _ []string) error { 29 | return c.Complete() 30 | }, 31 | RunE: func(_ *cobra.Command, _ []string) error { 32 | return c.Run() 33 | }, 34 | } 35 | 36 | flags := cmd.Flags() 37 | flags.BoolVar(&c.Installed, "installed", false, "Include chaincode installed on peer's filesystem") 38 | flags.BoolVar(&c.Instantiated, "instantiated", false, "Include instantiated chaincode") 39 | 40 | cmd.SetOutput(c.Settings.Streams.Out) 41 | 42 | return cmd 43 | } 44 | 45 | // ListCommand implements the chaincode list command 46 | type ListCommand struct { 47 | BaseCommand 48 | 49 | Installed bool 50 | Instantiated bool 51 | } 52 | 53 | // Run executes the command 54 | func (c *ListCommand) Run() error { 55 | if !c.Installed && !c.Instantiated { 56 | c.Installed = true 57 | c.Instantiated = true 58 | } 59 | 60 | context, err := c.Settings.Config.GetCurrentContext() 61 | if err != nil { 62 | return err 63 | } 64 | 65 | options := []resmgmt.RequestOption{ 66 | resmgmt.WithTargetEndpoints(context.Peers...), 67 | } 68 | 69 | if c.Installed { 70 | resp, err := c.ResourceManagement.QueryInstalledChaincodes(options...) 71 | if err != nil { 72 | return err 73 | } 74 | 75 | fmt.Fprintln(c.Settings.Streams.Out, "Installed Chaincode:") 76 | for _, chaincode := range resp.Chaincodes { 77 | fmt.Fprintf(c.Settings.Streams.Out, " - %s\n", chaincode.Name) 78 | } 79 | } 80 | 81 | if c.Instantiated { 82 | resp, err := c.ResourceManagement.QueryInstalledChaincodes(options...) 83 | if err != nil { 84 | return err 85 | } 86 | 87 | fmt.Fprintln(c.Settings.Streams.Out, "Instantiated Chaincode:") 88 | for _, chaincode := range resp.Chaincodes { 89 | fmt.Fprintf(c.Settings.Streams.Out, " - %s\n", chaincode.Name) 90 | } 91 | } 92 | 93 | return nil 94 | } 95 | -------------------------------------------------------------------------------- /cmd/commands/lifecycle/package.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright SecureKey Technologies Inc. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package lifecycle 8 | 9 | import ( 10 | "errors" 11 | "fmt" 12 | "io/ioutil" 13 | "strings" 14 | 15 | pb "github.com/hyperledger/fabric-protos-go/peer" 16 | lifecyclepkg "github.com/hyperledger/fabric-sdk-go/pkg/fab/ccpackager/lifecycle" 17 | "github.com/spf13/cobra" 18 | 19 | "github.com/hyperledger/fabric-cli/pkg/environment" 20 | ) 21 | 22 | // NewPackageCommand creates a new "fabric lifecycle chaincode package" command 23 | func NewPackageCommand(settings *environment.Settings) *cobra.Command { 24 | c := PackageCommand{} 25 | 26 | c.Settings = settings 27 | 28 | cmd := &cobra.Command{ 29 | Use: "package ", 30 | Short: "package a chaincode", 31 | Args: c.ParseArgs(), 32 | PreRunE: func(_ *cobra.Command, _ []string) error { 33 | return c.Validate() 34 | }, 35 | RunE: func(_ *cobra.Command, _ []string) error { 36 | return c.Run() 37 | }, 38 | } 39 | 40 | c.AddArg(&c.Label) 41 | c.AddArg(&c.Type) 42 | c.AddArg(&c.Path) 43 | 44 | cmd.SetOutput(c.Settings.Streams.Out) 45 | 46 | return cmd 47 | } 48 | 49 | // PackageCommand implements the chaincode package command 50 | type PackageCommand struct { 51 | BaseCommand 52 | 53 | Path string 54 | Label string 55 | Type string 56 | } 57 | 58 | // Validate checks the required parameters for run 59 | func (c *PackageCommand) Validate() error { 60 | if c.Label == "" { 61 | return errors.New("chaincode label not specified") 62 | } 63 | 64 | if c.Path == "" { 65 | return errors.New("chaincode path not specified") 66 | } 67 | 68 | if c.Type == "" { 69 | return errors.New("chaincode type not specified") 70 | } 71 | 72 | ccType, ok := pb.ChaincodeSpec_Type_value[strings.ToUpper(c.Type)] 73 | if !ok || ccType == int32(pb.ChaincodeSpec_UNDEFINED) { 74 | return errors.New("unsupported chaincode type") 75 | } 76 | 77 | return nil 78 | } 79 | 80 | // Run executes the command 81 | func (c *PackageCommand) Run() error { 82 | pkgBytes, err := lifecyclepkg.NewCCPackage(&lifecyclepkg.Descriptor{ 83 | Path: c.Path, 84 | Type: pb.ChaincodeSpec_Type(pb.ChaincodeSpec_Type_value[strings.ToUpper(c.Type)]), 85 | Label: c.Label, 86 | }) 87 | if err != nil { 88 | return err 89 | } 90 | 91 | if err := ioutil.WriteFile(fmt.Sprintf("./%s.tgz", c.Label), pkgBytes, 0644); err != nil { 92 | return err 93 | } 94 | 95 | fmt.Fprintf(c.Settings.Streams.Out, "successfully packaged chaincode '%s'\n", c.Label) 96 | 97 | return nil 98 | } 99 | -------------------------------------------------------------------------------- /cmd/commands/context/set.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package context 8 | 9 | import ( 10 | "errors" 11 | "fmt" 12 | 13 | "github.com/hyperledger/fabric-cli/cmd/common" 14 | "github.com/hyperledger/fabric-cli/pkg/environment" 15 | "github.com/spf13/cobra" 16 | ) 17 | 18 | // NewContextSetCommand creates a new "fabric context set" command 19 | func NewContextSetCommand(settings *environment.Settings) *cobra.Command { 20 | c := SetCommand{ 21 | Context: new(environment.Context), 22 | } 23 | 24 | c.Settings = settings 25 | 26 | cmd := &cobra.Command{ 27 | Use: "set [context-name]", 28 | Short: "Set a context", 29 | Long: "Set a context into config.yaml", 30 | Args: c.ParseArgs(), 31 | PreRunE: func(_ *cobra.Command, _ []string) error { 32 | return c.Validate() 33 | }, 34 | RunE: func(_ *cobra.Command, _ []string) error { 35 | return c.Run() 36 | }, 37 | } 38 | 39 | c.AddArg(&c.Name) 40 | 41 | flags := cmd.Flags() 42 | flags.StringVar(&c.Context.Network, "network", "", "Set the network context") 43 | flags.StringVar(&c.Context.Organization, "organization", "", "Set the organization context") 44 | flags.StringVar(&c.Context.Channel, "channel", "", "Set the channel context") 45 | flags.StringVar(&c.Context.User, "user", "", "Set the user context") 46 | flags.StringArrayVar(&c.Context.Peers, "peers", []string{}, "Set the peers context") 47 | 48 | cmd.SetOutput(c.Settings.Streams.Out) 49 | 50 | return cmd 51 | } 52 | 53 | // SetCommand implements the set context command 54 | type SetCommand struct { 55 | common.Command 56 | 57 | Name string 58 | Context *environment.Context 59 | } 60 | 61 | // Validate checks the required parameters for run 62 | func (c *SetCommand) Validate() error { 63 | if c.Context == nil || 64 | (len(c.Context.Network) == 0 && 65 | len(c.Context.Organization) == 0 && 66 | len(c.Context.User) == 0) { 67 | return errors.New("context details not specified") 68 | } 69 | 70 | return nil 71 | } 72 | 73 | // Run executes the command 74 | func (c *SetCommand) Run() error { 75 | if len(c.Name) == 0 { 76 | // ensure current context is set and exists 77 | if _, err := c.Settings.Config.GetCurrentContext(); err != nil { 78 | return err 79 | } 80 | 81 | c.Name = c.Settings.Config.CurrentContext 82 | } 83 | 84 | err := c.Settings.ModifyConfig(environment.SetContext(c.Name, c.Context)) 85 | if err != nil { 86 | return err 87 | } 88 | 89 | fmt.Fprintf(c.Settings.Streams.Out, "successfully set context '%s'\n", c.Name) 90 | fmt.Fprintln(c.Settings.Streams.Out, "") 91 | fmt.Fprintln(c.Settings.Streams.Out, c.Settings.Config.Contexts[c.Name]) 92 | 93 | return nil 94 | } 95 | -------------------------------------------------------------------------------- /pkg/fabric/fabric_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package fabric_test 8 | 9 | import ( 10 | "testing" 11 | 12 | "github.com/hyperledger/fabric-cli/pkg/environment" 13 | "github.com/hyperledger/fabric-cli/pkg/fabric" 14 | 15 | . "github.com/onsi/ginkgo" 16 | . "github.com/onsi/gomega" 17 | ) 18 | 19 | //go:generate gobin -m -run github.com/maxbrunsfeld/counterfeiter/v6 -o mocks/factory.go --fake-name Factory . Factory 20 | //go:generate gobin -m -run github.com/maxbrunsfeld/counterfeiter/v6 -o mocks/channel.go --fake-name Channel . Channel 21 | //go:generate gobin -m -run github.com/maxbrunsfeld/counterfeiter/v6 -o mocks/event.go --fake-name Event . Event 22 | //go:generate gobin -m -run github.com/maxbrunsfeld/counterfeiter/v6 -o mocks/ledger.go --fake-name Ledger . Ledger 23 | //go:generate gobin -m -run github.com/maxbrunsfeld/counterfeiter/v6 -o mocks/resmgmt.go --fake-name ResourceManagement . ResourceManagement 24 | //go:generate gobin -m -run github.com/maxbrunsfeld/counterfeiter/v6 -o mocks/msp.go --fake-name MSP . MSP 25 | //go:generate gobin -m -run github.com/maxbrunsfeld/counterfeiter/v6 -o mocks/channelcfg.go --fake-name ChannelCfg github.com/hyperledger/fabric-sdk-go/pkg/common/providers/fab.ChannelCfg 26 | 27 | func TestFabric(t *testing.T) { 28 | RegisterFailHandler(Fail) 29 | 30 | RunSpecs(t, "Fabric Suite") 31 | } 32 | 33 | var _ = Describe("Factory", func() { 34 | var ( 35 | factory fabric.Factory 36 | err error 37 | 38 | config *environment.Config 39 | ) 40 | 41 | BeforeEach(func() { 42 | config = environment.NewConfig() 43 | }) 44 | 45 | JustBeforeEach(func() { 46 | factory, err = fabric.NewFactory(config) 47 | }) 48 | 49 | It("should fail with empty config", func() { 50 | Expect(factory).To(BeNil()) 51 | Expect(err).NotTo(BeNil()) 52 | }) 53 | 54 | Context("when current context is set", func() { 55 | BeforeEach(func() { 56 | config = &environment.Config{ 57 | CurrentContext: "foo", 58 | Contexts: map[string]*environment.Context{ 59 | "foo": { 60 | Network: "bar", 61 | }, 62 | }, 63 | } 64 | }) 65 | 66 | It("should fail to get current network", func() { 67 | Expect(factory).To(BeNil()) 68 | Expect(err).NotTo(BeNil()) 69 | }) 70 | }) 71 | 72 | Context("when current context and network is set", func() { 73 | BeforeEach(func() { 74 | config = &environment.Config{ 75 | CurrentContext: "foo", 76 | Contexts: map[string]*environment.Context{ 77 | "foo": { 78 | Network: "bar", 79 | }, 80 | }, 81 | Networks: map[string]*environment.Network{ 82 | "bar": {}, 83 | }, 84 | } 85 | }) 86 | 87 | It("should create a factory", func() { 88 | Expect(factory).NotTo(BeNil()) 89 | Expect(err).To(BeNil()) 90 | }) 91 | }) 92 | 93 | }) 94 | -------------------------------------------------------------------------------- /cmd/commands/chaincode/invoke.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package chaincode 8 | 9 | import ( 10 | "errors" 11 | "fmt" 12 | 13 | "github.com/hyperledger/fabric-sdk-go/pkg/client/channel" 14 | "github.com/hyperledger/fabric-sdk-go/pkg/common/errors/retry" 15 | "github.com/spf13/cobra" 16 | 17 | "github.com/hyperledger/fabric-cli/cmd/commands/common" 18 | "github.com/hyperledger/fabric-cli/pkg/environment" 19 | ) 20 | 21 | // NewChaincodeInvokeCommand creates a new "fabric chaincode invoke" command 22 | func NewChaincodeInvokeCommand(settings *environment.Settings) *cobra.Command { 23 | c := InvokeCommand{} 24 | 25 | c.Settings = settings 26 | 27 | cmd := &cobra.Command{ 28 | Use: "invoke ", 29 | Short: "Invoke a chaincode", 30 | Long: "Invoke a chaincode with chaincode-name args function", 31 | Args: c.ParseArgs(), 32 | PreRunE: func(_ *cobra.Command, _ []string) error { 33 | if err := c.Complete(); err != nil { 34 | return err 35 | } 36 | 37 | if err := c.Validate(); err != nil { 38 | return err 39 | } 40 | 41 | return nil 42 | }, 43 | RunE: func(_ *cobra.Command, _ []string) error { 44 | return c.Run() 45 | }, 46 | } 47 | 48 | c.AddArg(&c.ChaincodeName) 49 | 50 | flags := cmd.Flags() 51 | flags.StringVar(&c.ChaincodeFcn, "fcn", "", "set the invoke function") 52 | flags.StringArrayVar(&c.ChaincodeArgs, "args", []string{}, "set the invoke arguments") 53 | flags.BoolVar(&c.IsInit, "is-init", false, "indicates whether or not this invocation is meant to initialize the chaincode") 54 | 55 | cmd.SetOutput(c.Settings.Streams.Out) 56 | 57 | return cmd 58 | } 59 | 60 | // InvokeCommand implements the chaincode invoke command 61 | type InvokeCommand struct { 62 | BaseCommand 63 | 64 | ChaincodeName string 65 | 66 | ChaincodeFcn string 67 | ChaincodeArgs []string 68 | IsInit bool 69 | } 70 | 71 | // Validate checks the required parameters for run 72 | func (c *InvokeCommand) Validate() error { 73 | if len(c.ChaincodeName) == 0 { 74 | return errors.New("chaincode name not specified") 75 | } 76 | 77 | return nil 78 | } 79 | 80 | // Run executes the command 81 | func (c *InvokeCommand) Run() error { 82 | fcn := c.ChaincodeFcn 83 | if c.IsInit { 84 | fcn = "Init" 85 | } 86 | 87 | req := channel.Request{ 88 | ChaincodeID: c.ChaincodeName, 89 | Fcn: fcn, 90 | Args: common.AsByteArgs(c.ChaincodeArgs), 91 | IsInit: c.IsInit, 92 | } 93 | 94 | resp, err := c.Channel.Execute(req, channel.WithRetry(retry.DefaultChannelOpts)) 95 | if err != nil { 96 | return err 97 | } 98 | 99 | fmt.Fprintln(c.Settings.Streams.Out, string(resp.Payload)) 100 | 101 | return nil 102 | } 103 | -------------------------------------------------------------------------------- /cmd/commands/context/list_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package context_test 8 | 9 | import ( 10 | "bytes" 11 | "fmt" 12 | "os" 13 | 14 | . "github.com/onsi/ginkgo" 15 | . "github.com/onsi/gomega" 16 | "github.com/spf13/cobra" 17 | 18 | "github.com/hyperledger/fabric-cli/cmd/commands/context" 19 | "github.com/hyperledger/fabric-cli/pkg/environment" 20 | ) 21 | 22 | var _ = Describe("ListContextCommand", func() { 23 | var ( 24 | cmd *cobra.Command 25 | settings *environment.Settings 26 | out *bytes.Buffer 27 | 28 | args []string 29 | ) 30 | 31 | BeforeEach(func() { 32 | out = new(bytes.Buffer) 33 | 34 | settings = &environment.Settings{ 35 | Home: environment.Home(os.TempDir()), 36 | Streams: environment.Streams{ 37 | Out: out, 38 | }, 39 | } 40 | 41 | args = os.Args 42 | }) 43 | 44 | JustBeforeEach(func() { 45 | cmd = context.NewContextListCommand(settings) 46 | }) 47 | 48 | AfterEach(func() { 49 | os.Args = args 50 | }) 51 | 52 | It("should create a list context command", func() { 53 | Expect(cmd.Name()).To(Equal("list")) 54 | Expect(cmd.HasSubCommands()).To(BeFalse()) 55 | }) 56 | 57 | It("should provide a help prompt", func() { 58 | os.Args = append(os.Args, "--help") 59 | 60 | Expect(cmd.Execute()).Should(Succeed()) 61 | Expect(fmt.Sprint(out)).To(ContainSubstring("list")) 62 | }) 63 | }) 64 | 65 | var _ = Describe("ListContextImplementation", func() { 66 | var ( 67 | impl *context.ListCommand 68 | err error 69 | out *bytes.Buffer 70 | settings *environment.Settings 71 | ) 72 | 73 | BeforeEach(func() { 74 | out = new(bytes.Buffer) 75 | 76 | settings = environment.NewDefaultSettings() 77 | settings.Home = environment.Home(os.TempDir()) 78 | settings.Streams = environment.Streams{Out: out} 79 | 80 | impl = &context.ListCommand{} 81 | impl.Settings = settings 82 | }) 83 | 84 | It("should not be nil", func() { 85 | Expect(impl).ShouldNot(BeNil()) 86 | }) 87 | 88 | Describe("Run", func() { 89 | JustBeforeEach(func() { 90 | err = impl.Run() 91 | }) 92 | 93 | It("should fail without a context", func() { 94 | Expect(err).NotTo(BeNil()) 95 | }) 96 | 97 | Context("when a context exists", func() { 98 | BeforeEach(func() { 99 | settings.Config = &environment.Config{ 100 | CurrentContext: "foo", 101 | Contexts: map[string]*environment.Context{ 102 | "foo": {}, 103 | "bar": {}, 104 | }, 105 | } 106 | }) 107 | 108 | It("should print list context", func() { 109 | Expect(err).To(BeNil()) 110 | Expect(fmt.Sprint(out)).To(ContainSubstring("foo (current)")) 111 | Expect(fmt.Sprint(out)).To(ContainSubstring("bar")) 112 | }) 113 | }) 114 | }) 115 | }) 116 | -------------------------------------------------------------------------------- /cmd/commands/channel/channel_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package channel_test 8 | 9 | import ( 10 | "bytes" 11 | "errors" 12 | "fmt" 13 | "os" 14 | "testing" 15 | 16 | . "github.com/onsi/ginkgo" 17 | . "github.com/onsi/gomega" 18 | "github.com/spf13/cobra" 19 | 20 | "github.com/hyperledger/fabric-cli/cmd/commands/channel" 21 | "github.com/hyperledger/fabric-cli/pkg/environment" 22 | "github.com/hyperledger/fabric-cli/pkg/fabric/mocks" 23 | ) 24 | 25 | func TestChannel(t *testing.T) { 26 | RegisterFailHandler(Fail) 27 | RunSpecs(t, "Channel Suite") 28 | } 29 | 30 | var _ = Describe("ChannelCommand", func() { 31 | var ( 32 | cmd *cobra.Command 33 | settings *environment.Settings 34 | out *bytes.Buffer 35 | ) 36 | 37 | Context("when creating a command from settings", func() { 38 | BeforeEach(func() { 39 | out = new(bytes.Buffer) 40 | 41 | settings = &environment.Settings{ 42 | Home: environment.Home(os.TempDir()), 43 | Streams: environment.Streams{ 44 | Out: out, 45 | }, 46 | } 47 | }) 48 | 49 | JustBeforeEach(func() { 50 | cmd = channel.NewChannelCommand(settings) 51 | }) 52 | 53 | It("should create a channel command", func() { 54 | Expect(cmd.Name()).To(Equal("channel")) 55 | Expect(cmd.HasSubCommands()).To(BeTrue()) 56 | Expect(cmd.Execute()).Should(Succeed()) 57 | Expect(fmt.Sprint(out)).To(ContainSubstring("channel [command]")) 58 | Expect(fmt.Sprint(out)).To(ContainSubstring("create")) 59 | Expect(fmt.Sprint(out)).To(ContainSubstring("join")) 60 | Expect(fmt.Sprint(out)).To(ContainSubstring("update")) 61 | Expect(fmt.Sprint(out)).To(ContainSubstring("list")) 62 | Expect(fmt.Sprint(out)).To(ContainSubstring("config")) 63 | }) 64 | }) 65 | }) 66 | var _ = Describe("BaseChannelCommand", func() { 67 | var c *channel.BaseCommand 68 | 69 | BeforeEach(func() { 70 | c = &channel.BaseCommand{} 71 | }) 72 | 73 | Describe("Complete", func() { 74 | var ( 75 | err error 76 | factory *mocks.Factory 77 | client *mocks.ResourceManagement 78 | ) 79 | 80 | BeforeEach(func() { 81 | factory = &mocks.Factory{} 82 | client = &mocks.ResourceManagement{} 83 | 84 | factory.ResourceManagementReturns(client, nil) 85 | 86 | c.Factory = factory 87 | }) 88 | 89 | JustBeforeEach(func() { 90 | err = c.Complete() 91 | }) 92 | 93 | It("should complete", func() { 94 | Expect(err).To(BeNil()) 95 | Expect(c.ResourceManagement).NotTo(BeNil()) 96 | }) 97 | 98 | Context("when resmgmt fails", func() { 99 | BeforeEach(func() { 100 | factory.ResourceManagementReturns(nil, errors.New("factory error")) 101 | }) 102 | 103 | It("should fail with factory error", func() { 104 | Expect(err).NotTo(BeNil()) 105 | }) 106 | }) 107 | }) 108 | }) 109 | -------------------------------------------------------------------------------- /cmd/commands/lifecycle/install.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright SecureKey Technologies Inc. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package lifecycle 8 | 9 | import ( 10 | "errors" 11 | "fmt" 12 | "io/ioutil" 13 | 14 | "github.com/hyperledger/fabric-sdk-go/pkg/client/resmgmt" 15 | "github.com/hyperledger/fabric-sdk-go/pkg/common/errors/retry" 16 | "github.com/hyperledger/fabric-sdk-go/pkg/fab/ccpackager/lifecycle" 17 | "github.com/spf13/cobra" 18 | 19 | "github.com/hyperledger/fabric-cli/pkg/environment" 20 | ) 21 | 22 | // NewInstallCommand creates a new "fabric lifecycle install" command 23 | func NewInstallCommand(settings *environment.Settings) *cobra.Command { 24 | c := InstallCommand{} 25 | 26 | c.Settings = settings 27 | 28 | cmd := &cobra.Command{ 29 | Use: "install ", 30 | Short: "install a chaincode", 31 | Args: c.ParseArgs(), 32 | PreRunE: func(_ *cobra.Command, _ []string) error { 33 | if err := c.Complete(); err != nil { 34 | return err 35 | } 36 | 37 | if err := c.Validate(); err != nil { 38 | return err 39 | } 40 | 41 | return nil 42 | }, 43 | RunE: func(_ *cobra.Command, _ []string) error { 44 | return c.Run() 45 | }, 46 | } 47 | 48 | c.AddArg(&c.Label) 49 | c.AddArg(&c.Path) 50 | 51 | cmd.SetOutput(c.Settings.Streams.Out) 52 | 53 | return cmd 54 | } 55 | 56 | // InstallCommand implements the chaincode install command 57 | type InstallCommand struct { 58 | BaseCommand 59 | 60 | Label string 61 | Path string 62 | } 63 | 64 | // Validate checks the required parameters for run 65 | func (c *InstallCommand) Validate() error { 66 | if c.Label == "" { 67 | return errors.New("chaincode label not specified") 68 | } 69 | 70 | if c.Path == "" { 71 | return errors.New("chaincode path not specified") 72 | } 73 | 74 | return nil 75 | } 76 | 77 | // Run executes the command 78 | func (c *InstallCommand) Run() error { 79 | context, err := c.Settings.Config.GetCurrentContext() 80 | if err != nil { 81 | return err 82 | } 83 | 84 | pkg, err := ioutil.ReadFile(c.Path) 85 | if err != nil { 86 | return err 87 | } 88 | 89 | responses, err := c.ResourceManagement.LifecycleInstallCC( 90 | resmgmt.LifecycleInstallCCRequest{ 91 | Label: c.Label, 92 | Package: pkg, 93 | }, 94 | resmgmt.WithRetry(retry.DefaultResMgmtOpts), 95 | resmgmt.WithTargetEndpoints(context.Peers...), 96 | ) 97 | if err != nil { 98 | return err 99 | } 100 | 101 | if len(responses) == 0 { 102 | packageID := lifecycle.ComputePackageID(c.Label, pkg) 103 | fmt.Fprintf(c.Settings.Streams.Out, "chaincode '%s' has already been installed on all peers. Package ID '%s'\n", c.Label, packageID) 104 | } else { 105 | fmt.Fprintf(c.Settings.Streams.Out, "successfully installed chaincode '%s'. Package ID '%s'\n", c.Label, responses[0].PackageID) 106 | } 107 | 108 | return nil 109 | } 110 | -------------------------------------------------------------------------------- /cmd/commands/lifecycle/lifecycle.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright SecureKey Technologies Inc. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package lifecycle 8 | 9 | import ( 10 | "encoding/json" 11 | "fmt" 12 | 13 | "github.com/spf13/cobra" 14 | 15 | "github.com/hyperledger/fabric-cli/cmd/common" 16 | "github.com/hyperledger/fabric-cli/pkg/environment" 17 | "github.com/hyperledger/fabric-cli/pkg/fabric" 18 | ) 19 | 20 | const ( 21 | jsonFormat = "json" 22 | 23 | outputFormatUsage = `The output format for query results. If set to 'json' then the response is output in JSON format, 24 | otherwise the response is output in human-readable text.` 25 | ) 26 | 27 | // NewCommand creates a new "fabric lifecycle" command 28 | func NewCommand(settings *environment.Settings) *cobra.Command { 29 | cmd := &cobra.Command{ 30 | Use: "lifecycle", 31 | Short: "Manage chaincode lifecycle", 32 | } 33 | 34 | cmd.AddCommand( 35 | NewPackageCommand(settings), 36 | NewInstallCommand(settings), 37 | NewApproveCommand(settings), 38 | NewCommitCommand(settings), 39 | NewQueryInstalledCommand(settings), 40 | NewGetInstalledPkgCommand(settings), 41 | NewQueryApprovedCommand(settings), 42 | NewCheckCommitReadinessCommand(settings), 43 | NewQueryCommittedCommand(settings), 44 | ) 45 | 46 | cmd.SetOutput(settings.Streams.Out) 47 | 48 | return cmd 49 | } 50 | 51 | // BaseCommand implements common channel command functions 52 | type BaseCommand struct { 53 | common.Command 54 | 55 | Factory fabric.Factory 56 | Channel fabric.Channel 57 | ResourceManagement fabric.ResourceManagement 58 | } 59 | 60 | // Complete initializes all clients needed for Run 61 | func (c *BaseCommand) Complete() error { 62 | var err error 63 | 64 | if c.Factory == nil { 65 | c.Factory, err = fabric.NewFactory(c.Settings.Config) 66 | if err != nil { 67 | return err 68 | } 69 | } 70 | 71 | c.Channel, err = c.Factory.Channel() 72 | if err != nil { 73 | return err 74 | } 75 | 76 | c.ResourceManagement, err = c.Factory.ResourceManagement() 77 | if err != nil { 78 | return err 79 | } 80 | 81 | return nil 82 | } 83 | 84 | func (c *BaseCommand) printf(format string, a ...interface{}) { 85 | _, err := fmt.Fprintf(c.Settings.Streams.Out, format, a...) 86 | if err != nil { 87 | panic(err) 88 | } 89 | } 90 | 91 | func (c *BaseCommand) println(a ...interface{}) { 92 | _, err := fmt.Fprintln(c.Settings.Streams.Out, a...) 93 | if err != nil { 94 | panic(err) 95 | } 96 | } 97 | 98 | func (c *BaseCommand) print(a ...interface{}) { 99 | _, err := fmt.Fprint(c.Settings.Streams.Out, a...) 100 | if err != nil { 101 | panic(err) 102 | } 103 | } 104 | 105 | func (c *BaseCommand) printJSONResponse(v interface{}) error { 106 | respBytes, err := json.Marshal(v) 107 | if err != nil { 108 | return err 109 | } 110 | 111 | c.print(string(respBytes)) 112 | 113 | return nil 114 | } 115 | -------------------------------------------------------------------------------- /cmd/commands/network/list_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package network_test 8 | 9 | import ( 10 | "bytes" 11 | "fmt" 12 | "os" 13 | 14 | . "github.com/onsi/ginkgo" 15 | . "github.com/onsi/gomega" 16 | "github.com/spf13/cobra" 17 | 18 | "github.com/hyperledger/fabric-cli/cmd/commands/network" 19 | "github.com/hyperledger/fabric-cli/pkg/environment" 20 | ) 21 | 22 | var _ = Describe("ListNetworkCommand", func() { 23 | var ( 24 | cmd *cobra.Command 25 | settings *environment.Settings 26 | out *bytes.Buffer 27 | 28 | args []string 29 | ) 30 | 31 | BeforeEach(func() { 32 | out = new(bytes.Buffer) 33 | 34 | settings = &environment.Settings{ 35 | Home: environment.Home(os.TempDir()), 36 | Streams: environment.Streams{ 37 | Out: out, 38 | }, 39 | } 40 | 41 | args = os.Args 42 | }) 43 | 44 | JustBeforeEach(func() { 45 | cmd = network.NewNetworkListCommand(settings) 46 | }) 47 | 48 | AfterEach(func() { 49 | os.Args = args 50 | }) 51 | 52 | It("should create a list network command", func() { 53 | Expect(cmd.Name()).To(Equal("list")) 54 | Expect(cmd.HasSubCommands()).To(BeFalse()) 55 | }) 56 | 57 | It("should provide a help prompt", func() { 58 | os.Args = append(os.Args, "--help") 59 | 60 | Expect(cmd.Execute()).Should(Succeed()) 61 | Expect(fmt.Sprint(out)).To(ContainSubstring("list")) 62 | }) 63 | }) 64 | 65 | var _ = Describe("ListNetworkImplementation", func() { 66 | var ( 67 | impl *network.ListCommand 68 | err error 69 | out *bytes.Buffer 70 | settings *environment.Settings 71 | ) 72 | 73 | BeforeEach(func() { 74 | out = new(bytes.Buffer) 75 | 76 | settings = environment.NewDefaultSettings() 77 | settings.Home = environment.Home(os.TempDir()) 78 | settings.Streams = environment.Streams{Out: out} 79 | 80 | impl = &network.ListCommand{} 81 | impl.Settings = settings 82 | }) 83 | 84 | It("should not be nil", func() { 85 | Expect(impl).ShouldNot(BeNil()) 86 | }) 87 | 88 | Describe("Run", func() { 89 | JustBeforeEach(func() { 90 | err = impl.Run() 91 | }) 92 | 93 | It("should fail without a network", func() { 94 | Expect(err).NotTo(BeNil()) 95 | }) 96 | 97 | Context("when a network exists", func() { 98 | BeforeEach(func() { 99 | settings.Config = &environment.Config{ 100 | CurrentContext: "foo", 101 | Contexts: map[string]*environment.Context{ 102 | "foo": { 103 | Network: "baz", 104 | }, 105 | }, 106 | Networks: map[string]*environment.Network{ 107 | "bar": {}, 108 | "baz": {}, 109 | }, 110 | } 111 | }) 112 | 113 | It("should print list network", func() { 114 | Expect(err).To(BeNil()) 115 | Expect(fmt.Sprint(out)).To(ContainSubstring("baz (current)")) 116 | Expect(fmt.Sprint(out)).To(ContainSubstring("bar")) 117 | }) 118 | }) 119 | }) 120 | }) 121 | -------------------------------------------------------------------------------- /cmd/commands/lifecycle/getinstalledpkg.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright SecureKey Technologies Inc. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package lifecycle 8 | 9 | import ( 10 | "io/ioutil" 11 | "os" 12 | "path/filepath" 13 | 14 | "github.com/hyperledger/fabric-sdk-go/pkg/client/resmgmt" 15 | "github.com/hyperledger/fabric-sdk-go/pkg/common/errors/retry" 16 | "github.com/pkg/errors" 17 | "github.com/spf13/cobra" 18 | 19 | "github.com/hyperledger/fabric-cli/pkg/environment" 20 | ) 21 | 22 | type fileWriter func(filename string, data []byte, perm os.FileMode) error 23 | 24 | // NewGetInstalledPkgCommand creates a new "fabric lifecycle getinstalledpkg" command 25 | func NewGetInstalledPkgCommand(settings *environment.Settings) *cobra.Command { 26 | c := GetInstalledPkgCommand{} 27 | 28 | c.Settings = settings 29 | c.WriteFile = ioutil.WriteFile 30 | 31 | cmd := &cobra.Command{ 32 | Use: "getinstalledpackage ", 33 | Short: "Get an installed chaincode package", 34 | Args: c.ParseArgs(), 35 | PreRunE: func(_ *cobra.Command, _ []string) error { 36 | if err := c.Complete(); err != nil { 37 | return err 38 | } 39 | 40 | return nil 41 | }, 42 | RunE: func(_ *cobra.Command, _ []string) error { 43 | return c.Run() 44 | }, 45 | } 46 | 47 | c.AddArg(&c.Peer) 48 | c.AddArg(&c.PackageID) 49 | 50 | flags := cmd.Flags() 51 | flags.StringVar(&c.OutputDirectory, "output-directory", "", 52 | "sets the output directory for the chaincode package file (default is current directory)") 53 | 54 | cmd.SetOutput(c.Settings.Streams.Out) 55 | 56 | return cmd 57 | } 58 | 59 | // GetInstalledPkgCommand implements the chaincode getinstalledpackage command 60 | type GetInstalledPkgCommand struct { 61 | BaseCommand 62 | 63 | Peer string 64 | PackageID string 65 | OutputDirectory string 66 | WriteFile fileWriter 67 | } 68 | 69 | // Validate checks the required parameters for run 70 | func (c *GetInstalledPkgCommand) Validate() error { 71 | if c.Peer == "" { 72 | return errors.New("peer not specified") 73 | } 74 | 75 | if c.PackageID == "" { 76 | return errors.New("package ID not specified") 77 | } 78 | 79 | return nil 80 | } 81 | 82 | // Run executes the command 83 | func (c *GetInstalledPkgCommand) Run() error { 84 | pkgBytes, err := c.ResourceManagement.LifecycleGetInstalledCCPackage( 85 | c.PackageID, 86 | resmgmt.WithRetry(retry.DefaultResMgmtOpts), 87 | resmgmt.WithTargetEndpoints(c.Peer), 88 | ) 89 | if err != nil { 90 | return err 91 | } 92 | 93 | filePath, err := filepath.Abs(filepath.Join(c.OutputDirectory, c.PackageID+".tar.gz")) 94 | if err != nil { 95 | return err 96 | } 97 | 98 | err = c.WriteFile(filePath, pkgBytes, os.ModePerm) 99 | if err != nil { 100 | return errors.WithMessagef(err, "failed to write chaincode package to file %s", filePath) 101 | } 102 | 103 | c.printf("Chaincode package saved to %s\n", filePath) 104 | 105 | return nil 106 | } 107 | -------------------------------------------------------------------------------- /cmd/commands/lifecycle/queryinstalled.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright SecureKey Technologies Inc. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package lifecycle 8 | 9 | import ( 10 | "github.com/hyperledger/fabric-sdk-go/pkg/client/resmgmt" 11 | "github.com/hyperledger/fabric-sdk-go/pkg/common/errors/retry" 12 | "github.com/pkg/errors" 13 | "github.com/spf13/cobra" 14 | 15 | "github.com/hyperledger/fabric-cli/pkg/environment" 16 | ) 17 | 18 | // NewQueryInstalledCommand creates a new "fabric lifecycle queryinstalled" command 19 | func NewQueryInstalledCommand(settings *environment.Settings) *cobra.Command { 20 | c := QueryInstalledCommand{} 21 | 22 | c.Settings = settings 23 | 24 | cmd := &cobra.Command{ 25 | Use: "queryinstalled ", 26 | Short: "Query a peer for installed chaincodes", 27 | Args: c.ParseArgs(), 28 | PreRunE: func(_ *cobra.Command, _ []string) error { 29 | if err := c.Complete(); err != nil { 30 | return err 31 | } 32 | 33 | return nil 34 | }, 35 | RunE: func(_ *cobra.Command, _ []string) error { 36 | return c.Run() 37 | }, 38 | } 39 | 40 | c.AddArg(&c.Peer) 41 | 42 | flags := cmd.Flags() 43 | flags.StringVar(&c.OutputFormat, "output", "", outputFormatUsage) 44 | 45 | cmd.SetOutput(c.Settings.Streams.Out) 46 | 47 | return cmd 48 | } 49 | 50 | // QueryInstalledCommand implements the chaincode queryinstalled command 51 | type QueryInstalledCommand struct { 52 | BaseCommand 53 | 54 | Peer string 55 | OutputFormat string 56 | } 57 | 58 | // Validate checks the required parameters for run 59 | func (c *QueryInstalledCommand) Validate() error { 60 | if c.Peer == "" { 61 | return errors.New("peer not specified") 62 | } 63 | 64 | return nil 65 | } 66 | 67 | // Run executes the command 68 | func (c *QueryInstalledCommand) Run() error { 69 | installedChaincodes, err := c.ResourceManagement.LifecycleQueryInstalledCC( 70 | resmgmt.WithRetry(retry.DefaultResMgmtOpts), 71 | resmgmt.WithTargetEndpoints(c.Peer), 72 | ) 73 | if err != nil { 74 | return err 75 | } 76 | 77 | if c.OutputFormat == jsonFormat { 78 | return c.printJSONResponse(installedChaincodes) 79 | } 80 | 81 | c.printResponse(installedChaincodes) 82 | 83 | return nil 84 | } 85 | 86 | func (c *QueryInstalledCommand) printResponse(installedChaincodes []resmgmt.LifecycleInstalledCC) { 87 | if len(installedChaincodes) == 0 { 88 | c.printf("No installed chaincodes on peer %s", c.Peer) 89 | 90 | return 91 | } 92 | 93 | c.println("Installed chaincodes:") 94 | 95 | for _, cc := range installedChaincodes { 96 | c.printf("- Package ID: %s, Label: %s\n", cc.PackageID, cc.Label) 97 | 98 | c.printReferences(cc.References) 99 | } 100 | } 101 | 102 | func (c *QueryInstalledCommand) printReferences(refs map[string][]resmgmt.CCReference) { 103 | for channelID, refs := range refs { 104 | c.printf("-- References for channel [%s]:\n", channelID) 105 | 106 | for _, ref := range refs { 107 | c.printf("--- Name: %s, Version: %s\n", ref.Name, ref.Version) 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /pkg/environment/actions_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package environment_test 8 | 9 | import ( 10 | "github.com/hyperledger/fabric-cli/pkg/environment" 11 | . "github.com/onsi/ginkgo" 12 | . "github.com/onsi/gomega" 13 | ) 14 | 15 | var _ = Describe("Actions", func() { 16 | var ( 17 | config *environment.Config 18 | action environment.Action 19 | ) 20 | 21 | BeforeEach(func() { 22 | config = environment.NewConfig() 23 | }) 24 | 25 | JustBeforeEach(func() { 26 | action(config) 27 | }) 28 | 29 | Describe("SetCurrentContext", func() { 30 | BeforeEach(func() { 31 | action = environment.SetCurrentContext("foo") 32 | }) 33 | 34 | It("should set current context", func() { 35 | Expect(config.CurrentContext).To(Equal("foo")) 36 | }) 37 | }) 38 | 39 | Describe("SetContext", func() { 40 | Context("when context does not exit", func() { 41 | BeforeEach(func() { 42 | action = environment.SetContext("foo", &environment.Context{ 43 | Network: "foo", 44 | Organization: "Org1", 45 | User: "Admin", 46 | Channel: "mychannel", 47 | Orderers: []string{"orderer.example.com"}, 48 | Peers: []string{"peer0.org1.example.com"}, 49 | }) 50 | }) 51 | 52 | It("should set context", func() { 53 | Expect(config.Contexts).To(HaveKey("foo")) 54 | }) 55 | }) 56 | 57 | Context("when context exists", func() { 58 | BeforeEach(func() { 59 | config.Contexts["foo"] = &environment.Context{} 60 | 61 | action = environment.SetContext("foo", &environment.Context{ 62 | Network: "foo", 63 | Organization: "Org1", 64 | User: "Admin", 65 | Channel: "mychannel", 66 | Orderers: []string{"orderer.example.com"}, 67 | Peers: []string{"peer0.org1.example.com"}, 68 | }) 69 | }) 70 | 71 | It("should set context", func() { 72 | Expect(config.Contexts).To(HaveKey("foo")) 73 | Expect(config.Contexts["foo"].Organization).To(Equal("Org1")) 74 | }) 75 | }) 76 | }) 77 | 78 | Describe("DeleteContext", func() { 79 | BeforeEach(func() { 80 | config = &environment.Config{ 81 | Contexts: map[string]*environment.Context{ 82 | "foo": {}, 83 | }, 84 | } 85 | action = environment.DeleteContext("foo") 86 | }) 87 | 88 | It("should set context", func() { 89 | Expect(config.Contexts).NotTo(HaveKey("foo")) 90 | }) 91 | }) 92 | 93 | Describe("SetNetwork", func() { 94 | BeforeEach(func() { 95 | action = environment.SetNetwork("foo", &environment.Network{}) 96 | }) 97 | 98 | It("should set network", func() { 99 | Expect(config.Networks).To(HaveKey("foo")) 100 | }) 101 | }) 102 | 103 | Describe("DeleteNetwork", func() { 104 | BeforeEach(func() { 105 | config = &environment.Config{ 106 | Networks: map[string]*environment.Network{ 107 | "foo": {}, 108 | }, 109 | } 110 | action = environment.DeleteNetwork("foo") 111 | }) 112 | 113 | It("should set context", func() { 114 | Expect(config.Networks).NotTo(HaveKey("foo")) 115 | }) 116 | }) 117 | }) 118 | -------------------------------------------------------------------------------- /cmd/commands/plugin/install_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package plugin_test 8 | 9 | import ( 10 | "bytes" 11 | "errors" 12 | "fmt" 13 | "os" 14 | 15 | . "github.com/onsi/ginkgo" 16 | . "github.com/onsi/gomega" 17 | "github.com/spf13/cobra" 18 | 19 | "github.com/hyperledger/fabric-cli/cmd/commands/plugin" 20 | "github.com/hyperledger/fabric-cli/pkg/environment" 21 | "github.com/hyperledger/fabric-cli/pkg/plugin/mocks" 22 | ) 23 | 24 | var _ = Describe("PluginInstallCommand", func() { 25 | var ( 26 | cmd *cobra.Command 27 | settings *environment.Settings 28 | out *bytes.Buffer 29 | 30 | args []string 31 | ) 32 | 33 | BeforeEach(func() { 34 | out = new(bytes.Buffer) 35 | 36 | settings = &environment.Settings{ 37 | Home: environment.Home(os.TempDir()), 38 | Streams: environment.Streams{ 39 | Out: out, 40 | }, 41 | } 42 | 43 | args = os.Args 44 | }) 45 | 46 | JustBeforeEach(func() { 47 | cmd = plugin.NewPluginInstallCommand(settings) 48 | }) 49 | 50 | AfterEach(func() { 51 | os.Args = args 52 | }) 53 | 54 | It("should create a plugin install command", func() { 55 | Expect(cmd.Name()).To(Equal("install")) 56 | Expect(cmd.HasSubCommands()).To(BeFalse()) 57 | }) 58 | 59 | It("should provide a help prompt", func() { 60 | os.Args = append(os.Args, "--help") 61 | 62 | Expect(cmd.Execute()).Should(Succeed()) 63 | Expect(fmt.Sprint(out)).To(ContainSubstring("install ")) 64 | }) 65 | }) 66 | 67 | var _ = Describe("PluginInstallImplementation", func() { 68 | var ( 69 | impl *plugin.InstallCommand 70 | out *bytes.Buffer 71 | handler *mocks.PluginHandler 72 | ) 73 | 74 | BeforeEach(func() { 75 | out = new(bytes.Buffer) 76 | handler = &mocks.PluginHandler{} 77 | }) 78 | 79 | JustBeforeEach(func() { 80 | impl = &plugin.InstallCommand{} 81 | impl.Settings = &environment.Settings{ 82 | Streams: environment.Streams{ 83 | Out: out, 84 | }, 85 | } 86 | impl.Handler = handler 87 | }) 88 | 89 | It("should not be nil", func() { 90 | Expect(impl).ShouldNot(BeNil()) 91 | }) 92 | 93 | Describe("Validate", func() { 94 | It("should fail without args", func() { 95 | err := impl.Validate() 96 | Expect(err).NotTo(BeNil()) 97 | Expect(err.Error()).To(ContainSubstring("plugin path not specified")) 98 | }) 99 | 100 | It("should succeed with input path", func() { 101 | impl.Path = "foo" 102 | Expect(impl.Validate()).Should(Succeed()) 103 | }) 104 | }) 105 | 106 | Describe("Run", func() { 107 | BeforeEach(func() { 108 | impl.Path = "foo" 109 | }) 110 | 111 | It("should fail if handler fails", func() { 112 | handler.InstallPluginReturns(errors.New("handler error")) 113 | 114 | err := impl.Run() 115 | 116 | Expect(err).NotTo(BeNil()) 117 | Expect(err.Error()).To(ContainSubstring("handler error")) 118 | }) 119 | 120 | It("should successfully install a plugin", func() { 121 | Expect(impl.Run()).Should(Succeed()) 122 | Expect(fmt.Sprint(out)).To(ContainSubstring("successfully installed the plugin\n")) 123 | }) 124 | }) 125 | }) 126 | -------------------------------------------------------------------------------- /cmd/commands/chaincode/install.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package chaincode 8 | 9 | import ( 10 | "errors" 11 | "fmt" 12 | "io/ioutil" 13 | 14 | "github.com/hyperledger/fabric-protos-go/peer" 15 | "github.com/hyperledger/fabric-sdk-go/pkg/client/resmgmt" 16 | "github.com/hyperledger/fabric-sdk-go/pkg/common/errors/retry" 17 | "github.com/hyperledger/fabric-sdk-go/pkg/fab/resource" 18 | "github.com/spf13/cobra" 19 | 20 | "github.com/hyperledger/fabric-cli/pkg/environment" 21 | ) 22 | 23 | // NewChaincodeInstallCommand creates a new "fabric chaincode install" command 24 | func NewChaincodeInstallCommand(settings *environment.Settings) *cobra.Command { 25 | c := InstallCommand{} 26 | 27 | c.Settings = settings 28 | 29 | cmd := &cobra.Command{ 30 | Use: "install ", 31 | Short: "Install a chaincode", 32 | Long: "Install a chaincode to current context's peers", 33 | Args: c.ParseArgs(), 34 | PreRunE: func(_ *cobra.Command, _ []string) error { 35 | if err := c.Complete(); err != nil { 36 | return err 37 | } 38 | 39 | if err := c.Validate(); err != nil { 40 | return err 41 | } 42 | 43 | return nil 44 | }, 45 | RunE: func(_ *cobra.Command, _ []string) error { 46 | return c.Run() 47 | }, 48 | } 49 | 50 | c.AddArg(&c.ChaincodeName) 51 | c.AddArg(&c.ChaincodeVersion) 52 | c.AddArg(&c.ChaincodePath) 53 | 54 | cmd.SetOutput(c.Settings.Streams.Out) 55 | 56 | return cmd 57 | } 58 | 59 | // InstallCommand implements the chaincode install command 60 | type InstallCommand struct { 61 | BaseCommand 62 | 63 | ChaincodeName string 64 | ChaincodeVersion string 65 | ChaincodePath string 66 | } 67 | 68 | // Validate checks the required parameters for run 69 | func (c *InstallCommand) Validate() error { 70 | if len(c.ChaincodeName) == 0 { 71 | return errors.New("chaincode name not specified") 72 | } 73 | 74 | if len(c.ChaincodeVersion) == 0 { 75 | return errors.New("chaincode version not specified") 76 | } 77 | 78 | if len(c.ChaincodePath) == 0 { 79 | return errors.New("chaincode path not specified") 80 | } 81 | 82 | return nil 83 | } 84 | 85 | // Run executes the command 86 | func (c *InstallCommand) Run() error { 87 | context, err := c.Settings.Config.GetCurrentContext() 88 | if err != nil { 89 | return err 90 | } 91 | 92 | pkg, err := ioutil.ReadFile(c.ChaincodePath) 93 | if err != nil { 94 | return err 95 | } 96 | 97 | req := resmgmt.InstallCCRequest{ 98 | Name: c.ChaincodeName, 99 | Path: c.ChaincodePath, 100 | Version: c.ChaincodeVersion, 101 | Package: &resource.CCPackage{ 102 | Type: peer.ChaincodeSpec_GOLANG, 103 | Code: pkg, 104 | }, 105 | } 106 | 107 | options := []resmgmt.RequestOption{ 108 | resmgmt.WithTargetEndpoints(context.Peers...), 109 | resmgmt.WithRetry(retry.DefaultResMgmtOpts), 110 | } 111 | 112 | if _, err := c.ResourceManagement.InstallCC(req, options...); err != nil { 113 | return err 114 | } 115 | 116 | fmt.Fprintf(c.Settings.Streams.Out, "successfully installed chaincode '%s'\n", c.ChaincodeName) 117 | 118 | return nil 119 | } 120 | -------------------------------------------------------------------------------- /pkg/environment/environment.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package environment 8 | 9 | import ( 10 | "os" 11 | 12 | "github.com/spf13/pflag" 13 | ) 14 | 15 | // Settings contains environment configuration details 16 | type Settings struct { 17 | Home Home 18 | Streams Streams 19 | DisablePlugins bool 20 | Config *Config 21 | 22 | configFilename string 23 | } 24 | 25 | // AddFlags appeneds settings flags onto an existing flag set 26 | func (s *Settings) AddFlags(fs *pflag.FlagSet) { 27 | fs.StringVar((*string)(&s.Home), "home", DefaultHome.String(), "Set path to configuration files") 28 | fs.BoolVar(&s.DisablePlugins, "disable-plugins", false, "Disable plugins") 29 | } 30 | 31 | // Init populates the settings based on a precedence: 32 | // Flag > Env > Config File > Defaults 33 | func (s *Settings) Init(fs *pflag.FlagSet) error { 34 | // if the flag was not set, check the corresponding environment variable 35 | // must resolve home value before loading config from file 36 | for flag, env := range map[string]string{ 37 | "home": "FABRIC_HOME", 38 | "disable-plugins": "FABRIC_DISABLE_PLUGINS", 39 | } { 40 | if fs.Changed(flag) { 41 | continue 42 | } 43 | 44 | if v, ok := os.LookupEnv(env); ok { 45 | fs.Set(flag, v) 46 | } 47 | } 48 | 49 | if err := s.Home.Init(); err != nil { 50 | return err 51 | } 52 | 53 | // if the config file does not exist, continue since it could be a new user or home 54 | if err := s.Config.LoadFromFile(s.Home.Path(s.configFilename)); err != nil && 55 | !os.IsNotExist(err) { 56 | return err 57 | } 58 | 59 | return nil 60 | } 61 | 62 | // ModifyConfig loads the config file and updates it based on actions 63 | func (s *Settings) ModifyConfig(actions ...Action) error { 64 | if len(actions) == 0 { 65 | return nil 66 | } 67 | 68 | // build a new config to prevent saving overrides 69 | fromFile := NewConfig() 70 | 71 | if err := s.Home.Init(); err != nil { 72 | return err 73 | } 74 | 75 | // if config file does not exist, create a new one 76 | if err := fromFile.LoadFromFile(s.Home.Path(s.configFilename)); err != nil && 77 | !os.IsNotExist(err) { 78 | return err 79 | } 80 | 81 | for _, action := range actions { 82 | action(fromFile) 83 | 84 | // update settings in case it continues to be used after modification 85 | action(s.Config) 86 | } 87 | 88 | return fromFile.Save(s.Home.Path(s.configFilename)) 89 | } 90 | 91 | // SetupPluginEnvironment sets the environment variables that are important to plugins 92 | // This is needed because environment variables are not populated with defaults 93 | func (s *Settings) SetupPluginEnvironment() { 94 | for k, v := range map[string]string{ 95 | "FABRIC_HOME": s.Home.String(), 96 | } { 97 | os.Setenv(k, v) // nolint: errcheck 98 | } 99 | } 100 | 101 | // NewDefaultSettings returns settings populated with default values 102 | func NewDefaultSettings() *Settings { 103 | return &Settings{ 104 | Home: DefaultHome, 105 | Streams: DefaultStreams, 106 | Config: NewConfig(), 107 | 108 | configFilename: DefaultConfigFilename, 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /cmd/commands/common/common.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "io/ioutil" 7 | 8 | "github.com/hyperledger/fabric-protos-go/common" 9 | pb "github.com/hyperledger/fabric-protos-go/peer" 10 | 11 | "github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric/common/policydsl" 12 | ) 13 | 14 | // CollectionConfigJSON contains the parameters for a collection configuration 15 | type CollectionConfigJSON struct { 16 | Name string `json:"name"` 17 | Policy string `json:"policy"` 18 | RequiredCount int32 `json:"requiredPeerCount"` 19 | MaxPeerCount int32 `json:"maxPeerCount"` 20 | BlockToLive uint64 `json:"blockToLive"` 21 | MemberOnlyRead bool `json:"memberOnlyRead"` 22 | MemberOnlyWrite bool `json:"memberOnlyWrite"` 23 | } 24 | 25 | // GetCollectionConfigFromFile returns the collection config from the given file 26 | func GetCollectionConfigFromFile(path string) ([]*pb.CollectionConfig, error) { 27 | if len(path) == 0 { 28 | return nil, nil 29 | } 30 | 31 | bytes, err := ioutil.ReadFile(path) 32 | if err != nil { 33 | return nil, errors.New("error reading collections config file") 34 | } 35 | 36 | return GetCollectionsConfigFromBytes(bytes) 37 | } 38 | 39 | // GetCollectionsConfigFromBytes returns the collection config from the given byte array 40 | func GetCollectionsConfigFromBytes(bytes []byte) ([]*pb.CollectionConfig, error) { 41 | var cconf []CollectionConfigJSON 42 | if err := json.Unmarshal(bytes, &cconf); err != nil { 43 | return nil, errors.New("error unmarshalling collections config") 44 | } 45 | 46 | ccarray := make([]*pb.CollectionConfig, 0, len(cconf)) 47 | for _, cconfitem := range cconf { 48 | p, err := policydsl.FromString(cconfitem.Policy) 49 | if err != nil { 50 | return nil, err 51 | } 52 | cpc := &pb.CollectionPolicyConfig{ 53 | Payload: &pb.CollectionPolicyConfig_SignaturePolicy{ 54 | SignaturePolicy: p, 55 | }, 56 | } 57 | cc := &pb.CollectionConfig{ 58 | Payload: &pb.CollectionConfig_StaticCollectionConfig{ 59 | StaticCollectionConfig: &pb.StaticCollectionConfig{ 60 | Name: cconfitem.Name, 61 | MemberOrgsPolicy: cpc, 62 | RequiredPeerCount: cconfitem.RequiredCount, 63 | MaximumPeerCount: cconfitem.MaxPeerCount, 64 | MemberOnlyRead: cconfitem.MemberOnlyRead, 65 | MemberOnlyWrite: cconfitem.MemberOnlyWrite, 66 | BlockToLive: cconfitem.BlockToLive, 67 | }, 68 | }, 69 | } 70 | ccarray = append(ccarray, cc) 71 | } 72 | return ccarray, nil 73 | } 74 | 75 | // GetChaincodePolicy returns the signature policy from the given policy string 76 | func GetChaincodePolicy(policyString string) (*common.SignaturePolicyEnvelope, error) { 77 | if len(policyString) == 0 { 78 | return policydsl.AcceptAllPolicy, nil 79 | } 80 | 81 | policy, err := policydsl.FromString(policyString) 82 | if err != nil { 83 | return nil, errors.New("error parsing chaincode policy") 84 | } 85 | return policy, nil 86 | } 87 | 88 | // AsByteArgs converts the given string array into an array of byte arrays so that they 89 | // may be passed as chaincode arguments. 90 | func AsByteArgs(strArgs []string) [][]byte { 91 | args := make([][]byte, len(strArgs)) 92 | for i, arg := range strArgs { 93 | args[i] = []byte(arg) 94 | } 95 | 96 | return args 97 | } 98 | -------------------------------------------------------------------------------- /cmd/commands/plugin/list_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package plugin_test 8 | 9 | import ( 10 | "bytes" 11 | "errors" 12 | "fmt" 13 | "os" 14 | 15 | . "github.com/onsi/ginkgo" 16 | . "github.com/onsi/gomega" 17 | "github.com/spf13/cobra" 18 | 19 | "github.com/hyperledger/fabric-cli/cmd/commands/plugin" 20 | "github.com/hyperledger/fabric-cli/pkg/environment" 21 | plug "github.com/hyperledger/fabric-cli/pkg/plugin" 22 | "github.com/hyperledger/fabric-cli/pkg/plugin/mocks" 23 | ) 24 | 25 | var _ = Describe("PluginListCommand", func() { 26 | var ( 27 | cmd *cobra.Command 28 | settings *environment.Settings 29 | out *bytes.Buffer 30 | 31 | args []string 32 | ) 33 | 34 | BeforeEach(func() { 35 | out = new(bytes.Buffer) 36 | 37 | settings = &environment.Settings{ 38 | Home: environment.Home(os.TempDir()), 39 | Streams: environment.Streams{ 40 | Out: out, 41 | }, 42 | } 43 | 44 | args = os.Args 45 | }) 46 | 47 | JustBeforeEach(func() { 48 | cmd = plugin.NewPluginListCommand(settings) 49 | }) 50 | 51 | AfterEach(func() { 52 | os.Args = args 53 | }) 54 | 55 | It("should create a plugin list command", func() { 56 | Expect(cmd.Name()).To(Equal("list")) 57 | Expect(cmd.HasSubCommands()).To(BeFalse()) 58 | }) 59 | 60 | It("should provide a help prompt", func() { 61 | os.Args = append(os.Args, "--help") 62 | 63 | Expect(cmd.Execute()).Should(Succeed()) 64 | Expect(fmt.Sprint(out)).To(ContainSubstring("list")) 65 | }) 66 | }) 67 | 68 | var _ = Describe("PluginListImplementation", func() { 69 | var ( 70 | impl *plugin.ListCommand 71 | out *bytes.Buffer 72 | handler *mocks.PluginHandler 73 | ) 74 | 75 | BeforeEach(func() { 76 | out = new(bytes.Buffer) 77 | handler = &mocks.PluginHandler{} 78 | }) 79 | 80 | JustBeforeEach(func() { 81 | impl = &plugin.ListCommand{} 82 | impl.Settings = &environment.Settings{ 83 | Streams: environment.Streams{ 84 | Out: out, 85 | }, 86 | } 87 | impl.Handler = handler 88 | }) 89 | 90 | It("should not be nil", func() { 91 | Expect(impl).ShouldNot(BeNil()) 92 | }) 93 | 94 | Describe("Run", func() { 95 | It("should fail if handler fails", func() { 96 | handler.GetPluginsReturns(nil, errors.New("handler error")) 97 | 98 | err := impl.Run() 99 | 100 | Expect(err).NotTo(BeNil()) 101 | Expect(err.Error()).To(ContainSubstring("handler error")) 102 | }) 103 | 104 | It("should succeed when plugins have not been installed", func() { 105 | Expect(impl.Run()).Should(Succeed()) 106 | Expect(fmt.Sprint(out)).To(ContainSubstring("no plugins currently exist")) 107 | }) 108 | 109 | Context("when plugins have been installed", func() { 110 | BeforeEach(func() { 111 | handler.GetPluginsReturns([]*plug.Plugin{ 112 | { 113 | Name: "foo", 114 | }, 115 | }, nil) 116 | }) 117 | 118 | JustBeforeEach(func() { 119 | err := handler.InstallPlugin("foo") 120 | 121 | Expect(err).NotTo(HaveOccurred()) 122 | }) 123 | 124 | It("should successfully list a plugin", func() { 125 | Expect(impl.Run()).Should(Succeed()) 126 | Expect(fmt.Sprint(out)).To(ContainSubstring("foo\n")) 127 | }) 128 | }) 129 | }) 130 | }) 131 | -------------------------------------------------------------------------------- /cmd/commands/plugin/uninstall_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package plugin_test 8 | 9 | import ( 10 | "bytes" 11 | "errors" 12 | "fmt" 13 | "os" 14 | 15 | . "github.com/onsi/ginkgo" 16 | . "github.com/onsi/gomega" 17 | "github.com/spf13/cobra" 18 | 19 | "github.com/hyperledger/fabric-cli/cmd/commands/plugin" 20 | "github.com/hyperledger/fabric-cli/pkg/environment" 21 | "github.com/hyperledger/fabric-cli/pkg/plugin/mocks" 22 | ) 23 | 24 | var _ = Describe("PluginUninstallCommand", func() { 25 | var ( 26 | cmd *cobra.Command 27 | settings *environment.Settings 28 | out *bytes.Buffer 29 | 30 | args []string 31 | ) 32 | 33 | BeforeEach(func() { 34 | out = new(bytes.Buffer) 35 | 36 | settings = &environment.Settings{ 37 | Home: environment.Home(os.TempDir()), 38 | Streams: environment.Streams{ 39 | Out: out, 40 | }, 41 | } 42 | 43 | args = os.Args 44 | }) 45 | 46 | JustBeforeEach(func() { 47 | cmd = plugin.NewPluginUninstallCommand(settings) 48 | }) 49 | 50 | AfterEach(func() { 51 | os.Args = args 52 | }) 53 | 54 | It("should create a plugin uninstall command", func() { 55 | Expect(cmd.Name()).To(Equal("uninstall")) 56 | Expect(cmd.HasSubCommands()).To(BeFalse()) 57 | }) 58 | 59 | It("should provide a help prompt", func() { 60 | os.Args = append(os.Args, "--help") 61 | 62 | Expect(cmd.Execute()).Should(Succeed()) 63 | Expect(fmt.Sprint(out)).To(ContainSubstring("uninstall ")) 64 | }) 65 | }) 66 | 67 | var _ = Describe("PluginUninstallImplementation", func() { 68 | var ( 69 | impl *plugin.UninstallCommand 70 | out *bytes.Buffer 71 | handler *mocks.PluginHandler 72 | ) 73 | 74 | BeforeEach(func() { 75 | out = new(bytes.Buffer) 76 | handler = &mocks.PluginHandler{} 77 | }) 78 | 79 | JustBeforeEach(func() { 80 | impl = &plugin.UninstallCommand{} 81 | impl.Settings = &environment.Settings{ 82 | Streams: environment.Streams{ 83 | Out: out, 84 | }, 85 | } 86 | impl.Handler = handler 87 | }) 88 | 89 | It("should not be nil", func() { 90 | Expect(impl).ShouldNot(BeNil()) 91 | }) 92 | 93 | Describe("Validate", func() { 94 | It("should fail without args", func() { 95 | err := impl.Validate() 96 | Expect(err).NotTo(BeNil()) 97 | Expect(err.Error()).To(ContainSubstring("plugin name not specified")) 98 | }) 99 | 100 | It("should succeed with input path", func() { 101 | impl.Name = "foo" 102 | Expect(impl.Validate()).Should(Succeed()) 103 | }) 104 | }) 105 | 106 | Describe("Run", func() { 107 | BeforeEach(func() { 108 | impl.Name = "foo" 109 | }) 110 | 111 | It("should fail if handler fails", func() { 112 | handler.UninstallPluginReturns(errors.New("handler error")) 113 | 114 | err := impl.Run() 115 | 116 | Expect(err).NotTo(BeNil()) 117 | Expect(err.Error()).To(ContainSubstring("handler error")) 118 | }) 119 | 120 | Context("when plugins have been installed", func() { 121 | JustBeforeEach(func() { 122 | err := handler.InstallPlugin("foo") 123 | 124 | Expect(err).NotTo(HaveOccurred()) 125 | }) 126 | 127 | It("should successfully uninstall a plugin", func() { 128 | Expect(impl.Run()).Should(Succeed()) 129 | Expect(fmt.Sprint(out)).To(ContainSubstring("successfully uninstalled the plugin\n")) 130 | }) 131 | }) 132 | }) 133 | }) 134 | -------------------------------------------------------------------------------- /cmd/fabric.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package main 8 | 9 | import ( 10 | "fmt" 11 | "os" 12 | "os/exec" 13 | 14 | "github.com/spf13/cobra" 15 | 16 | "github.com/hyperledger/fabric-cli/cmd/commands" 17 | "github.com/hyperledger/fabric-cli/pkg/environment" 18 | "github.com/hyperledger/fabric-cli/pkg/plugin" 19 | ) 20 | 21 | // NewFabricCommand returns a new root command for fabric 22 | func NewFabricCommand(settings *environment.Settings) *cobra.Command { 23 | cmd := &cobra.Command{ 24 | Use: "fabric", 25 | Short: "The command line interface for Hyperledger Fabric", 26 | } 27 | 28 | // load all built in commands into the root command 29 | cmd.AddCommand(commands.All(settings)...) 30 | 31 | cmd.SetOutput(settings.Streams.Out) 32 | 33 | return cmd 34 | } 35 | 36 | // NewDefaultFabricCommand returns a new default root commad for fabric 37 | func NewDefaultFabricCommand(settings *environment.Settings, args []string) *cobra.Command { 38 | cmd := NewFabricCommand(settings) 39 | flags := cmd.PersistentFlags() 40 | 41 | settings.AddFlags(flags) 42 | flags.Parse(args) 43 | 44 | if err := settings.Init(flags); err != nil { 45 | fmt.Fprintf(settings.Streams.Err, "An error occurred while loading configurations: %v\n", err) 46 | os.Exit(1) 47 | } 48 | 49 | // must resolve home and config file before loading config flags 50 | settings.Config.AddFlags(flags) 51 | 52 | if err := loadPlugins(cmd, settings, &plugin.DefaultHandler{ 53 | Dir: settings.Home.Plugins(), 54 | Filename: plugin.DefaultFilename, 55 | }); err != nil { 56 | fmt.Fprintf(settings.Streams.Err, "An error occurred while loading plugins: %v\n", err) 57 | os.Exit(1) 58 | } 59 | 60 | return cmd 61 | } 62 | 63 | func main() { 64 | settings := environment.NewDefaultSettings() 65 | cmd := NewDefaultFabricCommand(settings, os.Args[1:]) 66 | 67 | if err := cmd.Execute(); err != nil { 68 | os.Exit(1) 69 | } 70 | 71 | os.Exit(0) 72 | } 73 | 74 | // loadPlugins processes all of the installed plugins, wraps them with cobra, 75 | // and adds them to the root command 76 | func loadPlugins(cmd *cobra.Command, settings *environment.Settings, handler plugin.Handler) error { 77 | if settings.DisablePlugins { 78 | return nil 79 | } 80 | 81 | plugins, err := handler.GetPlugins() 82 | if err != nil { 83 | return err 84 | } 85 | 86 | settings.SetupPluginEnvironment() 87 | 88 | for _, p := range plugins { 89 | c, err := loadPlugin(p, settings, handler) 90 | if err != nil { 91 | return err 92 | } 93 | cmd.AddCommand(c) 94 | } 95 | 96 | return nil 97 | } 98 | 99 | // loadPlugin loads the given plugin as either a Go plugin or a wrapped executable 100 | func loadPlugin(p *plugin.Plugin, settings *environment.Settings, handler plugin.Handler) (*cobra.Command, error) { 101 | path := os.ExpandEnv(p.Command.Base) 102 | c, err := handler.LoadGoPlugin(path, settings) 103 | if err == nil { 104 | return c, nil 105 | } 106 | if err != plugin.ErrNotAGoPlugin { 107 | return nil, err 108 | } 109 | 110 | return &cobra.Command{ 111 | Use: p.Name, 112 | Short: p.Description, 113 | RunE: func(cmd *cobra.Command, args []string) error { 114 | e := exec.Command(path, append(p.Command.Args, args...)...) 115 | e.Env = os.Environ() 116 | e.Stdin = settings.Streams.In 117 | e.Stdout = settings.Streams.Out 118 | e.Stderr = settings.Streams.Err 119 | return e.Run() 120 | }, 121 | }, nil 122 | } 123 | -------------------------------------------------------------------------------- /cmd/commands/chaincode/chaincode_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package chaincode_test 8 | 9 | import ( 10 | "bytes" 11 | "errors" 12 | "fmt" 13 | "os" 14 | "testing" 15 | 16 | . "github.com/onsi/ginkgo" 17 | . "github.com/onsi/gomega" 18 | "github.com/spf13/cobra" 19 | 20 | "github.com/hyperledger/fabric-cli/cmd/commands/chaincode" 21 | "github.com/hyperledger/fabric-cli/pkg/environment" 22 | "github.com/hyperledger/fabric-cli/pkg/fabric/mocks" 23 | ) 24 | 25 | func TestChaincode(t *testing.T) { 26 | RegisterFailHandler(Fail) 27 | RunSpecs(t, "Chaincode Suite") 28 | } 29 | 30 | var _ = Describe("ChaincodeCommand", func() { 31 | var ( 32 | cmd *cobra.Command 33 | settings *environment.Settings 34 | out *bytes.Buffer 35 | ) 36 | 37 | Context("when creating a command from settings", func() { 38 | BeforeEach(func() { 39 | out = new(bytes.Buffer) 40 | 41 | settings = &environment.Settings{ 42 | Home: environment.Home(os.TempDir()), 43 | Streams: environment.Streams{ 44 | Out: out, 45 | }, 46 | } 47 | }) 48 | 49 | JustBeforeEach(func() { 50 | cmd = chaincode.NewChaincodeCommand(settings) 51 | }) 52 | 53 | It("should create a chaincode command", func() { 54 | Expect(cmd.Name()).To(Equal("chaincode")) 55 | Expect(cmd.HasSubCommands()).To(BeTrue()) 56 | Expect(cmd.Execute()).Should(Succeed()) 57 | Expect(fmt.Sprint(out)).To(ContainSubstring("chaincode [command]")) 58 | Expect(fmt.Sprint(out)).To(ContainSubstring("list")) 59 | Expect(fmt.Sprint(out)).To(ContainSubstring("install")) 60 | Expect(fmt.Sprint(out)).To(ContainSubstring("instantiate")) 61 | Expect(fmt.Sprint(out)).To(ContainSubstring("upgrade")) 62 | Expect(fmt.Sprint(out)).To(ContainSubstring("query")) 63 | Expect(fmt.Sprint(out)).To(ContainSubstring("invoke")) 64 | Expect(fmt.Sprint(out)).To(ContainSubstring("events")) 65 | }) 66 | }) 67 | }) 68 | 69 | var _ = Describe("BaseChaincodeCommand", func() { 70 | var c *chaincode.BaseCommand 71 | 72 | BeforeEach(func() { 73 | c = &chaincode.BaseCommand{} 74 | }) 75 | 76 | Describe("Complete", func() { 77 | var ( 78 | err error 79 | factory *mocks.Factory 80 | channelClient *mocks.Channel 81 | resmgmtClient *mocks.ResourceManagement 82 | ) 83 | 84 | BeforeEach(func() { 85 | factory = &mocks.Factory{} 86 | channelClient = &mocks.Channel{} 87 | resmgmtClient = &mocks.ResourceManagement{} 88 | 89 | factory.ResourceManagementReturns(resmgmtClient, nil) 90 | factory.ChannelReturns(channelClient, nil) 91 | 92 | c.Factory = factory 93 | }) 94 | 95 | JustBeforeEach(func() { 96 | err = c.Complete() 97 | }) 98 | 99 | It("should complete", func() { 100 | Expect(err).To(BeNil()) 101 | Expect(c.Channel).NotTo(BeNil()) 102 | }) 103 | 104 | Context("when factory fails to create channel client", func() { 105 | BeforeEach(func() { 106 | factory.ChannelReturns(nil, errors.New("factory error")) 107 | }) 108 | 109 | It("should fail with factory error", func() { 110 | Expect(err).NotTo(BeNil()) 111 | }) 112 | }) 113 | 114 | Context("when factory fails to create resmgmt client", func() { 115 | BeforeEach(func() { 116 | factory.ResourceManagementReturns(nil, errors.New("factory error")) 117 | }) 118 | 119 | It("should fail with factory error", func() { 120 | Expect(err).NotTo(BeNil()) 121 | }) 122 | }) 123 | }) 124 | }) 125 | -------------------------------------------------------------------------------- /pkg/fabric/fabric.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package fabric 8 | 9 | import ( 10 | "os" 11 | 12 | "github.com/hyperledger/fabric-cli/pkg/environment" 13 | "github.com/hyperledger/fabric-sdk-go/pkg/client/channel" 14 | "github.com/hyperledger/fabric-sdk-go/pkg/client/event" 15 | "github.com/hyperledger/fabric-sdk-go/pkg/client/ledger" 16 | "github.com/hyperledger/fabric-sdk-go/pkg/client/msp" 17 | "github.com/hyperledger/fabric-sdk-go/pkg/client/resmgmt" 18 | "github.com/hyperledger/fabric-sdk-go/pkg/core/config" 19 | "github.com/hyperledger/fabric-sdk-go/pkg/fabsdk" 20 | ) 21 | 22 | type factory struct { 23 | config string 24 | context *environment.Context 25 | } 26 | 27 | // interface implementation check 28 | var _ Factory = &factory{} 29 | 30 | // NewFactory creates a factory for the given profile/context 31 | func NewFactory(config *environment.Config) (Factory, error) { 32 | context, err := config.GetCurrentContext() 33 | if err != nil { 34 | return nil, err 35 | } 36 | 37 | network, err := config.GetCurrentContextNetwork() 38 | if err != nil { 39 | return nil, err 40 | } 41 | 42 | return &factory{ 43 | config: network.ConfigPath, 44 | context: context, 45 | }, nil 46 | } 47 | 48 | func (f *factory) SDK() (SDK, error) { 49 | sdk, err := fabsdk.New(config.FromFile(os.ExpandEnv(f.config))) 50 | if err != nil { 51 | return nil, err 52 | } 53 | 54 | return sdk, nil 55 | } 56 | 57 | func (f *factory) Channel() (Channel, error) { 58 | sdk, err := f.SDK() 59 | if err != nil { 60 | return nil, err 61 | } 62 | 63 | ctx := sdk.ChannelContext( 64 | f.context.Channel, 65 | fabsdk.WithUser(f.context.User), 66 | fabsdk.WithOrg(f.context.Organization), 67 | ) 68 | 69 | client, err := channel.New(ctx) 70 | if err != nil { 71 | return nil, err 72 | } 73 | 74 | return client, nil 75 | } 76 | 77 | func (f *factory) Event() (Event, error) { 78 | sdk, err := f.SDK() 79 | if err != nil { 80 | return nil, err 81 | } 82 | 83 | ctx := sdk.ChannelContext( 84 | f.context.Channel, 85 | fabsdk.WithUser(f.context.User), 86 | fabsdk.WithOrg(f.context.Organization), 87 | ) 88 | 89 | client, err := event.New(ctx) 90 | if err != nil { 91 | return nil, err 92 | } 93 | 94 | return client, nil 95 | } 96 | 97 | func (f *factory) Ledger() (Ledger, error) { 98 | sdk, err := f.SDK() 99 | if err != nil { 100 | return nil, err 101 | } 102 | 103 | ctx := sdk.ChannelContext( 104 | f.context.Channel, 105 | fabsdk.WithUser(f.context.User), 106 | fabsdk.WithOrg(f.context.Organization), 107 | ) 108 | 109 | client, err := ledger.New(ctx) 110 | if err != nil { 111 | return nil, err 112 | } 113 | 114 | return client, nil 115 | } 116 | 117 | func (f *factory) ResourceManagement() (ResourceManagement, error) { 118 | sdk, err := f.SDK() 119 | if err != nil { 120 | return nil, err 121 | } 122 | 123 | ctx := sdk.Context(fabsdk.WithUser(f.context.User), 124 | fabsdk.WithOrg(f.context.Organization)) 125 | 126 | client, err := resmgmt.New(ctx) 127 | if err != nil { 128 | return nil, err 129 | } 130 | 131 | return client, nil 132 | } 133 | 134 | func (f *factory) MSP() (MSP, error) { 135 | sdk, err := f.SDK() 136 | if err != nil { 137 | return nil, err 138 | } 139 | 140 | ctx := sdk.Context(fabsdk.WithUser(f.context.User), 141 | fabsdk.WithOrg(f.context.Organization)) 142 | 143 | client, err := msp.New(ctx) 144 | if err != nil { 145 | return nil, err 146 | } 147 | 148 | return client, nil 149 | } 150 | -------------------------------------------------------------------------------- /cmd/commands/lifecycle/lifecycle_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright SecureKey Technologies Inc. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package lifecycle_test 8 | 9 | import ( 10 | "bytes" 11 | "errors" 12 | "fmt" 13 | "os" 14 | "testing" 15 | 16 | . "github.com/onsi/ginkgo" 17 | . "github.com/onsi/gomega" 18 | "github.com/spf13/cobra" 19 | 20 | "github.com/hyperledger/fabric-cli/cmd/commands/lifecycle" 21 | "github.com/hyperledger/fabric-cli/pkg/environment" 22 | "github.com/hyperledger/fabric-cli/pkg/fabric/mocks" 23 | ) 24 | 25 | func TestLifecycle(t *testing.T) { 26 | RegisterFailHandler(Fail) 27 | RunSpecs(t, "Lifecycle Suite") 28 | } 29 | 30 | var _ = Describe("LifecycleChaincodeCommand", func() { 31 | var ( 32 | cmd *cobra.Command 33 | settings *environment.Settings 34 | out *bytes.Buffer 35 | ) 36 | 37 | Context("when creating a command from settings", func() { 38 | BeforeEach(func() { 39 | out = new(bytes.Buffer) 40 | 41 | settings = &environment.Settings{ 42 | Home: environment.Home(os.TempDir()), 43 | Streams: environment.Streams{ 44 | Out: out, 45 | }, 46 | } 47 | }) 48 | 49 | JustBeforeEach(func() { 50 | cmd = lifecycle.NewCommand(settings) 51 | }) 52 | 53 | It("should create a lifecycle command", func() { 54 | Expect(cmd.Name()).To(Equal("lifecycle")) 55 | Expect(cmd.HasSubCommands()).To(BeTrue()) 56 | Expect(cmd.Execute()).Should(Succeed()) 57 | Expect(fmt.Sprint(out)).To(ContainSubstring("lifecycle [command]")) 58 | Expect(fmt.Sprint(out)).To(ContainSubstring("package")) 59 | Expect(fmt.Sprint(out)).To(ContainSubstring("install")) 60 | Expect(fmt.Sprint(out)).To(ContainSubstring("approve")) 61 | Expect(fmt.Sprint(out)).To(ContainSubstring("commit")) 62 | Expect(fmt.Sprint(out)).To(ContainSubstring("queryinstalled")) 63 | Expect(fmt.Sprint(out)).To(ContainSubstring("getinstalledpackage")) 64 | Expect(fmt.Sprint(out)).To(ContainSubstring("queryapproved")) 65 | Expect(fmt.Sprint(out)).To(ContainSubstring("checkcommitreadiness")) 66 | Expect(fmt.Sprint(out)).To(ContainSubstring("querycommitted")) 67 | }) 68 | }) 69 | }) 70 | 71 | var _ = Describe("LifecycleBaseChaincodeCommand", func() { 72 | var c *lifecycle.BaseCommand 73 | 74 | BeforeEach(func() { 75 | c = &lifecycle.BaseCommand{} 76 | }) 77 | 78 | Describe("Complete", func() { 79 | var ( 80 | err error 81 | factory *mocks.Factory 82 | channelClient *mocks.Channel 83 | resmgmtClient *mocks.ResourceManagement 84 | ) 85 | 86 | BeforeEach(func() { 87 | factory = &mocks.Factory{} 88 | channelClient = &mocks.Channel{} 89 | resmgmtClient = &mocks.ResourceManagement{} 90 | 91 | factory.ResourceManagementReturns(resmgmtClient, nil) 92 | factory.ChannelReturns(channelClient, nil) 93 | 94 | c.Factory = factory 95 | }) 96 | 97 | JustBeforeEach(func() { 98 | err = c.Complete() 99 | }) 100 | 101 | It("should complete", func() { 102 | Expect(err).To(BeNil()) 103 | Expect(c.Channel).NotTo(BeNil()) 104 | }) 105 | 106 | Context("when factory fails to create channel client", func() { 107 | BeforeEach(func() { 108 | factory.ChannelReturns(nil, errors.New("factory error")) 109 | }) 110 | 111 | It("should fail with factory error", func() { 112 | Expect(err).NotTo(BeNil()) 113 | }) 114 | }) 115 | 116 | Context("when factory fails to create resmgmt client", func() { 117 | BeforeEach(func() { 118 | factory.ResourceManagementReturns(nil, errors.New("factory error")) 119 | }) 120 | 121 | It("should fail with factory error", func() { 122 | Expect(err).NotTo(BeNil()) 123 | }) 124 | }) 125 | }) 126 | }) 127 | -------------------------------------------------------------------------------- /cmd/commands/context/view_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package context_test 8 | 9 | import ( 10 | "bytes" 11 | "fmt" 12 | "os" 13 | 14 | . "github.com/onsi/ginkgo" 15 | . "github.com/onsi/gomega" 16 | "github.com/spf13/cobra" 17 | 18 | "github.com/hyperledger/fabric-cli/cmd/commands/context" 19 | "github.com/hyperledger/fabric-cli/pkg/environment" 20 | ) 21 | 22 | var _ = Describe("CurrentContextCommand", func() { 23 | var ( 24 | cmd *cobra.Command 25 | settings *environment.Settings 26 | out *bytes.Buffer 27 | 28 | args []string 29 | ) 30 | 31 | BeforeEach(func() { 32 | out = new(bytes.Buffer) 33 | 34 | settings = &environment.Settings{ 35 | Home: environment.Home(os.TempDir()), 36 | Streams: environment.Streams{ 37 | Out: out, 38 | }, 39 | } 40 | 41 | args = os.Args 42 | }) 43 | 44 | JustBeforeEach(func() { 45 | cmd = context.NewContextViewCommand(settings) 46 | }) 47 | 48 | AfterEach(func() { 49 | os.Args = args 50 | }) 51 | 52 | It("should create a view context command", func() { 53 | Expect(cmd.Name()).To(Equal("view")) 54 | Expect(cmd.HasSubCommands()).To(BeFalse()) 55 | }) 56 | 57 | It("should provide a help prompt", func() { 58 | os.Args = append(os.Args, "--help") 59 | 60 | Expect(cmd.Execute()).Should(Succeed()) 61 | Expect(fmt.Sprint(out)).To(ContainSubstring("view")) 62 | }) 63 | }) 64 | 65 | var _ = Describe("ViewContextImplementation", func() { 66 | var ( 67 | impl *context.ViewCommand 68 | err error 69 | out *bytes.Buffer 70 | settings *environment.Settings 71 | ) 72 | 73 | BeforeEach(func() { 74 | out = new(bytes.Buffer) 75 | 76 | settings = environment.NewDefaultSettings() 77 | settings.Home = environment.Home(os.TempDir()) 78 | settings.Streams = environment.Streams{Out: out} 79 | 80 | impl = &context.ViewCommand{} 81 | impl.Settings = settings 82 | }) 83 | 84 | It("should not be nil", func() { 85 | Expect(impl).ShouldNot(BeNil()) 86 | }) 87 | 88 | Describe("Run", func() { 89 | JustBeforeEach(func() { 90 | err = impl.Run() 91 | }) 92 | 93 | It("should fail without a context", func() { 94 | Expect(err).NotTo(BeNil()) 95 | }) 96 | 97 | Context("when a context exists", func() { 98 | BeforeEach(func() { 99 | settings.Config = &environment.Config{ 100 | CurrentContext: "foo", 101 | Contexts: map[string]*environment.Context{ 102 | "foo": {}, 103 | }, 104 | } 105 | }) 106 | 107 | It("should print the current context", func() { 108 | Expect(err).To(BeNil()) 109 | Expect(fmt.Sprint(out)).To(ContainSubstring("foo")) 110 | }) 111 | }) 112 | 113 | Context("when a name is provided and found", func() { 114 | BeforeEach(func() { 115 | settings.Config = &environment.Config{ 116 | CurrentContext: "foo", 117 | Contexts: map[string]*environment.Context{ 118 | "foo": {}, 119 | "bar": {}, 120 | }, 121 | } 122 | 123 | impl.Name = "bar" 124 | }) 125 | 126 | It("should print the specified context", func() { 127 | Expect(err).To(BeNil()) 128 | Expect(fmt.Sprint(out)).To(ContainSubstring("bar")) 129 | }) 130 | }) 131 | 132 | Context("when a name is provided but not found", func() { 133 | BeforeEach(func() { 134 | settings.Config = &environment.Config{ 135 | CurrentContext: "foo", 136 | Contexts: map[string]*environment.Context{ 137 | "foo": {}, 138 | }, 139 | } 140 | 141 | impl.Name = "bar" 142 | }) 143 | 144 | It("should print the specified context", func() { 145 | Expect(err).NotTo(BeNil()) 146 | Expect(err.Error()).To(ContainSubstring("context 'bar' does not exist")) 147 | }) 148 | }) 149 | }) 150 | }) 151 | -------------------------------------------------------------------------------- /cmd/commands/network/view_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package network_test 8 | 9 | import ( 10 | "bytes" 11 | "fmt" 12 | "os" 13 | 14 | . "github.com/onsi/ginkgo" 15 | . "github.com/onsi/gomega" 16 | "github.com/spf13/cobra" 17 | 18 | "github.com/hyperledger/fabric-cli/cmd/commands/network" 19 | "github.com/hyperledger/fabric-cli/pkg/environment" 20 | ) 21 | 22 | var _ = Describe("ViewNetworkCommand", func() { 23 | var ( 24 | cmd *cobra.Command 25 | settings *environment.Settings 26 | out *bytes.Buffer 27 | 28 | args []string 29 | ) 30 | 31 | BeforeEach(func() { 32 | out = new(bytes.Buffer) 33 | 34 | settings = &environment.Settings{ 35 | Home: environment.Home(os.TempDir()), 36 | Streams: environment.Streams{ 37 | Out: out, 38 | }, 39 | } 40 | 41 | args = os.Args 42 | }) 43 | 44 | JustBeforeEach(func() { 45 | cmd = network.NewNetworkViewCommand(settings) 46 | }) 47 | 48 | AfterEach(func() { 49 | os.Args = args 50 | }) 51 | 52 | It("should create a view network command", func() { 53 | Expect(cmd.Name()).To(Equal("view")) 54 | Expect(cmd.HasSubCommands()).To(BeFalse()) 55 | }) 56 | 57 | It("should provide a help prompt", func() { 58 | os.Args = append(os.Args, "--help") 59 | 60 | Expect(cmd.Execute()).Should(Succeed()) 61 | Expect(fmt.Sprint(out)).To(ContainSubstring("view")) 62 | }) 63 | }) 64 | 65 | var _ = Describe("ViewNetworkImplementation", func() { 66 | var ( 67 | impl *network.ViewCommand 68 | err error 69 | out *bytes.Buffer 70 | settings *environment.Settings 71 | ) 72 | 73 | BeforeEach(func() { 74 | out = new(bytes.Buffer) 75 | 76 | settings = environment.NewDefaultSettings() 77 | settings.Home = environment.Home(os.TempDir()) 78 | settings.Streams = environment.Streams{Out: out} 79 | 80 | impl = &network.ViewCommand{} 81 | impl.Settings = settings 82 | }) 83 | 84 | It("should not be nil", func() { 85 | Expect(impl).ShouldNot(BeNil()) 86 | }) 87 | 88 | Describe("Run", func() { 89 | JustBeforeEach(func() { 90 | err = impl.Run() 91 | }) 92 | 93 | It("should fail without a network", func() { 94 | Expect(err).NotTo(BeNil()) 95 | }) 96 | 97 | Context("when a network exists", func() { 98 | BeforeEach(func() { 99 | settings.Config = &environment.Config{ 100 | CurrentContext: "foo", 101 | Contexts: map[string]*environment.Context{ 102 | "foo": { 103 | Network: "bar", 104 | }, 105 | }, 106 | Networks: map[string]*environment.Network{ 107 | "bar": {}, 108 | }, 109 | } 110 | }) 111 | 112 | It("should print the current network", func() { 113 | Expect(err).To(BeNil()) 114 | Expect(fmt.Sprint(out)).To(ContainSubstring("bar")) 115 | }) 116 | }) 117 | 118 | Context("when a name is provided and found", func() { 119 | BeforeEach(func() { 120 | settings.Config = &environment.Config{ 121 | Networks: map[string]*environment.Network{ 122 | "foo": {}, 123 | }, 124 | } 125 | 126 | impl.Name = "foo" 127 | }) 128 | 129 | It("should print the specified network", func() { 130 | Expect(err).To(BeNil()) 131 | Expect(fmt.Sprint(out)).To(ContainSubstring("foo")) 132 | }) 133 | }) 134 | 135 | Context("when a name is provided but not found", func() { 136 | BeforeEach(func() { 137 | settings.Config = &environment.Config{ 138 | Networks: map[string]*environment.Network{ 139 | "foo": {}, 140 | }, 141 | } 142 | 143 | impl.Name = "bar" 144 | }) 145 | 146 | It("should print the specified network", func() { 147 | Expect(err).NotTo(BeNil()) 148 | Expect(err.Error()).To(ContainSubstring("network 'bar' does not exist")) 149 | }) 150 | }) 151 | }) 152 | }) 153 | -------------------------------------------------------------------------------- /cmd/commands/chaincode/package_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package chaincode_test 8 | 9 | import ( 10 | "bytes" 11 | "fmt" 12 | "os" 13 | 14 | . "github.com/onsi/ginkgo" 15 | . "github.com/onsi/gomega" 16 | "github.com/spf13/cobra" 17 | 18 | "github.com/hyperledger/fabric-cli/cmd/commands/chaincode" 19 | "github.com/hyperledger/fabric-cli/pkg/environment" 20 | ) 21 | 22 | var _ = Describe("ChaincodePackageCommand", func() { 23 | var ( 24 | cmd *cobra.Command 25 | settings *environment.Settings 26 | out *bytes.Buffer 27 | 28 | args []string 29 | ) 30 | 31 | BeforeEach(func() { 32 | out = new(bytes.Buffer) 33 | 34 | settings = &environment.Settings{ 35 | Home: environment.Home(os.TempDir()), 36 | Streams: environment.Streams{ 37 | Out: out, 38 | }, 39 | } 40 | 41 | args = os.Args 42 | }) 43 | 44 | JustBeforeEach(func() { 45 | cmd = chaincode.NewChaincodePackageCommand(settings) 46 | }) 47 | 48 | AfterEach(func() { 49 | os.Args = args 50 | }) 51 | 52 | It("should create a chaincode package command", func() { 53 | Expect(cmd.Name()).To(Equal("package")) 54 | Expect(cmd.HasSubCommands()).To(BeFalse()) 55 | }) 56 | 57 | It("should provide a help prompt", func() { 58 | os.Args = append(os.Args, "--help") 59 | 60 | Expect(cmd.Execute()).Should(Succeed()) 61 | Expect(fmt.Sprint(out)).To(ContainSubstring("package ")) 62 | }) 63 | }) 64 | 65 | var _ = Describe("ChaincodePackageImplementation", func() { 66 | var ( 67 | impl *chaincode.PackageCommand 68 | err error 69 | out *bytes.Buffer 70 | settings *environment.Settings 71 | ) 72 | 73 | BeforeEach(func() { 74 | out = new(bytes.Buffer) 75 | 76 | settings = &environment.Settings{ 77 | Home: environment.Home(os.TempDir()), 78 | Streams: environment.Streams{ 79 | Out: out, 80 | }, 81 | } 82 | 83 | impl = &chaincode.PackageCommand{} 84 | impl.Settings = settings 85 | }) 86 | 87 | It("should not be nil", func() { 88 | Expect(impl).ShouldNot(BeNil()) 89 | }) 90 | 91 | Describe("Validate", func() { 92 | JustBeforeEach(func() { 93 | err = impl.Validate() 94 | }) 95 | 96 | It("should fail when name is not set", func() { 97 | Expect(err).NotTo(BeNil()) 98 | Expect(err.Error()).To(Equal("chaincode name not specified")) 99 | }) 100 | 101 | Context("when chaincode path is not set", func() { 102 | BeforeEach(func() { 103 | impl.ChaincodeName = "mycc" 104 | }) 105 | 106 | It("should fail without chaincode path", func() { 107 | Expect(err).NotTo(BeNil()) 108 | Expect(err.Error()).To(Equal("chaincode path not specified")) 109 | }) 110 | }) 111 | 112 | Context("when all arguments are set", func() { 113 | BeforeEach(func() { 114 | impl.ChaincodeName = "mycc" 115 | impl.ChaincodePath = "path" 116 | }) 117 | 118 | It("should succeed with all arguments", func() { 119 | Expect(err).To(BeNil()) 120 | }) 121 | }) 122 | }) 123 | 124 | Describe("Run", func() { 125 | BeforeEach(func() { 126 | impl.ChaincodeName = "mycc" 127 | impl.ChaincodePath = "github.com/hyperledger/fabric-cli/cmd/commands/chaincode/testdata/chaincode/example/example.go" 128 | }) 129 | 130 | JustBeforeEach(func() { 131 | err = impl.Run() 132 | }) 133 | 134 | Context("when chaincode path is invalid", func() { 135 | BeforeEach(func() { 136 | settings.Config = &environment.Config{ 137 | Contexts: map[string]*environment.Context{ 138 | "foo": {}, 139 | }, 140 | CurrentContext: "foo", 141 | } 142 | 143 | impl.ChaincodePath = "path/to/chaincode" 144 | }) 145 | 146 | It("should fail with an invalid path", func() { 147 | Expect(err).NotTo(BeNil()) 148 | }) 149 | }) 150 | }) 151 | }) 152 | -------------------------------------------------------------------------------- /cmd/commands/lifecycle/querycommitted.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright SecureKey Technologies Inc. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package lifecycle 8 | 9 | import ( 10 | "github.com/hyperledger/fabric-sdk-go/pkg/client/resmgmt" 11 | "github.com/hyperledger/fabric-sdk-go/pkg/common/errors/retry" 12 | "github.com/pkg/errors" 13 | "github.com/spf13/cobra" 14 | 15 | "github.com/hyperledger/fabric-cli/pkg/environment" 16 | ) 17 | 18 | // NewQueryCommittedCommand creates a new "fabric lifecycle querycommitted" command 19 | func NewQueryCommittedCommand(settings *environment.Settings) *cobra.Command { 20 | c := QueryCommittedCommand{} 21 | 22 | c.Settings = settings 23 | 24 | cmd := &cobra.Command{ 25 | Use: "querycommitted ", 26 | Short: "Query for committed chaincodes", 27 | Args: c.ParseArgs(), 28 | PreRunE: func(_ *cobra.Command, _ []string) error { 29 | if err := c.Complete(); err != nil { 30 | return err 31 | } 32 | 33 | return nil 34 | }, 35 | RunE: func(_ *cobra.Command, _ []string) error { 36 | return c.Run() 37 | }, 38 | } 39 | 40 | c.AddArg(&c.ChaincodeName) 41 | 42 | flags := cmd.Flags() 43 | flags.StringVar(&c.OutputFormat, "output", "", outputFormatUsage) 44 | 45 | cmd.SetOutput(c.Settings.Streams.Out) 46 | 47 | return cmd 48 | } 49 | 50 | // QueryCommittedCommand implements the chaincode queryapproved command 51 | type QueryCommittedCommand struct { 52 | BaseCommand 53 | 54 | ChaincodeName string 55 | OutputFormat string 56 | } 57 | 58 | // Validate checks the required parameters for run 59 | func (c *QueryCommittedCommand) Validate() error { 60 | if c.ChaincodeName == "" { 61 | return errors.New("chaincode name not specified") 62 | } 63 | 64 | return nil 65 | } 66 | 67 | // Run executes the command 68 | func (c *QueryCommittedCommand) Run() error { 69 | context, err := c.Settings.Config.GetCurrentContext() 70 | if err != nil { 71 | return err 72 | } 73 | 74 | committedChaincodes, err := c.ResourceManagement.LifecycleQueryCommittedCC( 75 | context.Channel, 76 | resmgmt.LifecycleQueryCommittedCCRequest{ 77 | Name: c.ChaincodeName, 78 | }, 79 | resmgmt.WithRetry(retry.DefaultResMgmtOpts), 80 | resmgmt.WithTargetEndpoints(context.Peers[0]), 81 | ) 82 | if err != nil { 83 | return err 84 | } 85 | 86 | if c.OutputFormat == jsonFormat { 87 | return c.printJSONResponse(committedChaincodes) 88 | } 89 | 90 | c.printResponse(committedChaincodes) 91 | 92 | return nil 93 | } 94 | 95 | func (c *QueryCommittedCommand) printResponse(defs []resmgmt.LifecycleChaincodeDefinition) { 96 | if len(defs) == 0 { 97 | c.println("No committed chaincodes") 98 | 99 | return 100 | } 101 | 102 | for _, def := range defs { 103 | var approvingOrgs []string 104 | var nonApprovingOrgs []string 105 | 106 | for org, approved := range def.Approvals { 107 | if approved { 108 | approvingOrgs = append(approvingOrgs, org) 109 | } else { 110 | nonApprovingOrgs = append(nonApprovingOrgs, org) 111 | } 112 | } 113 | 114 | c.printf("Name: %s, Version: %s, Sequence: %d, Validation Plugin: %s, Endorsement Plugin: %s,"+ 115 | " Channel Config Policy: %s, Init Required: %t, Approving orgs: %s, Non-approving orgs: %s\n", 116 | def.Name, def.Version, def.Sequence, def.ValidationPlugin, def.EndorsementPlugin, def.ChannelConfigPolicy, 117 | def.InitRequired, approvingOrgs, nonApprovingOrgs) 118 | 119 | for _, collConfig := range def.CollectionConfig { 120 | cfg := collConfig.GetStaticCollectionConfig() 121 | 122 | c.printf("- Collection: %s, Blocks to Live: %d, Maximum Peer Count: %d,"+ 123 | " Required Peer Count: %d, MemberOnlyRead: %t, cfg.MemberOnlyWrite: %t\n", 124 | cfg.Name, cfg.BlockToLive, cfg.MaximumPeerCount, cfg.RequiredPeerCount, cfg.MemberOnlyRead, cfg.MemberOnlyWrite) 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /cmd/commands/chaincode/query_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package chaincode_test 8 | 9 | import ( 10 | "bytes" 11 | "errors" 12 | "fmt" 13 | "os" 14 | 15 | . "github.com/onsi/ginkgo" 16 | . "github.com/onsi/gomega" 17 | "github.com/spf13/cobra" 18 | 19 | "github.com/hyperledger/fabric-cli/cmd/commands/chaincode" 20 | "github.com/hyperledger/fabric-cli/pkg/environment" 21 | "github.com/hyperledger/fabric-cli/pkg/fabric/mocks" 22 | "github.com/hyperledger/fabric-sdk-go/pkg/client/channel" 23 | ) 24 | 25 | var _ = Describe("ChaincodeQueryCommand", func() { 26 | var ( 27 | cmd *cobra.Command 28 | settings *environment.Settings 29 | out *bytes.Buffer 30 | 31 | args []string 32 | ) 33 | 34 | BeforeEach(func() { 35 | out = new(bytes.Buffer) 36 | 37 | settings = &environment.Settings{ 38 | Home: environment.Home(os.TempDir()), 39 | Streams: environment.Streams{ 40 | Out: out, 41 | }, 42 | } 43 | 44 | args = os.Args 45 | }) 46 | 47 | JustBeforeEach(func() { 48 | cmd = chaincode.NewChaincodeQueryCommand(settings) 49 | }) 50 | 51 | AfterEach(func() { 52 | os.Args = args 53 | }) 54 | 55 | It("should create a chaincode query command", func() { 56 | Expect(cmd.Name()).To(Equal("query")) 57 | Expect(cmd.HasSubCommands()).To(BeFalse()) 58 | }) 59 | 60 | It("should provide a help prompt", func() { 61 | os.Args = append(os.Args, "--help") 62 | 63 | Expect(cmd.Execute()).Should(Succeed()) 64 | Expect(fmt.Sprint(out)).To(ContainSubstring("query ")) 65 | }) 66 | }) 67 | 68 | var _ = Describe("ChaincodeQueryImplementation", func() { 69 | var ( 70 | impl *chaincode.QueryCommand 71 | err error 72 | out *bytes.Buffer 73 | settings *environment.Settings 74 | factory *mocks.Factory 75 | client *mocks.Channel 76 | ) 77 | 78 | BeforeEach(func() { 79 | out = new(bytes.Buffer) 80 | 81 | settings = &environment.Settings{ 82 | Home: environment.Home(os.TempDir()), 83 | Streams: environment.Streams{ 84 | Out: out, 85 | }, 86 | } 87 | 88 | factory = &mocks.Factory{} 89 | client = &mocks.Channel{} 90 | 91 | impl = &chaincode.QueryCommand{} 92 | impl.Settings = settings 93 | impl.Factory = factory 94 | }) 95 | 96 | It("should not be nil", func() { 97 | Expect(impl).ShouldNot(BeNil()) 98 | }) 99 | 100 | Describe("Validate", func() { 101 | JustBeforeEach(func() { 102 | err = impl.Validate() 103 | }) 104 | 105 | It("should fail when name is not set", func() { 106 | Expect(err).NotTo(BeNil()) 107 | Expect(err.Error()).To(Equal("chaincode name not specified")) 108 | }) 109 | 110 | Context("when chaincode name is set", func() { 111 | BeforeEach(func() { 112 | impl.ChaincodeName = "mycc" 113 | }) 114 | 115 | It("should succeed with chaincode name", func() { 116 | Expect(err).To(BeNil()) 117 | }) 118 | }) 119 | }) 120 | 121 | Describe("Run", func() { 122 | BeforeEach(func() { 123 | impl.ChaincodeName = "mycc" 124 | 125 | impl.Channel = client 126 | }) 127 | 128 | JustBeforeEach(func() { 129 | 130 | err = impl.Run() 131 | 132 | }) 133 | 134 | Context("when channel client succeeds", func() { 135 | BeforeEach(func() { 136 | client.QueryReturns(channel.Response{}, nil) 137 | }) 138 | 139 | It("should successfully run chaincode query", func() { 140 | Expect(err).To(BeNil()) 141 | }) 142 | }) 143 | 144 | Context("when channel client fails", func() { 145 | BeforeEach(func() { 146 | client.QueryReturns(channel.Response{}, errors.New("query error")) 147 | }) 148 | 149 | It("should fail to run chaincode query", func() { 150 | Expect(err).NotTo(BeNil()) 151 | Expect(err.Error()).To(ContainSubstring("query error")) 152 | }) 153 | }) 154 | }) 155 | }) 156 | -------------------------------------------------------------------------------- /cmd/commands/lifecycle/package_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright SecureKey Technologies Inc. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package lifecycle_test 8 | 9 | import ( 10 | "bytes" 11 | "fmt" 12 | "os" 13 | 14 | . "github.com/onsi/ginkgo" 15 | . "github.com/onsi/gomega" 16 | "github.com/spf13/cobra" 17 | 18 | "github.com/hyperledger/fabric-cli/cmd/commands/lifecycle" 19 | "github.com/hyperledger/fabric-cli/pkg/environment" 20 | ) 21 | 22 | var _ = Describe("LifecycleChaincodePackageCommand", func() { 23 | var ( 24 | cmd *cobra.Command 25 | settings *environment.Settings 26 | out *bytes.Buffer 27 | 28 | args []string 29 | ) 30 | 31 | BeforeEach(func() { 32 | out = new(bytes.Buffer) 33 | 34 | settings = &environment.Settings{ 35 | Home: environment.Home(os.TempDir()), 36 | Streams: environment.Streams{ 37 | Out: out, 38 | }, 39 | } 40 | 41 | args = os.Args 42 | }) 43 | 44 | JustBeforeEach(func() { 45 | cmd = lifecycle.NewPackageCommand(settings) 46 | }) 47 | 48 | AfterEach(func() { 49 | os.Args = args 50 | }) 51 | 52 | It("should create a chaincode package command", func() { 53 | Expect(cmd.Name()).To(Equal("package")) 54 | Expect(cmd.HasSubCommands()).To(BeFalse()) 55 | }) 56 | 57 | It("should provide a help prompt", func() { 58 | os.Args = append(os.Args, "--help") 59 | 60 | Expect(cmd.Execute()).Should(Succeed()) 61 | Expect(fmt.Sprint(out)).To(ContainSubstring("package ")) 62 | }) 63 | }) 64 | 65 | var _ = Describe("LifecycleChaincodePackageImplementation", func() { 66 | var ( 67 | impl *lifecycle.PackageCommand 68 | err error 69 | out *bytes.Buffer 70 | settings *environment.Settings 71 | ) 72 | 73 | BeforeEach(func() { 74 | out = new(bytes.Buffer) 75 | 76 | settings = &environment.Settings{ 77 | Home: environment.Home(os.TempDir()), 78 | Streams: environment.Streams{ 79 | Out: out, 80 | }, 81 | } 82 | 83 | impl = &lifecycle.PackageCommand{} 84 | impl.Settings = settings 85 | }) 86 | 87 | It("should not be nil", func() { 88 | Expect(impl).ShouldNot(BeNil()) 89 | }) 90 | 91 | Describe("Validate", func() { 92 | JustBeforeEach(func() { 93 | err = impl.Validate() 94 | }) 95 | 96 | It("should fail when label is not set", func() { 97 | Expect(err).NotTo(BeNil()) 98 | Expect(err.Error()).To(Equal("chaincode label not specified")) 99 | }) 100 | 101 | Context("when chaincode path is not set", func() { 102 | BeforeEach(func() { 103 | impl.Label = "mycc" 104 | }) 105 | 106 | It("should fail without chaincode path", func() { 107 | Expect(err).NotTo(BeNil()) 108 | Expect(err.Error()).To(Equal("chaincode path not specified")) 109 | }) 110 | }) 111 | 112 | Context("when all arguments are set", func() { 113 | BeforeEach(func() { 114 | impl.Label = "mycc" 115 | impl.Path = "path" 116 | impl.Type = "golang" 117 | }) 118 | 119 | It("should succeed with all arguments", func() { 120 | Expect(err).To(BeNil()) 121 | }) 122 | }) 123 | }) 124 | 125 | Describe("Run", func() { 126 | BeforeEach(func() { 127 | impl.Label = "mycc" 128 | impl.Path = "github.com/hyperledger/fabric-cli/cmd/commands/lifecycle/testdata/chaincode/example/example.go" 129 | }) 130 | 131 | JustBeforeEach(func() { 132 | err = impl.Run() 133 | }) 134 | 135 | Context("when chaincode path is invalid", func() { 136 | BeforeEach(func() { 137 | settings.Config = &environment.Config{ 138 | Contexts: map[string]*environment.Context{ 139 | "foo": {}, 140 | }, 141 | CurrentContext: "foo", 142 | } 143 | 144 | impl.Path = "path/to/chaincode" 145 | }) 146 | 147 | It("should fail with an invalid path", func() { 148 | Expect(err).NotTo(BeNil()) 149 | }) 150 | }) 151 | }) 152 | }) 153 | -------------------------------------------------------------------------------- /cmd/commands/network/delete_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package network_test 8 | 9 | import ( 10 | "bytes" 11 | "fmt" 12 | "io/ioutil" 13 | "os" 14 | 15 | . "github.com/onsi/ginkgo" 16 | . "github.com/onsi/gomega" 17 | "github.com/spf13/cobra" 18 | "gopkg.in/yaml.v2" 19 | 20 | "github.com/hyperledger/fabric-cli/cmd/commands/network" 21 | "github.com/hyperledger/fabric-cli/pkg/environment" 22 | ) 23 | 24 | var _ = Describe("NetworkDeleteCommand", func() { 25 | var ( 26 | cmd *cobra.Command 27 | settings *environment.Settings 28 | out *bytes.Buffer 29 | 30 | args []string 31 | ) 32 | 33 | BeforeEach(func() { 34 | out = new(bytes.Buffer) 35 | 36 | settings = &environment.Settings{ 37 | Home: environment.Home(os.TempDir()), 38 | Streams: environment.Streams{ 39 | Out: out, 40 | }, 41 | } 42 | 43 | args = os.Args 44 | }) 45 | 46 | JustBeforeEach(func() { 47 | cmd = network.NewNetworkDeleteCommand(settings) 48 | }) 49 | 50 | AfterEach(func() { 51 | os.Args = args 52 | }) 53 | 54 | It("should create a delete network command", func() { 55 | Expect(cmd.Name()).To(Equal("delete")) 56 | Expect(cmd.HasSubCommands()).To(BeFalse()) 57 | }) 58 | 59 | It("should provide a help prompt", func() { 60 | os.Args = append(os.Args, "--help") 61 | 62 | Expect(cmd.Execute()).Should(Succeed()) 63 | Expect(fmt.Sprint(out)).To(ContainSubstring("delete")) 64 | }) 65 | }) 66 | 67 | var _ = Describe("NetworkDeleteImplementation", func() { 68 | var ( 69 | impl *network.DeleteCommand 70 | err error 71 | out *bytes.Buffer 72 | settings *environment.Settings 73 | ) 74 | 75 | BeforeEach(func() { 76 | out = new(bytes.Buffer) 77 | 78 | settings = environment.NewDefaultSettings() 79 | settings.Home = environment.Home(os.TempDir()) 80 | settings.Streams = environment.Streams{Out: out} 81 | 82 | impl = &network.DeleteCommand{} 83 | impl.Settings = settings 84 | }) 85 | 86 | It("should not be nil", func() { 87 | Expect(impl).ShouldNot(BeNil()) 88 | }) 89 | 90 | Describe("Validate", func() { 91 | JustBeforeEach(func() { 92 | err = impl.Validate() 93 | }) 94 | 95 | It("should fail without network name", func() { 96 | Expect(err).NotTo(BeNil()) 97 | }) 98 | 99 | Context("when network name is set", func() { 100 | BeforeEach(func() { 101 | impl.Name = "foo" 102 | }) 103 | 104 | It("should successfully validate", func() { 105 | Expect(err).To(BeNil()) 106 | }) 107 | }) 108 | }) 109 | 110 | Describe("Run", func() { 111 | JustBeforeEach(func() { 112 | err = impl.Run() 113 | }) 114 | 115 | JustAfterEach(func() { 116 | os.RemoveAll(impl.Settings.Home.Path(environment.DefaultConfigFilename)) 117 | }) 118 | 119 | Context("when a network exists", func() { 120 | BeforeEach(func() { 121 | settings.Config = &environment.Config{ 122 | Networks: map[string]*environment.Network{ 123 | "foo": {}, 124 | "bar": {}, 125 | }, 126 | } 127 | 128 | impl.Name = "bar" 129 | }) 130 | 131 | It("should delete the network", func() { 132 | Expect(err).To(BeNil()) 133 | Expect(fmt.Sprint(out)).To(ContainSubstring("successfully deleted network 'bar'")) 134 | }) 135 | }) 136 | 137 | Context("when network file is invalid", func() { 138 | BeforeEach(func() { 139 | data, _ := yaml.Marshal(struct { 140 | Networks string 141 | }{ 142 | Networks: "foo", 143 | }) 144 | 145 | os.MkdirAll(settings.Home.String(), 0777) 146 | 147 | ioutil.WriteFile( 148 | settings.Home.Path(environment.DefaultConfigFilename), 149 | data, 150 | 0777, 151 | ) 152 | }) 153 | 154 | It("should fail to unmarshal network file", func() { 155 | Expect(err).NotTo(BeNil()) 156 | }) 157 | }) 158 | }) 159 | }) 160 | -------------------------------------------------------------------------------- /cmd/commands/context/delete_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package context_test 8 | 9 | import ( 10 | "bytes" 11 | "fmt" 12 | "io/ioutil" 13 | "os" 14 | 15 | . "github.com/onsi/ginkgo" 16 | . "github.com/onsi/gomega" 17 | "github.com/spf13/cobra" 18 | "gopkg.in/yaml.v2" 19 | 20 | "github.com/hyperledger/fabric-cli/cmd/commands/context" 21 | "github.com/hyperledger/fabric-cli/pkg/environment" 22 | ) 23 | 24 | var _ = Describe("DeleteContextCommand", func() { 25 | var ( 26 | cmd *cobra.Command 27 | settings *environment.Settings 28 | out *bytes.Buffer 29 | 30 | args []string 31 | ) 32 | 33 | BeforeEach(func() { 34 | out = new(bytes.Buffer) 35 | 36 | settings = &environment.Settings{ 37 | Home: environment.Home(os.TempDir()), 38 | Streams: environment.Streams{ 39 | Out: out, 40 | }, 41 | } 42 | 43 | args = os.Args 44 | }) 45 | 46 | JustBeforeEach(func() { 47 | cmd = context.NewContextDeleteCommand(settings) 48 | }) 49 | 50 | AfterEach(func() { 51 | os.Args = args 52 | }) 53 | 54 | It("should create a delete context command", func() { 55 | Expect(cmd.Name()).To(Equal("delete")) 56 | Expect(cmd.HasSubCommands()).To(BeFalse()) 57 | }) 58 | 59 | It("should provide a help prompt", func() { 60 | os.Args = append(os.Args, "--help") 61 | 62 | Expect(cmd.Execute()).Should(Succeed()) 63 | Expect(fmt.Sprint(out)).To(ContainSubstring("delete")) 64 | }) 65 | }) 66 | 67 | var _ = Describe("DeleteContextImplementation", func() { 68 | var ( 69 | impl *context.DeleteCommand 70 | err error 71 | out *bytes.Buffer 72 | settings *environment.Settings 73 | ) 74 | 75 | BeforeEach(func() { 76 | out = new(bytes.Buffer) 77 | 78 | settings = environment.NewDefaultSettings() 79 | settings.Home = environment.Home(os.TempDir()) 80 | settings.Streams = environment.Streams{Out: out} 81 | 82 | impl = &context.DeleteCommand{} 83 | impl.Settings = settings 84 | }) 85 | 86 | It("should not be nil", func() { 87 | Expect(impl).ShouldNot(BeNil()) 88 | }) 89 | 90 | Describe("Validate", func() { 91 | JustBeforeEach(func() { 92 | err = impl.Validate() 93 | }) 94 | 95 | It("should fail without context name", func() { 96 | Expect(err).NotTo(BeNil()) 97 | }) 98 | 99 | Context("when context name is set", func() { 100 | BeforeEach(func() { 101 | impl.Name = "foo" 102 | }) 103 | 104 | It("should successfully validate", func() { 105 | Expect(err).To(BeNil()) 106 | }) 107 | }) 108 | }) 109 | 110 | Describe("Run", func() { 111 | JustBeforeEach(func() { 112 | err = impl.Run() 113 | }) 114 | 115 | JustAfterEach(func() { 116 | os.RemoveAll(impl.Settings.Home.Path(environment.DefaultConfigFilename)) 117 | }) 118 | 119 | Context("when a context exists", func() { 120 | BeforeEach(func() { 121 | settings.Config = &environment.Config{ 122 | CurrentContext: "foo", 123 | Contexts: map[string]*environment.Context{ 124 | "foo": {}, 125 | "bar": {}, 126 | }, 127 | } 128 | 129 | impl.Name = "bar" 130 | }) 131 | 132 | It("should delete the context", func() { 133 | Expect(err).To(BeNil()) 134 | Expect(fmt.Sprint(out)).To(ContainSubstring("successfully deleted context 'bar'")) 135 | }) 136 | }) 137 | 138 | Context("when context file is invalid", func() { 139 | BeforeEach(func() { 140 | data, _ := yaml.Marshal(struct { 141 | Networks string 142 | }{ 143 | Networks: "foo", 144 | }) 145 | 146 | os.MkdirAll(settings.Home.String(), 0777) 147 | 148 | ioutil.WriteFile( 149 | settings.Home.Path(environment.DefaultConfigFilename), 150 | data, 151 | 0777, 152 | ) 153 | }) 154 | 155 | It("should fail to unmarshal context file", func() { 156 | Expect(err).NotTo(BeNil()) 157 | }) 158 | }) 159 | }) 160 | }) 161 | -------------------------------------------------------------------------------- /cmd/commands/chaincode/upgrade.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package chaincode 8 | 9 | import ( 10 | "encoding/json" 11 | "errors" 12 | "fmt" 13 | 14 | "github.com/hyperledger/fabric-sdk-go/pkg/client/resmgmt" 15 | "github.com/hyperledger/fabric-sdk-go/pkg/common/errors/retry" 16 | "github.com/spf13/cobra" 17 | 18 | "github.com/hyperledger/fabric-cli/cmd/commands/common" 19 | "github.com/hyperledger/fabric-cli/pkg/environment" 20 | ) 21 | 22 | // NewChaincodeUpgradeCommand creates a new "fabric chaincode upgrade" command 23 | func NewChaincodeUpgradeCommand(settings *environment.Settings) *cobra.Command { 24 | c := UpgradeCommand{} 25 | 26 | c.Settings = settings 27 | 28 | cmd := &cobra.Command{ 29 | Use: "upgrade ", 30 | Short: "Upgrade a chaincode", 31 | Long: "Upgrade a chaincode with chaincode-name version path args collection and policy", 32 | Args: c.ParseArgs(), 33 | PreRunE: func(_ *cobra.Command, _ []string) error { 34 | if err := c.Complete(); err != nil { 35 | return err 36 | } 37 | 38 | if err := c.Validate(); err != nil { 39 | return err 40 | } 41 | 42 | return nil 43 | }, 44 | RunE: func(_ *cobra.Command, _ []string) error { 45 | return c.Run() 46 | }, 47 | } 48 | 49 | c.AddArg(&c.ChaincodeName) 50 | c.AddArg(&c.ChaincodeVersion) 51 | c.AddArg(&c.ChaincodePath) 52 | 53 | flags := cmd.Flags() 54 | flags.StringArrayVar(&c.ChaincodeArgs, "args", []string{}, "Set the upgrade arguments") 55 | flags.StringVar(&c.ChaincodePolicy, "policy", "", "Set the endorsement policy") 56 | flags.StringVar(&c.ChaincodeCollectionsConfig, "collections-config", "", "Set the path to the collections config file") 57 | 58 | cmd.SetOutput(c.Settings.Streams.Out) 59 | 60 | return cmd 61 | } 62 | 63 | // UpgradeCommand implements the chaincode upgrade command 64 | type UpgradeCommand struct { 65 | BaseCommand 66 | 67 | ChaincodeName string 68 | ChaincodeVersion string 69 | ChaincodePath string 70 | 71 | ChaincodeArgs []string 72 | ChaincodePolicy string 73 | ChaincodeCollectionsConfig string 74 | } 75 | 76 | // Validate checks the required parameters for run 77 | func (c *UpgradeCommand) Validate() error { 78 | if len(c.ChaincodeName) == 0 { 79 | return errors.New("chaincode name not specified") 80 | } 81 | 82 | if len(c.ChaincodeVersion) == 0 { 83 | return errors.New("chaincode version not specified") 84 | } 85 | 86 | if len(c.ChaincodePath) == 0 { 87 | return errors.New("chaincode path not specified") 88 | } 89 | 90 | return nil 91 | } 92 | 93 | // Run executes the command 94 | func (c *UpgradeCommand) Run() error { 95 | context, err := c.Settings.Config.GetCurrentContext() 96 | if err != nil { 97 | return err 98 | } 99 | 100 | args, err := json.Marshal(c.ChaincodeArgs) 101 | if err != nil { 102 | return err 103 | } 104 | 105 | policy, err := common.GetChaincodePolicy(c.ChaincodePolicy) 106 | if err != nil { 107 | return err 108 | } 109 | 110 | collectionsConfig, err := common.GetCollectionConfigFromFile(c.ChaincodeCollectionsConfig) 111 | if err != nil { 112 | return err 113 | } 114 | 115 | req := resmgmt.UpgradeCCRequest{ 116 | Name: c.ChaincodeName, 117 | Path: c.ChaincodePath, 118 | Version: c.ChaincodeVersion, 119 | Args: [][]byte{[]byte("init"), args}, 120 | Policy: policy, 121 | CollConfig: collectionsConfig, 122 | } 123 | 124 | options := []resmgmt.RequestOption{ 125 | resmgmt.WithTargetEndpoints(context.Peers...), 126 | resmgmt.WithRetry(retry.DefaultResMgmtOpts), 127 | } 128 | 129 | if _, err := c.ResourceManagement.UpgradeCC(context.Channel, req, options...); err != nil { 130 | return err 131 | } 132 | 133 | fmt.Fprintf(c.Settings.Streams.Out, "successfully upgraded chaincode '%s'\n", c.ChaincodeName) 134 | 135 | return nil 136 | } 137 | -------------------------------------------------------------------------------- /cmd/commands/lifecycle/queryapproved.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright SecureKey Technologies Inc. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package lifecycle 8 | 9 | import ( 10 | "strconv" 11 | 12 | "github.com/hyperledger/fabric-sdk-go/pkg/client/resmgmt" 13 | "github.com/hyperledger/fabric-sdk-go/pkg/common/errors/retry" 14 | "github.com/pkg/errors" 15 | "github.com/spf13/cobra" 16 | 17 | "github.com/hyperledger/fabric-cli/pkg/environment" 18 | ) 19 | 20 | // NewQueryApprovedCommand creates a new "fabric lifecycle queryapproved" command 21 | func NewQueryApprovedCommand(settings *environment.Settings) *cobra.Command { 22 | c := QueryApprovedCommand{} 23 | 24 | c.Settings = settings 25 | 26 | cmd := &cobra.Command{ 27 | Use: "queryapproved ", 28 | Short: "Query for approved chaincodes", 29 | Args: c.ParseArgs(), 30 | PreRunE: func(_ *cobra.Command, _ []string) error { 31 | if err := c.Complete(); err != nil { 32 | return err 33 | } 34 | 35 | return nil 36 | }, 37 | RunE: func(_ *cobra.Command, _ []string) error { 38 | return c.Run() 39 | }, 40 | } 41 | 42 | c.AddArg(&c.ChaincodeName) 43 | c.AddArg(&c.Sequence) 44 | 45 | flags := cmd.Flags() 46 | flags.StringVar(&c.Sequence, "sequence", "", "sets the sequence number (if not specified then the latest sequence is used)") 47 | flags.StringVar(&c.OutputFormat, "output", "", outputFormatUsage) 48 | 49 | cmd.SetOutput(c.Settings.Streams.Out) 50 | 51 | return cmd 52 | } 53 | 54 | // QueryApprovedCommand implements the chaincode queryapproved command 55 | type QueryApprovedCommand struct { 56 | BaseCommand 57 | 58 | ChaincodeName string 59 | Sequence string 60 | OutputFormat string 61 | } 62 | 63 | // Validate checks the required parameters for run 64 | func (c *QueryApprovedCommand) Validate() error { 65 | if c.ChaincodeName == "" { 66 | return errors.New("chaincode name not specified") 67 | } 68 | 69 | if c.Sequence != "" { 70 | _, err := strconv.ParseInt(c.Sequence, 10, 64) 71 | if err != nil { 72 | return errors.WithMessage(err, "invalid sequence") 73 | } 74 | } 75 | 76 | return nil 77 | } 78 | 79 | // Run executes the command 80 | func (c *QueryApprovedCommand) Run() error { 81 | context, err := c.Settings.Config.GetCurrentContext() 82 | if err != nil { 83 | return err 84 | } 85 | 86 | var sequence int64 87 | if c.Sequence != "" { 88 | sequence, err = strconv.ParseInt(c.Sequence, 10, 64) 89 | if err != nil { 90 | return errors.WithMessage(err, "invalid sequence") 91 | } 92 | } 93 | 94 | approvedChaincode, err := c.ResourceManagement.LifecycleQueryApprovedCC( 95 | context.Channel, 96 | resmgmt.LifecycleQueryApprovedCCRequest{ 97 | Name: c.ChaincodeName, 98 | Sequence: sequence, 99 | }, 100 | resmgmt.WithRetry(retry.DefaultResMgmtOpts), 101 | resmgmt.WithTargetEndpoints(context.Peers[0]), 102 | ) 103 | if err != nil { 104 | return err 105 | } 106 | 107 | if c.OutputFormat == jsonFormat { 108 | return c.printJSONResponse(approvedChaincode) 109 | } 110 | 111 | c.printResponse(approvedChaincode) 112 | 113 | return nil 114 | } 115 | 116 | func (c *QueryApprovedCommand) printResponse(ac resmgmt.LifecycleApprovedChaincodeDefinition) { 117 | c.printf("Name: %s, Version: %s, Package ID: %s, Sequence: %d, Validation Plugin: %s,"+ 118 | " Endorsement Plugin: %s, Channel Config Policy: %s, Init Required: %t\n", 119 | ac.Name, ac.Version, ac.PackageID, ac.Sequence, ac.ValidationPlugin, ac.EndorsementPlugin, ac.ChannelConfigPolicy, ac.InitRequired) 120 | 121 | for _, collConfig := range ac.CollectionConfig { 122 | cfg := collConfig.GetStaticCollectionConfig() 123 | 124 | c.printf("- Collection: %s, Blocks to Live: %d, Maximum Peer Count: %d,"+ 125 | " Required Peer Count: %d, MemberOnlyRead: %t, cfg.MemberOnlyWrite: %t\n", 126 | cfg.Name, cfg.BlockToLive, cfg.MaximumPeerCount, cfg.RequiredPeerCount, cfg.MemberOnlyRead, cfg.MemberOnlyWrite) 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /cmd/commands/chaincode/instantiate.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package chaincode 8 | 9 | import ( 10 | "encoding/json" 11 | "errors" 12 | "fmt" 13 | 14 | "github.com/hyperledger/fabric-cli/cmd/commands/common" 15 | "github.com/hyperledger/fabric-sdk-go/pkg/client/resmgmt" 16 | "github.com/hyperledger/fabric-sdk-go/pkg/common/errors/retry" 17 | "github.com/spf13/cobra" 18 | 19 | "github.com/hyperledger/fabric-cli/pkg/environment" 20 | ) 21 | 22 | // NewChaincodeInstantiateCommand creates a new "fabric chaincode instantiate" command 23 | func NewChaincodeInstantiateCommand(settings *environment.Settings) *cobra.Command { 24 | c := InstantiateCommand{} 25 | 26 | c.Settings = settings 27 | 28 | cmd := &cobra.Command{ 29 | Use: "instantiate ", 30 | Short: "Instantiate a chaincode", 31 | Long: "Instantiate a chaincode with chaincode-name version path", 32 | Args: c.ParseArgs(), 33 | PreRunE: func(_ *cobra.Command, _ []string) error { 34 | if err := c.Complete(); err != nil { 35 | return err 36 | } 37 | 38 | if err := c.Validate(); err != nil { 39 | return err 40 | } 41 | 42 | return nil 43 | }, 44 | RunE: func(_ *cobra.Command, _ []string) error { 45 | return c.Run() 46 | }, 47 | } 48 | 49 | c.AddArg(&c.ChaincodeName) 50 | c.AddArg(&c.ChaincodeVersion) 51 | c.AddArg(&c.ChaincodePath) 52 | 53 | flags := cmd.Flags() 54 | flags.StringArrayVar(&c.ChaincodeArgs, "args", []string{}, "Set the constructor arguments") 55 | flags.StringVar(&c.ChaincodePolicy, "policy", "", "Set the endorsement policy") 56 | flags.StringVar(&c.ChaincodeCollectionsConfig, "collections-config", "", "Set the path to the collections config file") 57 | 58 | cmd.SetOutput(c.Settings.Streams.Out) 59 | 60 | return cmd 61 | } 62 | 63 | // InstantiateCommand implements the chaincode instantiate command 64 | type InstantiateCommand struct { 65 | BaseCommand 66 | 67 | ChaincodeName string 68 | ChaincodeVersion string 69 | ChaincodePath string 70 | 71 | ChaincodeArgs []string 72 | ChaincodePolicy string 73 | ChaincodeCollectionsConfig string 74 | } 75 | 76 | // Validate checks the required parameters for run 77 | func (c *InstantiateCommand) Validate() error { 78 | if len(c.ChaincodeName) == 0 { 79 | return errors.New("chaincode name not specified") 80 | } 81 | 82 | if len(c.ChaincodeVersion) == 0 { 83 | return errors.New("chaincode version not specified") 84 | } 85 | 86 | if len(c.ChaincodePath) == 0 { 87 | return errors.New("chaincode path not specified") 88 | } 89 | 90 | return nil 91 | } 92 | 93 | // Run executes the command 94 | func (c *InstantiateCommand) Run() error { 95 | context, err := c.Settings.Config.GetCurrentContext() 96 | if err != nil { 97 | return err 98 | } 99 | 100 | args, err := json.Marshal(c.ChaincodeArgs) 101 | if err != nil { 102 | return err 103 | } 104 | 105 | policy, err := common.GetChaincodePolicy(c.ChaincodePolicy) 106 | if err != nil { 107 | return err 108 | } 109 | 110 | collectionsConfig, err := common.GetCollectionConfigFromFile(c.ChaincodeCollectionsConfig) 111 | if err != nil { 112 | return err 113 | } 114 | 115 | req := resmgmt.InstantiateCCRequest{ 116 | Name: c.ChaincodeName, 117 | Path: c.ChaincodePath, 118 | Version: c.ChaincodeVersion, 119 | Args: [][]byte{[]byte("init"), args}, 120 | Policy: policy, 121 | CollConfig: collectionsConfig, 122 | } 123 | 124 | options := []resmgmt.RequestOption{ 125 | resmgmt.WithTargetEndpoints(context.Peers...), 126 | resmgmt.WithRetry(retry.DefaultResMgmtOpts), 127 | } 128 | 129 | if _, err := c.ResourceManagement.InstantiateCC(context.Channel, req, options...); err != nil { 130 | return err 131 | } 132 | 133 | fmt.Fprintf(c.Settings.Streams.Out, "successfully instantiated chaincode '%s'\n", c.ChaincodeName) 134 | 135 | return nil 136 | } 137 | -------------------------------------------------------------------------------- /cmd/commands/channel/list_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package channel_test 8 | 9 | import ( 10 | "bytes" 11 | "errors" 12 | "fmt" 13 | "os" 14 | 15 | pb "github.com/hyperledger/fabric-protos-go/peer" 16 | . "github.com/onsi/ginkgo" 17 | . "github.com/onsi/gomega" 18 | "github.com/spf13/cobra" 19 | 20 | "github.com/hyperledger/fabric-cli/cmd/commands/channel" 21 | "github.com/hyperledger/fabric-cli/pkg/environment" 22 | "github.com/hyperledger/fabric-cli/pkg/fabric/mocks" 23 | ) 24 | 25 | var _ = Describe("ChannelListCommand", func() { 26 | var ( 27 | cmd *cobra.Command 28 | settings *environment.Settings 29 | out *bytes.Buffer 30 | 31 | args []string 32 | ) 33 | 34 | BeforeEach(func() { 35 | out = new(bytes.Buffer) 36 | 37 | settings = &environment.Settings{ 38 | Home: environment.Home(os.TempDir()), 39 | Streams: environment.Streams{ 40 | Out: out, 41 | }, 42 | } 43 | 44 | args = os.Args 45 | }) 46 | 47 | JustBeforeEach(func() { 48 | cmd = channel.NewChannelListCommand(settings) 49 | }) 50 | 51 | AfterEach(func() { 52 | os.Args = args 53 | }) 54 | 55 | It("should create a channel list command", func() { 56 | Expect(cmd.Name()).To(Equal("list")) 57 | Expect(cmd.HasSubCommands()).To(BeFalse()) 58 | }) 59 | 60 | It("should provide a help prompt", func() { 61 | os.Args = append(os.Args, "--help") 62 | 63 | Expect(cmd.Execute()).Should(Succeed()) 64 | Expect(fmt.Sprint(out)).To(ContainSubstring("list")) 65 | }) 66 | }) 67 | 68 | var _ = Describe("ChannelListImplementation", func() { 69 | var ( 70 | impl *channel.ListCommand 71 | err error 72 | out *bytes.Buffer 73 | settings *environment.Settings 74 | factory *mocks.Factory 75 | client *mocks.ResourceManagement 76 | ) 77 | 78 | BeforeEach(func() { 79 | out = new(bytes.Buffer) 80 | 81 | settings = &environment.Settings{ 82 | Home: environment.Home(os.TempDir()), 83 | Streams: environment.Streams{ 84 | Out: out, 85 | }, 86 | } 87 | 88 | factory = &mocks.Factory{} 89 | client = &mocks.ResourceManagement{} 90 | 91 | impl = &channel.ListCommand{} 92 | impl.Settings = settings 93 | impl.Factory = factory 94 | }) 95 | 96 | It("should not be nil", func() { 97 | Expect(impl).ShouldNot(BeNil()) 98 | }) 99 | 100 | Describe("Run", func() { 101 | BeforeEach(func() { 102 | impl.ResourceManagement = client 103 | }) 104 | 105 | JustBeforeEach(func() { 106 | err = impl.Run() 107 | }) 108 | 109 | It("should fail without context", func() { 110 | Expect(err).NotTo(BeNil()) 111 | }) 112 | 113 | Context("when resmgmt client succeeds", func() { 114 | BeforeEach(func() { 115 | settings.Config = &environment.Config{ 116 | CurrentContext: "foo", 117 | Contexts: map[string]*environment.Context{ 118 | "foo": { 119 | Peers: []string{"peer0", "peer1"}, 120 | }, 121 | }, 122 | } 123 | client.QueryChannelsReturns(&pb.ChannelQueryResponse{ 124 | Channels: []*pb.ChannelInfo{ 125 | { 126 | ChannelId: "mychannel", 127 | }, 128 | }, 129 | }, nil) 130 | }) 131 | 132 | It("should succeed with channel list", func() { 133 | Expect(err).To(BeNil()) 134 | Expect(fmt.Sprint(out)).To(ContainSubstring("mychannel")) 135 | }) 136 | }) 137 | 138 | Context("when resmgmt client fails", func() { 139 | BeforeEach(func() { 140 | settings.Config = &environment.Config{ 141 | CurrentContext: "foo", 142 | Contexts: map[string]*environment.Context{ 143 | "foo": { 144 | Peers: []string{"peer0", "peer1"}, 145 | }, 146 | }, 147 | } 148 | client.QueryChannelsReturns(nil, errors.New("query error")) 149 | }) 150 | 151 | It("should fail to get channel list", func() { 152 | Expect(err).NotTo(BeNil()) 153 | Expect(err.Error()).To(ContainSubstring("query error")) 154 | }) 155 | }) 156 | }) 157 | }) 158 | -------------------------------------------------------------------------------- /cmd/commands/network/set_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package network_test 8 | 9 | import ( 10 | "bytes" 11 | "fmt" 12 | "io/ioutil" 13 | "os" 14 | 15 | . "github.com/onsi/ginkgo" 16 | . "github.com/onsi/gomega" 17 | "github.com/spf13/cobra" 18 | "gopkg.in/yaml.v2" 19 | 20 | "github.com/hyperledger/fabric-cli/cmd/commands/network" 21 | "github.com/hyperledger/fabric-cli/pkg/environment" 22 | ) 23 | 24 | var _ = Describe("SetNetworkCommand", func() { 25 | var ( 26 | cmd *cobra.Command 27 | settings *environment.Settings 28 | out *bytes.Buffer 29 | 30 | args []string 31 | ) 32 | 33 | BeforeEach(func() { 34 | out = new(bytes.Buffer) 35 | 36 | settings = &environment.Settings{ 37 | Home: environment.Home(os.TempDir()), 38 | Streams: environment.Streams{ 39 | Out: out, 40 | }, 41 | } 42 | 43 | args = os.Args 44 | }) 45 | 46 | JustBeforeEach(func() { 47 | cmd = network.NewNetworkSetCommand(settings) 48 | }) 49 | 50 | AfterEach(func() { 51 | os.Args = args 52 | }) 53 | 54 | It("should create a set network command", func() { 55 | Expect(cmd.Name()).To(Equal("set")) 56 | Expect(cmd.HasSubCommands()).To(BeFalse()) 57 | }) 58 | 59 | It("should provide a help prompt", func() { 60 | os.Args = append(os.Args, "--help") 61 | 62 | Expect(cmd.Execute()).Should(Succeed()) 63 | Expect(fmt.Sprint(out)).To(ContainSubstring("set")) 64 | }) 65 | }) 66 | 67 | var _ = Describe("SetNetworkImplementation", func() { 68 | var ( 69 | impl *network.SetCommand 70 | err error 71 | out *bytes.Buffer 72 | settings *environment.Settings 73 | ) 74 | 75 | BeforeEach(func() { 76 | out = new(bytes.Buffer) 77 | 78 | settings = environment.NewDefaultSettings() 79 | settings.Home = environment.Home(os.TempDir()) 80 | settings.Streams = environment.Streams{Out: out} 81 | 82 | impl = &network.SetCommand{} 83 | impl.Settings = settings 84 | }) 85 | 86 | It("should not be nil", func() { 87 | Expect(impl).ShouldNot(BeNil()) 88 | }) 89 | 90 | Describe("Validate", func() { 91 | JustBeforeEach(func() { 92 | err = impl.Validate() 93 | }) 94 | 95 | It("should fail without network name", func() { 96 | Expect(err).NotTo(BeNil()) 97 | }) 98 | 99 | Context("when network name is set", func() { 100 | BeforeEach(func() { 101 | impl.Name = "foo" 102 | }) 103 | 104 | It("should successfully validate", func() { 105 | Expect(err).NotTo(BeNil()) 106 | }) 107 | }) 108 | 109 | Context("when network name and path are set", func() { 110 | BeforeEach(func() { 111 | impl.Name = "foo" 112 | impl.Network = &environment.Network{ 113 | ConfigPath: "foo/bar", 114 | } 115 | }) 116 | 117 | It("should successfully validate", func() { 118 | Expect(err).To(BeNil()) 119 | }) 120 | }) 121 | }) 122 | 123 | Describe("Run", func() { 124 | JustBeforeEach(func() { 125 | err = impl.Run() 126 | }) 127 | 128 | JustAfterEach(func() { 129 | os.RemoveAll(impl.Settings.Home.Path(environment.DefaultConfigFilename)) 130 | }) 131 | 132 | Context("when a network exists", func() { 133 | BeforeEach(func() { 134 | impl.Name = "bar" 135 | }) 136 | 137 | It("should set the network", func() { 138 | Expect(err).To(BeNil()) 139 | Expect(fmt.Sprint(out)).To(ContainSubstring("successfully set network 'bar'")) 140 | }) 141 | }) 142 | 143 | Context("when network file is invalid", func() { 144 | BeforeEach(func() { 145 | data, _ := yaml.Marshal(struct { 146 | Networks string 147 | }{ 148 | Networks: "foo", 149 | }) 150 | 151 | os.MkdirAll(settings.Home.String(), 0777) 152 | 153 | ioutil.WriteFile( 154 | settings.Home.Path(environment.DefaultConfigFilename), 155 | data, 156 | 0777, 157 | ) 158 | }) 159 | 160 | It("should fail to unmarshal network file", func() { 161 | Expect(err).NotTo(BeNil()) 162 | }) 163 | }) 164 | }) 165 | }) 166 | -------------------------------------------------------------------------------- /cmd/commands/context/use_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package context_test 8 | 9 | import ( 10 | "bytes" 11 | "fmt" 12 | "io/ioutil" 13 | "os" 14 | 15 | . "github.com/onsi/ginkgo" 16 | . "github.com/onsi/gomega" 17 | "github.com/spf13/cobra" 18 | "gopkg.in/yaml.v2" 19 | 20 | "github.com/hyperledger/fabric-cli/cmd/commands/context" 21 | "github.com/hyperledger/fabric-cli/pkg/environment" 22 | ) 23 | 24 | var _ = Describe("UseContextCommand", func() { 25 | var ( 26 | cmd *cobra.Command 27 | settings *environment.Settings 28 | out *bytes.Buffer 29 | 30 | args []string 31 | ) 32 | 33 | BeforeEach(func() { 34 | out = new(bytes.Buffer) 35 | 36 | settings = &environment.Settings{ 37 | Home: environment.Home(os.TempDir()), 38 | Streams: environment.Streams{ 39 | Out: out, 40 | }, 41 | } 42 | 43 | args = os.Args 44 | }) 45 | 46 | JustBeforeEach(func() { 47 | cmd = context.NewContextUseCommand(settings) 48 | }) 49 | 50 | AfterEach(func() { 51 | os.Args = args 52 | }) 53 | 54 | It("should create a set context command", func() { 55 | Expect(cmd.Name()).To(Equal("use")) 56 | Expect(cmd.HasSubCommands()).To(BeFalse()) 57 | }) 58 | 59 | It("should provide a help prompt", func() { 60 | os.Args = append(os.Args, "--help") 61 | 62 | Expect(cmd.Execute()).Should(Succeed()) 63 | Expect(fmt.Sprint(out)).To(ContainSubstring("use")) 64 | }) 65 | }) 66 | 67 | var _ = Describe("SetContextImplementation", func() { 68 | var ( 69 | impl *context.UseCommand 70 | err error 71 | out *bytes.Buffer 72 | settings *environment.Settings 73 | ) 74 | 75 | BeforeEach(func() { 76 | out = new(bytes.Buffer) 77 | 78 | settings = environment.NewDefaultSettings() 79 | settings.Home = environment.Home(os.TempDir()) 80 | settings.Streams = environment.Streams{Out: out} 81 | 82 | impl = &context.UseCommand{} 83 | impl.Settings = settings 84 | }) 85 | 86 | It("should not be nil", func() { 87 | Expect(impl).ShouldNot(BeNil()) 88 | }) 89 | 90 | Describe("Validate", func() { 91 | JustBeforeEach(func() { 92 | err = impl.Validate() 93 | }) 94 | 95 | It("should fail without context name", func() { 96 | Expect(err).NotTo(BeNil()) 97 | }) 98 | 99 | Context("when context name is set but does not exist", func() { 100 | BeforeEach(func() { 101 | impl.Name = "foo" 102 | }) 103 | 104 | It("should fail without an existing context", func() { 105 | Expect(err).NotTo(BeNil()) 106 | }) 107 | }) 108 | 109 | Context("when context name is set", func() { 110 | BeforeEach(func() { 111 | settings.Config = &environment.Config{ 112 | Contexts: map[string]*environment.Context{ 113 | "foo": {}, 114 | }, 115 | } 116 | impl.Name = "foo" 117 | }) 118 | 119 | It("should successfully validate", func() { 120 | Expect(err).To(BeNil()) 121 | }) 122 | }) 123 | }) 124 | 125 | Describe("Run", func() { 126 | JustBeforeEach(func() { 127 | err = impl.Run() 128 | }) 129 | 130 | JustAfterEach(func() { 131 | os.RemoveAll(impl.Settings.Home.Path(environment.DefaultConfigFilename)) 132 | }) 133 | 134 | Context("when a context exists", func() { 135 | BeforeEach(func() { 136 | impl.Name = "bar" 137 | }) 138 | 139 | It("should set the context", func() { 140 | Expect(err).To(BeNil()) 141 | Expect(fmt.Sprint(out)).To(ContainSubstring("successfully set current context to 'bar'")) 142 | }) 143 | }) 144 | 145 | Context("when context file is invalid", func() { 146 | BeforeEach(func() { 147 | data, _ := yaml.Marshal(struct { 148 | Networks string 149 | }{ 150 | Networks: "foo", 151 | }) 152 | 153 | os.MkdirAll(settings.Home.String(), 0777) 154 | 155 | ioutil.WriteFile( 156 | settings.Home.Path(environment.DefaultConfigFilename), 157 | data, 158 | 0777, 159 | ) 160 | }) 161 | 162 | It("should fail to unmarshal context file", func() { 163 | Expect(err).NotTo(BeNil()) 164 | }) 165 | }) 166 | }) 167 | }) 168 | -------------------------------------------------------------------------------- /cmd/commands/chaincode/invoke_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package chaincode_test 8 | 9 | import ( 10 | "bytes" 11 | "errors" 12 | "fmt" 13 | "os" 14 | 15 | . "github.com/onsi/ginkgo" 16 | . "github.com/onsi/gomega" 17 | "github.com/spf13/cobra" 18 | 19 | "github.com/hyperledger/fabric-cli/cmd/commands/chaincode" 20 | "github.com/hyperledger/fabric-cli/pkg/environment" 21 | "github.com/hyperledger/fabric-cli/pkg/fabric/mocks" 22 | "github.com/hyperledger/fabric-sdk-go/pkg/client/channel" 23 | ) 24 | 25 | var _ = Describe("ChaincodeInvokeCommand", func() { 26 | var ( 27 | cmd *cobra.Command 28 | settings *environment.Settings 29 | out *bytes.Buffer 30 | 31 | args []string 32 | ) 33 | 34 | BeforeEach(func() { 35 | out = new(bytes.Buffer) 36 | 37 | settings = &environment.Settings{ 38 | Home: environment.Home(os.TempDir()), 39 | Streams: environment.Streams{ 40 | Out: out, 41 | }, 42 | } 43 | 44 | args = os.Args 45 | }) 46 | 47 | JustBeforeEach(func() { 48 | cmd = chaincode.NewChaincodeInvokeCommand(settings) 49 | }) 50 | 51 | AfterEach(func() { 52 | os.Args = args 53 | }) 54 | 55 | It("should create a chaincode invoke command", func() { 56 | Expect(cmd.Name()).To(Equal("invoke")) 57 | Expect(cmd.HasSubCommands()).To(BeFalse()) 58 | }) 59 | 60 | It("should provide a help prompt", func() { 61 | os.Args = append(os.Args, "--help") 62 | 63 | Expect(cmd.Execute()).Should(Succeed()) 64 | Expect(fmt.Sprint(out)).To(ContainSubstring("invoke ")) 65 | }) 66 | }) 67 | 68 | var _ = Describe("ChaincodeInvokeImplementation", func() { 69 | var ( 70 | impl *chaincode.InvokeCommand 71 | err error 72 | out *bytes.Buffer 73 | settings *environment.Settings 74 | factory *mocks.Factory 75 | client *mocks.Channel 76 | ) 77 | 78 | BeforeEach(func() { 79 | out = new(bytes.Buffer) 80 | 81 | settings = &environment.Settings{ 82 | Home: environment.Home(os.TempDir()), 83 | Streams: environment.Streams{ 84 | Out: out, 85 | }, 86 | } 87 | 88 | factory = &mocks.Factory{} 89 | client = &mocks.Channel{} 90 | 91 | impl = &chaincode.InvokeCommand{} 92 | impl.Settings = settings 93 | impl.Factory = factory 94 | }) 95 | 96 | It("should not be nil", func() { 97 | Expect(impl).ShouldNot(BeNil()) 98 | }) 99 | 100 | Describe("Validate", func() { 101 | JustBeforeEach(func() { 102 | err = impl.Validate() 103 | }) 104 | 105 | It("should fail when name is not set", func() { 106 | Expect(err).NotTo(BeNil()) 107 | Expect(err.Error()).To(Equal("chaincode name not specified")) 108 | }) 109 | 110 | Context("when chaincode name is set", func() { 111 | BeforeEach(func() { 112 | impl.ChaincodeName = "mycc" 113 | }) 114 | 115 | It("should succeed with chaincode name is set", func() { 116 | Expect(err).To(BeNil()) 117 | }) 118 | }) 119 | 120 | Context("when --is-init is set", func() { 121 | BeforeEach(func() { 122 | impl.ChaincodeName = "mycc" 123 | impl.IsInit = true 124 | }) 125 | 126 | It("should succeed with chaincode name is set", func() { 127 | Expect(err).To(BeNil()) 128 | }) 129 | }) 130 | }) 131 | 132 | Describe("Run", func() { 133 | BeforeEach(func() { 134 | impl.ChaincodeName = "mycc" 135 | 136 | impl.Channel = client 137 | }) 138 | 139 | JustBeforeEach(func() { 140 | 141 | err = impl.Run() 142 | 143 | }) 144 | 145 | Context("when channel client succeeds", func() { 146 | BeforeEach(func() { 147 | client.ExecuteReturns(channel.Response{}, nil) 148 | }) 149 | 150 | It("should successfully invoke chaincode", func() { 151 | Expect(err).To(BeNil()) 152 | }) 153 | }) 154 | 155 | Context("when channel client fails", func() { 156 | BeforeEach(func() { 157 | client.ExecuteReturns(channel.Response{}, errors.New("invoke error")) 158 | }) 159 | 160 | It("should fail to invoke chaincode invoke", func() { 161 | Expect(err).NotTo(BeNil()) 162 | Expect(err.Error()).To(ContainSubstring("invoke error")) 163 | }) 164 | }) 165 | }) 166 | }) 167 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [//]: # (SPDX-License-Identifier: CC-BY-4.0) 2 | 3 | **Note:** Issue tracking is handled in [Jira](https://jira.hyperledger.org/secure/Dashboard.jspa). 4 | If you find any issues or you want to add new features, please work with Jira. 5 | 6 | This repo is going to be used to implement [FAB-10734 Fabric CLI Redesign](https://jira.hyperledger.org/browse/FAB-10734). 7 | This is NOT the "official" Fabric CLI and there is not yet any commitment that it is going to be. 8 | 9 | # Hyperledger Fabric CLI 10 | 11 | The Hyperledger Fabric CLI is a tool used to interact with [Fabric networks](https://hyperledger-fabric.readthedocs.io/en/latest/). 12 | 13 | ## Installation 14 | 15 | 1. Clone this repo 16 | 2. Run `make` 17 | 3. Locate the binary in the `bin` directory 18 | 4. Add the binary to your PATH 19 | 5. Execute `fabric` for more information 20 | 21 | ## Getting Started 22 | 23 | 1. Add a Network with `fabric network set` 24 | 2. Add a Context with `fabric context set` 25 | 3. Use the new context with `fabric context use` 26 | 4. You're all set... Have fun! 27 | 28 | ## Network 29 | 30 | A network is a direct reference to a [Fabric-SDK-Go configuration](https://github.com/hyperledger/fabric-sdk-go/blob/main/pkg/core/config/testdata/config_test.yaml). This configuration contains all of the necessary details for interacting with a Fabric network at a global scope. 31 | 32 | ## Context 33 | 34 | A context defines the scope for interactions with the network. An example of this would be: As `Admin`, I want peer `peer0.org1.example.com` in organization `Org1` to join channel `mychannel`. In this example, the context would include the identity, peer, organization, and channel. 35 | 36 | ## Built-in Commands 37 | 38 | Built-in commands can be found in [/cmd/fabric/commands](/cmd/fabric/commands). These commands can serve as examples for building future commands like `plugin chaincode install ...`. 39 | 40 | ## Plugins 41 | 42 | Users can create and install custom commands to the Fabric CLI. The only requirement is that all external commands must provide a `plugin.yaml`. 43 | 44 | The YAML must specify: 45 | * Name - command name 46 | * Usage - usage syntax 47 | * Description - short description shown for help 48 | * Command - plugin execution 49 | 50 | Example plugins can be found in [pkg/plugin/testdata/plugins](pkg/plugin/testdata/plugins). 51 | 52 | For example,if you want to integrate `cryptogen` into `fabric` cmd: 53 | 54 | 1. Prepare the `plugin.yaml`: 55 | ```yaml 56 | name: cryptogen 57 | usage: cryptogen [] [ ...] 58 | description: Utility for generating Hyperledger Fabric key material 59 | command: cryptogen 60 | ``` 61 | 2. Exec the command: 62 | ```shell script 63 | #PATH is the location of `plugin.yaml`. 64 | $fabric plugin install $PATH 65 | ``` 66 | 3. To enjoy the command: 67 | ``` 68 | $fabric cryptogen ... 69 | ``` 70 | You can integrate some **Go Plugins** or **External Command** into **fabric** cmd, 71 | 72 | ## Documentation 73 | * [Design Document](https://docs.google.com/document/d/1zIQrS4TRgQEx1z9-wwtO8tYOGRyWdUoTdfk49GFx1wY/edit?usp=sharing) 74 | * [User Stories](https://docs.google.com/document/d/1dxOeM85PgrMNQUJMxB2kwhDthyWnzDxdPvjlwk7x4-w/edit?usp=sharing) 75 | 76 | ## Contributing 77 | 1. Fork this repo on github. 78 | 2. Clone the forked repo to your local enviroment (git clone https://github.com/you_username/fabric-cli.git && cd fabric-cli). 79 | 3. Create your feature branch (git checkout -b feature-branch). 80 | 4. Install `gobin` using `GO111MODULE=off go get -u github.com/myitcv/gobin` 81 | 5. Make changes and use `make test` to finish the test. 82 | 6. If test passed, add them (git add .). 83 | 7. Use `make lint` to verify your code. 84 | 8. If correct, commit your changes (git commit -s). 85 | 9. Push to github (git push origin feature-branch). 86 | 10. Create new Pull Request. 87 | 88 | ## License 89 | 90 | Hyperledger Project source code files are made available under the Apache 91 | License, Version 2.0 (Apache-2.0), located in the [LICENSE](LICENSE) file. 92 | Hyperledger Project documentation files are made available under the Creative 93 | Commons Attribution 4.0 International License (CC-BY-4.0), available at http://creativecommons.org/licenses/by/4.0/. 94 | -------------------------------------------------------------------------------- /cmd/commands/chaincode/events_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright State Street Corp. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | package chaincode_test 8 | 9 | import ( 10 | "bytes" 11 | "errors" 12 | "fmt" 13 | "os" 14 | 15 | . "github.com/onsi/ginkgo" 16 | . "github.com/onsi/gomega" 17 | "github.com/spf13/cobra" 18 | 19 | "github.com/hyperledger/fabric-cli/cmd/commands/chaincode" 20 | "github.com/hyperledger/fabric-cli/pkg/environment" 21 | "github.com/hyperledger/fabric-cli/pkg/fabric/mocks" 22 | "github.com/hyperledger/fabric-sdk-go/pkg/common/providers/fab" 23 | ) 24 | 25 | var _ = Describe("ChaincodeEventsCommand", func() { 26 | var ( 27 | cmd *cobra.Command 28 | settings *environment.Settings 29 | out *bytes.Buffer 30 | 31 | args []string 32 | ) 33 | 34 | BeforeEach(func() { 35 | out = new(bytes.Buffer) 36 | 37 | settings = &environment.Settings{ 38 | Home: environment.Home(os.TempDir()), 39 | Streams: environment.Streams{ 40 | Out: out, 41 | }, 42 | } 43 | 44 | args = os.Args 45 | }) 46 | 47 | JustBeforeEach(func() { 48 | cmd = chaincode.NewChaincodeEventsCommand(settings) 49 | }) 50 | 51 | AfterEach(func() { 52 | os.Args = args 53 | }) 54 | 55 | It("should create a chaincode events command", func() { 56 | Expect(cmd.Name()).To(Equal("events")) 57 | Expect(cmd.HasSubCommands()).To(BeFalse()) 58 | }) 59 | 60 | It("should provide a help prompt", func() { 61 | os.Args = append(os.Args, "--help") 62 | 63 | Expect(cmd.Execute()).Should(Succeed()) 64 | Expect(fmt.Sprint(out)).To(ContainSubstring("events ")) 65 | }) 66 | }) 67 | 68 | var _ = Describe("ChaincodeEventsImplementation", func() { 69 | var ( 70 | impl *chaincode.EventsCommand 71 | err error 72 | out *bytes.Buffer 73 | settings *environment.Settings 74 | factory *mocks.Factory 75 | client *mocks.Channel 76 | ) 77 | 78 | BeforeEach(func() { 79 | out = new(bytes.Buffer) 80 | 81 | settings = &environment.Settings{ 82 | Home: environment.Home(os.TempDir()), 83 | Streams: environment.Streams{ 84 | Out: out, 85 | }, 86 | } 87 | 88 | factory = &mocks.Factory{} 89 | client = &mocks.Channel{} 90 | 91 | impl = &chaincode.EventsCommand{} 92 | impl.Settings = settings 93 | impl.Factory = factory 94 | }) 95 | 96 | It("should not be nil", func() { 97 | Expect(impl).ShouldNot(BeNil()) 98 | }) 99 | 100 | Describe("Validate", func() { 101 | JustBeforeEach(func() { 102 | err = impl.Validate() 103 | }) 104 | 105 | It("should fail when name is not set", func() { 106 | Expect(err).NotTo(BeNil()) 107 | Expect(err.Error()).To(Equal("chaincode name not specified")) 108 | }) 109 | 110 | Context("when chaincode name is set", func() { 111 | BeforeEach(func() { 112 | impl.ChaincodeName = "mycc" 113 | }) 114 | 115 | It("should succeed with chaincode name is set", func() { 116 | Expect(err).To(BeNil()) 117 | }) 118 | }) 119 | }) 120 | 121 | Describe("Run", func() { 122 | var ( 123 | eventch chan *fab.CCEvent 124 | runDone chan struct{} 125 | ) 126 | 127 | BeforeEach(func() { 128 | impl.ChaincodeName = "mycc" 129 | 130 | impl.Channel = client 131 | 132 | eventch = make(chan *fab.CCEvent, 1) 133 | }) 134 | 135 | JustBeforeEach(func() { 136 | runDone = make(chan struct{}) 137 | go func() { 138 | err = impl.Run() 139 | close(runDone) 140 | }() 141 | }) 142 | 143 | AfterEach(func() { 144 | close(eventch) 145 | <-runDone 146 | }) 147 | 148 | Context("when channel client succeeds", func() { 149 | BeforeEach(func() { 150 | eventch <- &fab.CCEvent{ 151 | TxID: "1", 152 | } 153 | 154 | client.RegisterChaincodeEventReturns(struct{}{}, eventch, nil) 155 | }) 156 | 157 | It("should process chaincode events", func() { 158 | Expect(err).To(BeNil()) 159 | }) 160 | }) 161 | 162 | Context("when channel client fails", func() { 163 | BeforeEach(func() { 164 | client.RegisterChaincodeEventReturns(nil, nil, errors.New("events error")) 165 | }) 166 | 167 | It("should fail process chaincode events", func() { 168 | <-runDone // Wait for goroutine to terminate (we expect error) 169 | Expect(err).NotTo(BeNil()) 170 | Expect(err.Error()).To(ContainSubstring("events error")) 171 | }) 172 | }) 173 | }) 174 | }) 175 | --------------------------------------------------------------------------------