From daa1550168a7310426dc24d3b6e805766f470442 Mon Sep 17 00:00:00 2001 From: Jordan Ribbink Date: Mon, 3 Jul 2023 16:08:13 -0700 Subject: [PATCH] Generate json schema for flowkit (#1113) --- .github/workflows/ci.yml | 1 + Makefile | 8 + flowkit/cmd/flow-schema/flow-schema.go | 64 +++++ flowkit/config/json/account.go | 26 +++ flowkit/config/json/contract.go | 17 ++ flowkit/config/json/deploy.go | 17 ++ flowkit/config/json/network.go | 20 ++ flowkit/config/json/schema.go | 44 ++++ flowkit/go.mod | 2 + flowkit/go.sum | 5 + flowkit/schema.json | 311 +++++++++++++++++++++++++ go.mod | 2 + go.sum | 5 + 13 files changed, 522 insertions(+) create mode 100644 flowkit/cmd/flow-schema/flow-schema.go create mode 100644 flowkit/config/json/schema.go create mode 100644 flowkit/schema.json diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2c3e66b99..f814f5906 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,6 +29,7 @@ jobs: make ci make check-tidy make check-headers + make check-schema - name: Upload coverage report uses: codecov/codecov-action@v1 with: diff --git a/Makefile b/Makefile index bdcbdd323..bd131835f 100644 --- a/Makefile +++ b/Makefile @@ -97,11 +97,19 @@ fix-lint: check-headers: @./check-headers.sh +.PHONY: check-schema +check-schema: + cd flowkit && go run ./cmd/flow-schema/flow-schema.go --verify=true ./schema.json + .PHONY: check-tidy check-tidy: go mod tidy cd flowkit; go mod tidy +.PHONY: generate-schema +generate-schema: + cd flowkit && go run ./cmd/flow-schema/flow-schema.go ./schema.json + .PHONY: generate generate: install-tools cd flowkit; \ diff --git a/flowkit/cmd/flow-schema/flow-schema.go b/flowkit/cmd/flow-schema/flow-schema.go new file mode 100644 index 000000000..422bf44ff --- /dev/null +++ b/flowkit/cmd/flow-schema/flow-schema.go @@ -0,0 +1,64 @@ +/* + * Flow CLI + * + * Copyright 2019 Dapper Labs, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package main + +import ( + "encoding/json" + "flag" + "fmt" + "os" + + configJson "github.com/onflow/flow-cli/flowkit/config/json" +) + +func main() { + var verify bool + flag.BoolVar(&verify, "verify", false, "Verify the schema") + + flag.Parse() + path := flag.Arg(0) + + if path == "" { + fmt.Println("Path is required") + os.Exit(1) + } + + schema := configJson.GenerateSchema() + json, err := json.MarshalIndent(schema, "", " ") + + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + if verify { + fileContents, err := os.ReadFile(path) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + if string(fileContents) != string(json) { + fmt.Println("Schema is out of date - have you run `make generate-schema`?") + os.Exit(1) + } + } else { + os.WriteFile(path, json, 0644) + } +} diff --git a/flowkit/config/json/account.go b/flowkit/config/json/account.go index 372aed761..6a6b0d178 100644 --- a/flowkit/config/json/account.go +++ b/flowkit/config/json/account.go @@ -25,6 +25,7 @@ import ( "regexp" "strings" + "github.com/invopop/jsonschema" "github.com/onflow/flow-go-sdk" "github.com/onflow/flow-go-sdk/crypto" "golang.org/x/exp/slices" @@ -456,3 +457,28 @@ func (j account) MarshalJSON() ([]byte, error) { return json.Marshal(j.Advanced) } + +func (a account) JSONSchema() *jsonschema.Schema { + return &jsonschema.Schema{ + OneOf: []*jsonschema.Schema{ + { + Ref: "#/$defs/simpleAccount", + }, + { + Ref: "#/$defs/advancedAccount", + }, + { + Ref: "#/$defs/simpleAccountPre022", + }, + { + Ref: "#/$defs/advanceAccountPre022", + }, + }, + Definitions: map[string]*jsonschema.Schema{ + "simpleAccount": jsonschema.Reflect(simpleAccount{}), + "advancedAccount": jsonschema.Reflect(advancedAccount{}), + "simpleAccountPre022": jsonschema.Reflect(simpleAccountPre022{}), + "advanceAccountPre022": jsonschema.Reflect(advanceAccountPre022{}), + }, + } +} diff --git a/flowkit/config/json/contract.go b/flowkit/config/json/contract.go index f8b7b0603..39a400f63 100644 --- a/flowkit/config/json/contract.go +++ b/flowkit/config/json/contract.go @@ -22,6 +22,7 @@ import ( "encoding/json" "fmt" + "github.com/invopop/jsonschema" "github.com/onflow/flow-go-sdk" "github.com/onflow/flow-cli/flowkit/config" @@ -131,3 +132,19 @@ func (j jsonContract) MarshalJSON() ([]byte, error) { return json.Marshal(j.Advanced) } } + +func (j jsonContract) JSONSchema() *jsonschema.Schema { + return &jsonschema.Schema{ + OneOf: []*jsonschema.Schema{ + { + Type: "string", + }, + { + Ref: "#/$defs/jsonContractAdvanced", + }, + }, + Definitions: map[string]*jsonschema.Schema{ + "jsonContractAdvanced": jsonschema.Reflect(jsonContractAdvanced{}), + }, + } +} diff --git a/flowkit/config/json/deploy.go b/flowkit/config/json/deploy.go index 3b74fd1d8..9e21270f3 100644 --- a/flowkit/config/json/deploy.go +++ b/flowkit/config/json/deploy.go @@ -22,6 +22,7 @@ import ( "encoding/json" "fmt" + "github.com/invopop/jsonschema" "github.com/onflow/cadence" jsoncdc "github.com/onflow/cadence/encoding/json" @@ -179,3 +180,19 @@ func (d deployment) MarshalJSON() ([]byte, error) { return json.Marshal(d.advanced) } } + +func (j deployment) JSONSchema() *jsonschema.Schema { + return &jsonschema.Schema{ + OneOf: []*jsonschema.Schema{ + { + Type: "string", + }, + { + Ref: "#/$defs/contractDeployment", + }, + }, + Definitions: map[string]*jsonschema.Schema{ + "contractDeployment": jsonschema.Reflect(contractDeployment{}), + }, + } +} diff --git a/flowkit/config/json/network.go b/flowkit/config/json/network.go index 1996020a2..1c2fa1c93 100644 --- a/flowkit/config/json/network.go +++ b/flowkit/config/json/network.go @@ -24,6 +24,7 @@ import ( "fmt" "strings" + "github.com/invopop/jsonschema" "github.com/onflow/flow-go-sdk/crypto" "github.com/onflow/flow-cli/flowkit/config" @@ -147,3 +148,22 @@ func validateECDSAP256Pub(key string) error { return nil } + +func (j jsonNetwork) JSONSchema() *jsonschema.Schema { + return &jsonschema.Schema{ + OneOf: []*jsonschema.Schema{ + { + Ref: "#/$defs/simpleNetwork", + }, + { + Ref: "#/$defs/advancedNetwork", + }, + }, + Definitions: map[string]*jsonschema.Schema{ + "simpleNetwork": { + Type: "string", + }, + "advancedNetwork": jsonschema.Reflect(advancedNetwork{}), + }, + } +} \ No newline at end of file diff --git a/flowkit/config/json/schema.go b/flowkit/config/json/schema.go new file mode 100644 index 000000000..8445f654a --- /dev/null +++ b/flowkit/config/json/schema.go @@ -0,0 +1,44 @@ +package json + +/* + * Flow CLI + * + * Copyright 2019 Dapper Labs, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import ( + "github.com/invopop/jsonschema" +) + +func GenerateSchema() *jsonschema.Schema { + schema := jsonschema.Reflect(jsonConfig{}) + + // Recursively move all definitions to the root of the schema + // This is necessary because the jsonschema library does not support + // definitions in nested schemas and is a workaround + var moveDefinitions func(*jsonschema.Schema) + moveDefinitions = func (s *jsonschema.Schema) { + for k, v := range s.Definitions { + schema.Definitions[k] = v + moveDefinitions(v) + } + if (s != schema) { + s.Definitions = nil + } + } + moveDefinitions(schema) + + return schema +} diff --git a/flowkit/go.mod b/flowkit/go.mod index 0c41c955d..1f9f3252a 100644 --- a/flowkit/go.mod +++ b/flowkit/go.mod @@ -5,6 +5,7 @@ go 1.18 require ( github.com/ethereum/go-ethereum v1.10.22 github.com/gosuri/uilive v0.0.4 + github.com/invopop/jsonschema v0.7.0 github.com/lmars/go-slip10 v0.0.0-20190606092855-400ba44fee12 github.com/onflow/cadence v0.39.12 github.com/onflow/flow-emulator v0.51.1 @@ -68,6 +69,7 @@ require ( github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d // indirect github.com/hashicorp/hcl v1.0.0 // indirect + github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/ipfs/bbloom v0.0.4 // indirect github.com/ipfs/go-block-format v0.0.3 // indirect diff --git a/flowkit/go.sum b/flowkit/go.sum index 2a4e2d843..e03adfaad 100644 --- a/flowkit/go.sum +++ b/flowkit/go.sum @@ -360,12 +360,16 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huin/goupnp v0.0.0-20161224104101-679507af18f3/go.mod h1:MZ2ZmwcBpvOoJ22IJsc7va19ZwoheaBk43rKg12SKag= +github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0 h1:i462o439ZjprVSFSZLZxcsoAe592sZB1rci2Z8j4wdk= +github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0/go.mod h1:N0Wam8K1arqPXNWjMo21EXnBPOPp36vB07FNRdD2geA= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/influxdata/influxdb v1.2.3-0.20180221223340-01288bdb0883/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY= +github.com/invopop/jsonschema v0.7.0 h1:2vgQcBz1n256N+FpX3Jq7Y17AjYt46Ig3zIWyy770So= +github.com/invopop/jsonschema v0.7.0/go.mod h1:O9uiLokuu0+MGFlyiaqtWxwqJm41/+8Nj0lD7A36YH0= github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs= github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0= github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY= @@ -690,6 +694,7 @@ github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpE github.com/stretchr/testify v0.0.0-20170601210322-f6abca593680/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.3.1-0.20190311161405-34c6fa2dc709/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= diff --git a/flowkit/schema.json b/flowkit/schema.json new file mode 100644 index 000000000..082b31434 --- /dev/null +++ b/flowkit/schema.json @@ -0,0 +1,311 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://github.com/onflow/flow-cli/flowkit/config/json/json-config", + "$ref": "#/$defs/jsonConfig", + "$defs": { + "account": { + "oneOf": [ + { + "$ref": "#/$defs/simpleAccount" + }, + { + "$ref": "#/$defs/advancedAccount" + }, + { + "$ref": "#/$defs/simpleAccountPre022" + }, + { + "$ref": "#/$defs/advanceAccountPre022" + } + ] + }, + "advanceAccountPre022": { + "properties": { + "address": { + "type": "string" + }, + "keys": { + "items": { + "$ref": "#/$defs/advanceKey" + }, + "type": "array" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "address", + "keys" + ] + }, + "advanceKey": { + "properties": { + "type": { + "type": "string" + }, + "index": { + "type": "integer" + }, + "signatureAlgorithm": { + "type": "string" + }, + "hashAlgorithm": { + "type": "string" + }, + "privateKey": { + "type": "string" + }, + "mnemonic": { + "type": "string" + }, + "derivationPath": { + "type": "string" + }, + "resourceID": { + "type": "string" + }, + "location": { + "type": "string" + }, + "context": { + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": "object" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "type" + ] + }, + "advancedAccount": { + "properties": { + "address": { + "type": "string" + }, + "key": { + "$ref": "#/$defs/advanceKey" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "address", + "key" + ] + }, + "advancedNetwork": { + "properties": { + "host": { + "type": "string" + }, + "key": { + "type": "string" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "host", + "key" + ] + }, + "contractDeployment": { + "properties": { + "name": { + "type": "string" + }, + "args": { + "items": { + "type": "object" + }, + "type": "array" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "name", + "args" + ] + }, + "deployment": { + "oneOf": [ + { + "type": "string" + }, + { + "$ref": "#/$defs/contractDeployment" + } + ] + }, + "jsonAccounts": { + "patternProperties": { + ".*": { + "$ref": "#/$defs/account" + } + }, + "type": "object" + }, + "jsonConfig": { + "properties": { + "emulators": { + "$ref": "#/$defs/jsonEmulators" + }, + "contracts": { + "$ref": "#/$defs/jsonContracts" + }, + "networks": { + "$ref": "#/$defs/jsonNetworks" + }, + "accounts": { + "$ref": "#/$defs/jsonAccounts" + }, + "deployments": { + "$ref": "#/$defs/jsonDeployments" + } + }, + "additionalProperties": false, + "type": "object" + }, + "jsonContract": { + "oneOf": [ + { + "type": "string" + }, + { + "$ref": "#/$defs/jsonContractAdvanced" + } + ] + }, + "jsonContractAdvanced": { + "properties": { + "source": { + "type": "string" + }, + "aliases": { + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": "object" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "source", + "aliases" + ] + }, + "jsonContracts": { + "patternProperties": { + ".*": { + "$ref": "#/$defs/jsonContract" + } + }, + "type": "object" + }, + "jsonDeployment": { + "patternProperties": { + ".*": { + "items": { + "$ref": "#/$defs/deployment" + }, + "type": "array" + } + }, + "type": "object" + }, + "jsonDeployments": { + "patternProperties": { + ".*": { + "$ref": "#/$defs/jsonDeployment" + } + }, + "type": "object" + }, + "jsonEmulator": { + "properties": { + "port": { + "type": "integer" + }, + "serviceAccount": { + "type": "string" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "port", + "serviceAccount" + ] + }, + "jsonEmulators": { + "patternProperties": { + ".*": { + "$ref": "#/$defs/jsonEmulator" + } + }, + "type": "object" + }, + "jsonNetwork": { + "oneOf": [ + { + "$ref": "#/$defs/simpleNetwork" + }, + { + "$ref": "#/$defs/advancedNetwork" + } + ] + }, + "jsonNetworks": { + "patternProperties": { + ".*": { + "$ref": "#/$defs/jsonNetwork" + } + }, + "type": "object" + }, + "simpleAccount": { + "properties": { + "address": { + "type": "string" + }, + "key": { + "type": "string" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "address", + "key" + ] + }, + "simpleAccountPre022": { + "properties": { + "address": { + "type": "string" + }, + "keys": { + "type": "string" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "address", + "keys" + ] + }, + "simpleNetwork": { + "type": "string" + } + } +} \ No newline at end of file diff --git a/go.mod b/go.mod index 95eb18ae2..93fbab74d 100644 --- a/go.mod +++ b/go.mod @@ -96,9 +96,11 @@ require ( github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d // indirect github.com/hashicorp/hcl v1.0.0 // indirect + github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0 // indirect github.com/imdario/mergo v0.3.13 // indirect github.com/improbable-eng/grpc-web v0.15.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/invopop/jsonschema v0.7.0 // indirect github.com/ipfs/bbloom v0.0.4 // indirect github.com/ipfs/go-block-format v0.0.3 // indirect github.com/ipfs/go-cid v0.3.2 // indirect diff --git a/go.sum b/go.sum index a06e73645..5dbc5b0b8 100644 --- a/go.sum +++ b/go.sum @@ -523,6 +523,8 @@ github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/J github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/huin/goupnp v0.0.0-20161224104101-679507af18f3/go.mod h1:MZ2ZmwcBpvOoJ22IJsc7va19ZwoheaBk43rKg12SKag= +github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0 h1:i462o439ZjprVSFSZLZxcsoAe592sZB1rci2Z8j4wdk= +github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0/go.mod h1:N0Wam8K1arqPXNWjMo21EXnBPOPp36vB07FNRdD2geA= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= @@ -534,6 +536,8 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/influxdata/influxdb v1.2.3-0.20180221223340-01288bdb0883/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY= github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/invopop/jsonschema v0.7.0 h1:2vgQcBz1n256N+FpX3Jq7Y17AjYt46Ig3zIWyy770So= +github.com/invopop/jsonschema v0.7.0/go.mod h1:O9uiLokuu0+MGFlyiaqtWxwqJm41/+8Nj0lD7A36YH0= github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs= github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0= github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY= @@ -1011,6 +1015,7 @@ github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpE github.com/stretchr/testify v0.0.0-20170601210322-f6abca593680/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.3.1-0.20190311161405-34c6fa2dc709/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=