diff --git a/.github/workflows/e2e_test_check.yml b/.github/workflows/e2e_test_check.yml deleted file mode 100644 index 9b2f9b1..0000000 --- a/.github/workflows/e2e_test_check.yml +++ /dev/null @@ -1,73 +0,0 @@ -name: e2e test -on: - # Trigger the workflow on push or pull request, - # but only for the master branch - push: - paths-ignore: - - '**.md' - - '**.png' - pull_request: - paths-ignore: - - '**.md' - - '**.png' -jobs: - job_1: - name: Build goc binary - runs-on: ubuntu-latest - steps: - - name: Install Go - uses: actions/setup-go@v2 - with: - go-version: 1.14.x - - name: Checkout code - uses: actions/checkout@v2 - - name: Go build - run: | - go build - - name: Use goc to build self - run: | - ./goc build --output ./gocc --debug - - name: Upload goc binary - uses: actions/upload-artifact@v2 - with: - name: goc - path: goc - - name: Upload covered self goc binary - uses: actions/upload-artifact@v2 - with: - name: gocc - path: gocc - - job_2: - name: E2E test - needs: job_1 - strategy: - matrix: - go-version: [1.11.x, 1.12.x, 1.13.x, 1.14.x, 1.15.x, 1.16.x] - runs-on: ubuntu-latest - steps: - - name: Install Go - uses: actions/setup-go@v2 - with: - go-version: ${{ matrix.go-version }} - - name: Checkout code - uses: actions/checkout@v2 - - name: Download built binary - uses: actions/download-artifact@v2 - with: - path: /home/runner/tools - - name: Install bats-core - run: | - git clone https://github.com/bats-core/bats-core.git - cd bats-core - sudo ./install.sh /usr/local - - name: Do test - env: - GOVERSION: ${{ matrix.go-version }} - run: | - chmod +x /home/runner/tools/goc/goc - export PATH=/home/runner/tools/goc:$PATH - chmod +x /home/runner/tools/gocc/gocc - export PATH=/home/runner/tools/gocc:$PATH - cd tests - ./run-ci-actions.sh \ No newline at end of file diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml deleted file mode 100644 index ec58f5c..0000000 --- a/.github/workflows/golangci-lint.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: golangci-lint -on: - pull_request: -jobs: - golangci: - name: lint - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: golangci-lint - uses: golangci/golangci-lint-action@v2 - with: - # Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version. - version: v1.29 - - # Optional: working directory, useful for monorepos - # working-directory: somedir - - # Optional: golangci-lint command line arguments. - # args: --issues-exit-code=0 - - # Optional: show only new issues if it's a pull request. The default value is `false`. - only-new-issues: true \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index eb559a7..0000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,55 +0,0 @@ -on: - release: - types: [published,edited] -name: Build Release -jobs: - release-linux-amd64: - name: release linux/amd64 - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@master - - name: Install Go - uses: actions/setup-go@v2 - with: - go-version: 1.14.x - - name: compile and release - run: | - ./ci-build.sh - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GOARCH: amd64 - GOOS: linux - - release-linux-386: - name: release linux/386 - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@master - - name: Install Go - uses: actions/setup-go@v2 - with: - go-version: 1.14.x - - name: compile and release - run: | - ./ci-build.sh - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GOARCH: "386" - GOOS: linux - - release-darwin-amd64: - name: release darwin/amd64 - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@master - - name: Install Go - uses: actions/setup-go@v2 - with: - go-version: 1.14.x - - name: compile and release - run: | - ./ci-build.sh - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GOARCH: amd64 - GOOS: darwin \ No newline at end of file diff --git a/.github/workflows/style_check.yml b/.github/workflows/style_check.yml deleted file mode 100644 index e96c9fa..0000000 --- a/.github/workflows/style_check.yml +++ /dev/null @@ -1,39 +0,0 @@ -name: style-check -on: - # Trigger the workflow on push or pull request, - # but only for the master branch - push: - paths-ignore: - - '**.md' - - '**.png' - pull_request: - paths-ignore: - - '**.md' - - '**.png' -jobs: - run: - name: vet and gofmt - strategy: - matrix: - go-version: [1.13.x, 1.14.x, 1.15.x] - runs-on: ubuntu-latest - steps: - - name: Install Go - uses: actions/setup-go@v2 - with: - go-version: ${{ matrix.go-version }} - # This step checks out a copy of your repository. - - name: Checkout code - uses: actions/checkout@v2 - - name: Go vet check - run: | - go vet ./... - - name: Gofmt check - run: | - diff=`find . -name "*.go" | xargs gofmt -s -d` - if [[ -n "${diff}" ]]; then - echo "Gofmt check failed :" - echo "${diff}" - echo "Please run this command to fix: [find . -name "*.go" | xargs gofmt -s -w]" - exit 1 - fi diff --git a/.github/workflows/ut_check.yml b/.github/workflows/ut_check.yml deleted file mode 100644 index 533fd29..0000000 --- a/.github/workflows/ut_check.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: ut-check -on: - # Trigger the workflow on push or pull request, - # but only for the master branch - push: - paths-ignore: - - '**.md' - - '**.png' - pull_request: - paths-ignore: - - '**.md' - - '**.png' -jobs: - run: - name: go test - strategy: - matrix: - go-version: [1.13.x, 1.14.x, 1.15.x, 1.16.x] - runs-on: ubuntu-latest - steps: - - name: Install Go - uses: actions/setup-go@v2 - with: - go-version: ${{ matrix.go-version }} - # This step checks out a copy of your repository. - - name: Checkout code - uses: actions/checkout@v2 - - name: Go test - env: - GOVERSION: ${{ matrix.go-version }} - run: | - export DEFAULT_EXCEPT_PKGS=e2e - go test -p 1 -coverprofile=coverage.txt $(go list ./... | grep -v -E $DEFAULT_EXCEPT_PKGS) - bash <(curl -s https://codecov.io/bash) -F unittest-$GOVERSION diff --git a/.gitignore b/.gitignore index e3dd50f..e69de29 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +0,0 @@ -# ignore log file -**/goc.log - -# binary -goc - -# the temp file to save service address -_svrs_address.txt - -# other -*.iml -.DS_Store -.idea diff --git a/Makefile b/Makefile deleted file mode 100644 index 88ffe4b..0000000 --- a/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -DEFAULT_EXCEPT_PKGS := e2e - -all: - go install ./... - -test: - go test -cover -p 1 `go list ./... | grep -v -E ${DEFAULT_EXCEPT_PKGS}` - -fmt: - go fmt ./... - -govet-check: - go vet ./... - -clean: - find tests/ -type f -name '*.bak' -delete - find tests/ -type f -name '*.cov' -delete - find tests/ -type f -name 'simple-project' -delete - find tests/ -type f -name '*_profile_listen_addr' -delete - find tests/ -type f -name 'simple_gopath_project' -delete - \ No newline at end of file diff --git a/README.md b/README.md deleted file mode 100644 index 97e5ff1..0000000 --- a/README.md +++ /dev/null @@ -1,88 +0,0 @@ -# goc -[![Go Report Card](https://goreportcard.com/badge/github.com/qiniu/goc)](https://goreportcard.com/report/github.com/qiniu/goc) -![](https://github.com/qiniu/goc/workflows/ut-check/badge.svg) -![](https://github.com/qiniu/goc/workflows/style-check/badge.svg) -![](https://github.com/qiniu/goc/workflows/e2e%20test/badge.svg) -![Build Release](https://github.com/qiniu/goc/workflows/Build%20Release/badge.svg) -[![codecov](https://codecov.io/gh/qiniu/goc/branch/master/graph/badge.svg)](https://codecov.io/gh/qiniu/goc) -[![GoDoc](https://godoc.org/github.com/qiniu/goc?status.svg)](https://godoc.org/github.com/qiniu/goc) - -[中文页](README_zh.md) | - -goc is a comprehensive coverage testing system for The Go Programming Language, especially for some complex scenarios, like system testing code coverage collection and -accurate testing. - -Enjoy, Have Fun! -![Demo](docs/images/intro.gif) - -## Installation - -Download the latest version from [Github Releases](https://github.com/qiniu/goc/releases) page. - -Goc supports both `GOPATH` project and `Go Modules` project with **Go 1.11+**. However, for developing goc, you need to install **Go 1.13+**. - -## Examples -You can use goc tool in many scenarios. - -### Code Coverage Collection for Your Golang System Tests -Goc can collect code coverages at runtime for your long-run golang applications. To do that, normally just need three steps: - -1. use `goc server` to start a service registry center: - ``` - ➜ simple-go-server git:(master) ✗ goc server - ``` -2. use `goc build` to build the target service, and run the generated binary. Here let's take the [simple-go-server](https://github.com/CarlJi/simple-go-server) project as example: - ``` - ➜ simple-go-server git:(master) ✗ goc build . - ... // omit logs - ➜ simple-go-server git:(master) ✗ ./simple-go-server - ``` -3. use `goc profile` to get the code coverage profile of the started simple server above: - ``` - ➜ simple-go-server git:(master) ✗ goc profile - mode: atomic - enricofoltran/simple-go-server/main.go:30.13,48.33 13 1 - enricofoltran/simple-go-server/main.go:48.33,50.3 1 0 - enricofoltran/simple-go-server/main.go:52.2,65.12 5 1 - enricofoltran/simple-go-server/main.go:65.12,74.46 7 1 - enricofoltran/simple-go-server/main.go:74.46,76.4 1 0 - ... - ``` - -### Show Code Coverage Change at Runtime in Vscode - -We provide a vscode extension - [Goc Coverage](https://marketplace.visualstudio.com/items?itemName=lyyyuna.goc) which can show highlighted covered source code at runtime. - -![Extension](docs/images/goc-vscode.gif) - -## Tips - -1. To understand the execution details of goc tool, you can use the `--debug` flag. Also we appreciate if you can provide such logs when submitting a bug to us. - -2. By default, the covered service will listen a random port in order to communicate with the goc server. This may not be suitable in [docker](https://docs.docker.com/engine/reference/commandline/run/#publish-or-expose-port--p---expose) or [kubernetes](https://kubernetes.io/docs/concepts/services-networking/service/#defining-a-service) environment since the port must be exposed explicitly in order to be accessible by others in such environment. For this kind of scenario, you can use `--agentport` flag to specify a fixed port when calling `goc build` or `goc install`. - -3. To use a remote goc server, you can use `--center` flag to compile the target service with `goc build` or `goc install` command. - -4. The coverage data is stored on each covered service side, so if one service needs to restart during test, this service's coverage data will be lost. For this case, you can use following steps to handle: - - 1. Before the service restarts, collect coverage with `goc profile -o a.cov` - 2. After service restarted and test finished, collect coverage again with `goc profile -o b.cov` - 3. Merge two coverage profiles together: `goc merge a.cov b.cov -o merge.cov` - -## RoadMap -- [x] Support code coverage collection for system testing. -- [x] Support code coverage counters clear for the services under test at runtime. -- [x] Support develop mode towards accurate testing. -- [x] Support code coverage diff based on Pull Request. -- [ ] Optimize the performance costed by code coverage counters. - -## Contributing -We welcome all kinds of contribution, including bug reports, feature requests, documentation improvements, UI refinements, etc. - -Thanks to all [contributors](https://github.com/qiniu/goc/graphs/contributors)!! - -## License -Goc is released under the Apache 2.0 license. See [LICENSE.txt](https://github.com/qiniu/goc/blob/master/LICENSE) - -## Join goc WeChat Group -![WeChat](docs/images/wechat.png) \ No newline at end of file diff --git a/README_zh.md b/README_zh.md deleted file mode 100644 index c866e47..0000000 --- a/README_zh.md +++ /dev/null @@ -1,97 +0,0 @@ -# goc - -[![Go Report Card](https://goreportcard.com/badge/github.com/qiniu/goc)](https://goreportcard.com/report/github.com/qiniu/goc) -![](https://github.com/qiniu/goc/workflows/ut-check/badge.svg) -![](https://github.com/qiniu/goc/workflows/style-check/badge.svg) -![](https://github.com/qiniu/goc/workflows/e2e%20test/badge.svg) -![Build Release](https://github.com/qiniu/goc/workflows/Build%20Release/badge.svg) -[![codecov](https://codecov.io/gh/qiniu/goc/branch/master/graph/badge.svg)](https://codecov.io/gh/qiniu/goc) -[![GoDoc](https://godoc.org/github.com/qiniu/goc?status.svg)](https://godoc.org/github.com/qiniu/goc) - -goc 是专为 Go 语言打造的一个综合覆盖率收集系统,尤其适合复杂的测试场景,比如系统测试时的代码覆盖率收集以及精准测试。 - -希望你们喜欢~ - -![Demo](docs/images/intro.gif) - -## 安装 - -最新版本在该页面下载 [Github Releases](https://github.com/qiniu/goc/releases)。 - -goc 同时支持 `GOPATH` 工程和 `Go Modules` 工程,且 Go 版本要求 **Go 1.11+**。如果想参与 goc 的开发,你必须使用 **Go 1.13+**。 - -## 例子 - -goc 有多种使用场景。 - -### 在系统测试中收集代码覆盖率 - -goc 可以实时收集长时运行的 golang 服务覆盖率。收集步骤只需要下面三步: - -1. 运行 `goc server` 命令启动一个服务注册中心: - ``` - ➜ simple-go-server git:(master) ✗ goc server - ``` -2. 运行 `goc build` 命令编译目标服务,然后启动插过桩的二进制。下面以 [simple-go-server](https://github.com/CarlJi/simple-go-server) 工程为例: - ``` - ➜ simple-go-server git:(master) ✗ goc build . - ... // omit logs - ➜ simple-go-server git:(master) ✗ ./simple-go-server - ``` -3. 运行 `goc profile` 命令收集刚启动的 simple server 的代码覆盖率: - ``` - ➜ simple-go-server git:(master) ✗ goc profile - mode: atomic - enricofoltran/simple-go-server/main.go:30.13,48.33 13 1 - enricofoltran/simple-go-server/main.go:48.33,50.3 1 0 - enricofoltran/simple-go-server/main.go:52.2,65.12 5 1 - enricofoltran/simple-go-server/main.go:65.12,74.46 7 1 - enricofoltran/simple-go-server/main.go:74.46,76.4 1 0 - ... - ``` - -### Vscode 中实时展示覆盖率动态变化 - -我们提供了一个 vscode 插件 - [Goc Coverage](https://marketplace.visualstudio.com/items?itemName=lyyyuna.goc)。该插件可以在运行时高亮覆盖过的代码。 - -![Extension](docs/images/goc-vscode.gif) - -## Tips - -1. goc 命令加上 `--debug` 会打印详细的日志。我们建议在提交 bug 时附上详细日志。 - -2. 默认情况下,插桩过的服务会监听在一个随机的端口,注册中心会通过这个端口与服务通信。然而,对于 [docker](https://docs.docker.com/engine/reference/commandline/run/#publish-or-expose-port--p---expose) 和 [kubernetes](https://kubernetes.io/docs/concepts/services-networking/service/#defining-a-service) 容器化运行环境,对外暴露端口需在容器启动前指定。针对这种场景,你可以在 `goc build` 或 `goc install` 时使用 `--agentport` 来指定插桩过的服务监听在固定的端口。 - -3. 如果注册中心不在本机,你可以在 `goc build` 或 `goc install` 编译目标服务时使用 `--center` 指定远端注册中心地址。 - -4. 目前覆盖率数据存储在插过桩的服务测,如果某个服务中途需要重启,那么其覆盖率数据在重启后会丢失。针对这个场景,你可以通过以下步骤解决: - - 1. 在重启前,通过 `goc profile -o a.cov` 命令收集一次覆盖率 - 2. 测试结束后,通过 `goc profile -o b.cov` 命令再收集一次覆盖率 - 3. 通过 `goc merge a.cov b.cov -o merge.cov` 命令合并两次的覆盖率 - -## Blogs - -- [Go语言系统测试覆盖率收集利器 goc](https://mp.weixin.qq.com/s/DzXEXwepaouSuD2dPVloOg) -- [聊聊Go代码覆盖率技术与最佳实践](https://mp.weixin.qq.com/s/SQHzsfV5T_B8fmt9NzGA7Q) - -## RoadMap - -- [x] 支持系统测试中收集代码覆盖率 -- [x] 支持运行时对被测服务代码覆盖率计数器清零 -- [x] 支持精准测试 -- [x] 支持基于 Pull Request 的增量代码覆盖率报告 -- [ ] 优化插桩计数器带来的性能损耗 - -## Contributing - -我们欢迎各种形式的贡献,包括提交 bug、提新需求、优化文档和改进 UI 等等。 - -感谢所有的[贡献者](https://github.com/qiniu/goc/graphs/contributors)!! - -## License - -Goc is released under the Apache 2.0 license. See [LICENSE.txt](https://github.com/qiniu/goc/blob/master/LICENSE) - -## 加入微信群聊 -![WeChat](docs/images/wechat.png) \ No newline at end of file diff --git a/ci-build.sh b/ci-build.sh deleted file mode 100755 index d888a5d..0000000 --- a/ci-build.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/bash - -set -eux - -EVENT_DATA=$(cat $GITHUB_EVENT_PATH) -echo $EVENT_DATA | jq . -UPLOAD_URL=$(echo $EVENT_DATA | jq -r .release.upload_url) -UPLOAD_URL=${UPLOAD_URL/\{?name,label\}/} -RELEASE_VERSION=$(echo $EVENT_DATA | jq -r .release.tag_name) -PROJECT_NAME=$(basename $GITHUB_REPOSITORY) -NAME="${NAME:-${PROJECT_NAME}-${RELEASE_VERSION}}-${GOOS}-${GOARCH}" - -CGO_ENABLED=0 go build -ldflags "-X 'github.com/qiniu/goc/cmd.version=${RELEASE_VERSION}'" . - -ARCHIVE=tmp.tar.gz -FILE_LIST=goc -tar cvfz $ARCHIVE ${FILE_LIST} - -CHECKSUM=$(md5sum ${ARCHIVE} | cut -d ' ' -f 1) - -curl \ - -X POST \ - --data-binary @${ARCHIVE} \ - -H 'Content-Type: application/octet-stream' \ - -H "Authorization: Bearer ${GITHUB_TOKEN}" \ - "${UPLOAD_URL}?name=${NAME}.${ARCHIVE/tmp./}" - -curl \ - -X POST \ - --data $CHECKSUM \ - -H 'Content-Type: text/plain' \ - -H "Authorization: Bearer ${GITHUB_TOKEN}" \ - "${UPLOAD_URL}?name=${NAME}_md5.txt" \ No newline at end of file diff --git a/cmd/build.go b/cmd/build.go deleted file mode 100644 index eb4a54b..0000000 --- a/cmd/build.go +++ /dev/null @@ -1,96 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.com) - - 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 cmd - -import ( - "os" - - log "github.com/sirupsen/logrus" - - "github.com/qiniu/goc/pkg/build" - "github.com/qiniu/goc/pkg/cover" - "github.com/spf13/cobra" -) - -var buildCmd = &cobra.Command{ - Use: "build", - Short: "Do cover for all go files and execute go build command", - Long: ` -Build command will copy the project code and its necessary dependencies to a temporary directory, then do cover for the target, binaries will be generated to their original place. -`, - Example: ` -# Build the current binary with cover variables injected. The binary will be generated in the current folder. -goc build . - -# Build the current binary with cover variables injected, and set the registry center to http://127.0.0.1:7777. -goc build --center=http://127.0.0.1:7777 - -# Build the current binary with cover variables injected, and redirect output to /to/this/path. -goc build --output /to/this/path - -# Build the current binary with cover variables injected, and set necessary build flags: -ldflags "-extldflags -static" -tags="embed kodo". -goc build --buildflags="-ldflags '-extldflags -static' -tags='embed kodo'" -`, - Run: func(cmd *cobra.Command, args []string) { - wd, err := os.Getwd() - if err != nil { - log.Fatalf("Fail to build: %v", err) - } - runBuild(args, wd) - }, -} - -var buildOutput string - -func init() { - addBuildFlags(buildCmd.Flags()) - buildCmd.Flags().StringVarP(&buildOutput, "output", "o", "", "it forces build to write the resulting executable to the named output file") - rootCmd.AddCommand(buildCmd) -} - -func runBuild(args []string, wd string) { - gocBuild, err := build.NewBuild(buildFlags, args, wd, buildOutput) - if err != nil { - log.Fatalf("Fail to build: %v", err) - } - // remove temporary directory if needed - defer gocBuild.Clean() - // doCover with original buildFlags, with new GOPATH( tmp:original ) - // in the tmp directory - ci := &cover.CoverInfo{ - Args: buildFlags, - GoPath: gocBuild.NewGOPATH, - Target: gocBuild.TmpDir, - Mode: coverMode.String(), - AgentPort: agentPort.String(), - Center: center, - IsMod: gocBuild.IsMod, - ModRootPath: gocBuild.ModRootPath, - OneMainPackage: true, // it is a go build - GlobalCoverVarImportPath: gocBuild.GlobalCoverVarImportPath, - } - err = cover.Execute(ci) - if err != nil { - log.Fatalf("Fail to build: %v", err) - } - // do install in the temporary directory - err = gocBuild.Build() - if err != nil { - log.Fatalf("Fail to build: %v", err) - } - return -} diff --git a/cmd/build_test.go b/cmd/build_test.go deleted file mode 100644 index f3677b3..0000000 --- a/cmd/build_test.go +++ /dev/null @@ -1,110 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.com) - - 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 cmd - -import ( - "os" - "os/exec" - "path/filepath" - "strings" - "testing" - "time" - - "github.com/stretchr/testify/assert" -) - -var baseDir string - -func init() { - baseDir, _ = os.Getwd() -} - -func TestGeneratedBinary(t *testing.T) { - startTime := time.Now() - - workingDir := filepath.Join(baseDir, "../tests/samples/simple_project") - gopath := "" - - os.Setenv("GOPATH", gopath) - os.Setenv("GO111MODULE", "on") - - buildFlags, buildOutput = "", "" - args := []string{"."} - runBuild(args, workingDir) - - obj := filepath.Join(workingDir, "simple-project") - fInfo, err := os.Lstat(obj) - assert.Equal(t, err, nil, "the binary should be generated.") - assert.Equal(t, startTime.Before(fInfo.ModTime()), true, obj+"new binary should be generated, not the old one") - - cmd := exec.Command("go", "tool", "objdump", "simple-project") - cmd.Dir = workingDir - out, _ := cmd.CombinedOutput() - cnt := strings.Count(string(out), "main.registerSelf") - assert.Equal(t, cnt > 0, true, "main.registerSelf function should be in the binary") - - cnt = strings.Count(string(out), "GoCover") - assert.Equal(t, cnt > 0, true, "GoCover variable should be in the binary") -} - -func TestBuildBinaryName(t *testing.T) { - startTime := time.Now() - - workingDir := filepath.Join(baseDir, "../tests/samples/simple_project2") - gopath := "" - - os.Setenv("GOPATH", gopath) - os.Setenv("GO111MODULE", "on") - - buildFlags, buildOutput = "", "" - args := []string{"."} - runBuild(args, workingDir) - - obj := filepath.Join(workingDir, "simple-project") - fInfo, err := os.Lstat(obj) - assert.Equal(t, err, nil, "the binary should be generated.") - assert.Equal(t, startTime.Before(fInfo.ModTime()), true, obj+"new binary should be generated, not the old one") - - cmd := exec.Command("go", "tool", "objdump", "simple-project") - cmd.Dir = workingDir - out, _ := cmd.CombinedOutput() - cnt := strings.Count(string(out), "main.registerSelf") - assert.Equal(t, cnt > 0, true, "main.registerSelf function should be in the binary") - - cnt = strings.Count(string(out), "GoCover") - assert.Equal(t, cnt > 0, true, "GoCover variable should be in the binary") -} - -// test if goc can get variables in internal package -func TestBuildBinaryForInternalPackage(t *testing.T) { - startTime := time.Now() - - workingDir := filepath.Join(baseDir, "../tests/samples/simple_project_with_internal") - gopath := "" - - os.Setenv("GOPATH", gopath) - os.Setenv("GO111MODULE", "on") - - buildFlags, buildOutput = "", "" - args := []string{"."} - runBuild(args, workingDir) - - obj := filepath.Join(workingDir, "simple-project") - fInfo, err := os.Lstat(obj) - assert.Equal(t, err, nil, "the binary should be generated.") - assert.Equal(t, startTime.Before(fInfo.ModTime()), true, obj+"new binary should be generated, not the old one") -} diff --git a/cmd/clear.go b/cmd/clear.go deleted file mode 100644 index 2e5aea2..0000000 --- a/cmd/clear.go +++ /dev/null @@ -1,58 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.com) - - 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 cmd - -import ( - "fmt" - "os" - - log "github.com/sirupsen/logrus" - - "github.com/qiniu/goc/pkg/cover" - "github.com/spf13/cobra" -) - -var clearCmd = &cobra.Command{ - Use: "clear", - Short: "Clear code coverage counters of all the registered services", - Long: `Clear code coverage counters for the services under test at runtime.`, - Example: ` -# Clear coverage counter from default register center http://127.0.0.1:7777. -goc clear - -# Clear coverage counter from specified register center. -goc clear --center=http://192.168.1.1:8080 -`, - Run: func(cmd *cobra.Command, args []string) { - p := cover.ProfileParam{ - Service: svrList, - Address: addrList, - } - res, err := cover.NewWorker(center).Clear(p) - if err != nil { - log.Fatalf("call host %v failed, err: %v, response: %v", center, err, string(res)) - } - fmt.Fprint(os.Stdout, string(res)) - }, -} - -func init() { - addBasicFlags(clearCmd.Flags()) - clearCmd.Flags().StringSliceVarP(&svrList, "service", "", nil, "service name to clear profile, see 'goc list' for all services.") - clearCmd.Flags().StringSliceVarP(&addrList, "address", "", nil, "address to clear profile, see 'goc list' for all addresses.") - rootCmd.AddCommand(clearCmd) -} diff --git a/cmd/commonflags.go b/cmd/commonflags.go deleted file mode 100644 index 9440276..0000000 --- a/cmd/commonflags.go +++ /dev/null @@ -1,126 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.com) - - 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 cmd - -import ( - "fmt" - "net" - - "github.com/spf13/pflag" - "github.com/spf13/viper" -) - -var ( - target string - center string - agentPort AgentPort - debugGoc bool - debugInCISyncFile string - buildFlags string - - goRunExecFlag string - goRunArguments string -) - -var coverMode = CoverMode{ - mode: "count", -} - -// addBasicFlags adds a -func addBasicFlags(cmdset *pflag.FlagSet) { - cmdset.StringVar(¢er, "center", "http://127.0.0.1:7777", "cover profile host center") - // bind to viper - viper.BindPFlags(cmdset) -} - -func addCommonFlags(cmdset *pflag.FlagSet) { - addBasicFlags(cmdset) - cmdset.Var(&coverMode, "mode", "coverage mode: set, count, atomic") - cmdset.Var(&agentPort, "agentport", "a fixed port such as :8100 for registered service communicate with goc server. if not provided, using a random one") - cmdset.StringVar(&buildFlags, "buildflags", "", "specify the build flags") - // bind to viper - viper.BindPFlags(cmdset) -} - -func addBuildFlags(cmdset *pflag.FlagSet) { - addCommonFlags(cmdset) - // bind to viper - viper.BindPFlags(cmdset) -} - -func addRunFlags(cmdset *pflag.FlagSet) { - addBuildFlags(cmdset) - cmdset.StringVar(&goRunExecFlag, "exec", "", "same as -exec flag in 'go run' command") - cmdset.StringVar(&goRunArguments, "arguments", "", "same as 'arguments' in 'go run' command") - // bind to viper - viper.BindPFlags(cmdset) -} - -// CoverMode represents the covermode when doing cover for source code -type CoverMode struct { - mode string -} - -func (m *CoverMode) String() string { - return m.mode -} - -// Set sets the value to the CoverMode struct, use 'count' as default if v is empty -func (m *CoverMode) Set(v string) error { - if v == "" { - m.mode = "count" - return nil - } - if v != "set" && v != "count" && v != "atomic" { - return fmt.Errorf("unknown mode") - } - m.mode = v - return nil -} - -// Type returns the type of CoverMode -func (m *CoverMode) Type() string { - return "string" -} - -// AgentPort is the struct to do agentPort check -type AgentPort struct { - port string -} - -func (agent *AgentPort) String() string { - return agent.port -} - -// Set sets the value to the AgentPort struct -func (agent *AgentPort) Set(v string) error { - if v == "" { - agent.port = "" - return nil - } - _, _, err := net.SplitHostPort(v) - if err != nil { - return err - } - agent.port = v - return nil -} - -// Type returns the type of AgentPort -func (agent *AgentPort) Type() string { - return "string" -} diff --git a/cmd/commonflags_test.go b/cmd/commonflags_test.go deleted file mode 100644 index ea5f4f0..0000000 --- a/cmd/commonflags_test.go +++ /dev/null @@ -1,110 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.com) - - 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 cmd - -import ( - "errors" - "fmt" - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestCoverModeFlag(t *testing.T) { - var tcs = []struct { - value string - expectedValue interface{} - err interface{} - }{ - { - value: "", - expectedValue: "count", - err: nil, - }, - { - value: "set", - expectedValue: "set", - err: nil, - }, - { - value: "count", - expectedValue: "count", - err: nil, - }, - { - value: "atomic", - expectedValue: "atomic", - err: nil, - }, - { - value: "xxxxx", - expectedValue: "", - err: errors.New("unknown mode"), - }, - { - value: "123333", - expectedValue: "", - err: errors.New("unknown mode"), - }, - } - for _, tc := range tcs { - mode := &CoverMode{} - err := mode.Set(tc.value) - actual := mode.String() - assert.Equal(t, actual, tc.expectedValue, fmt.Sprintf("check mode flag value failed, expected %s, got %s", tc.expectedValue, actual)) - assert.Equal(t, err, tc.err, fmt.Sprintf("check mode flag error, expected %s, got %s", tc.err, err)) - } -} - -func TestAgentPortFlag(t *testing.T) { - var tcs = []struct { - value string - expectedValue interface{} - isErr bool - }{ - { - value: "", - expectedValue: "", - isErr: false, - }, - { - value: ":8888", - expectedValue: ":8888", - isErr: false, - }, - { - value: "8888", - expectedValue: "", - isErr: true, - }, - { - value: "::8888", - expectedValue: "", - isErr: true, - }, - } - for _, tc := range tcs { - agent := &AgentPort{} - err := agent.Set(tc.value) - if tc.isErr { - assert.NotEqual(t, nil, err, fmt.Sprintf("check agentport flag error, expected %v, got %v", nil, err)) - } else { - actual := agent.String() - assert.Equal(t, tc.expectedValue, actual, fmt.Sprintf("check agentport flag value failed, expected %s, got %s", tc.expectedValue, actual)) - } - } -} diff --git a/cmd/cover.go b/cmd/cover.go deleted file mode 100644 index dec4e5b..0000000 --- a/cmd/cover.go +++ /dev/null @@ -1,61 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.com) - - 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 cmd - -import ( - "github.com/qiniu/goc/pkg/cover" - "github.com/spf13/cobra" - "github.com/spf13/viper" -) - -var coverCmd = &cobra.Command{ - Use: "cover", - Short: "Do cover for the target source", - Long: `Do cover for the target source. You can select different cover mode (set, count, atomic), default: count`, - Example: ` -# Do cover for the current path, default center: http://127.0.0.1:7777, default cover mode: count. -goc cover - -# Do cover for the current path, default cover mode: count. -goc cover --center=http://127.0.0.1:7777 - -# Do cover for the target path, cover mode: atomic. -goc cover --center=http://127.0.0.1:7777 --target=/path/to/target --mode=atomic -`, - Hidden: true, - Run: func(cmd *cobra.Command, args []string) { - var buildFlags string - buildFlags = viper.GetString("buildflags") - - ci := &cover.CoverInfo{ - Args: buildFlags, - GoPath: "", - Target: target, - Mode: coverMode.String(), - AgentPort: agentPort.String(), - Center: center, - OneMainPackage: false, - } - _ = cover.Execute(ci) - }, -} - -func init() { - coverCmd.Flags().StringVar(&target, "target", ".", "target folder to cover") - addCommonFlags(coverCmd.Flags()) - rootCmd.AddCommand(coverCmd) -} diff --git a/cmd/diff.go b/cmd/diff.go deleted file mode 100644 index 6ad26c9..0000000 --- a/cmd/diff.go +++ /dev/null @@ -1,209 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.com) - - 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 cmd - -import ( - "encoding/json" - "io/ioutil" - "os" - - "github.com/olekukonko/tablewriter" - "github.com/sirupsen/logrus" - "github.com/spf13/cobra" - - "github.com/qiniu/goc/pkg/cover" - "github.com/qiniu/goc/pkg/github" - "github.com/qiniu/goc/pkg/prow" - "github.com/qiniu/goc/pkg/qiniu" -) - -var diffCmd = &cobra.Command{ - Use: "diff", - Short: "Do coverage profile diff analysis, it can also work with prow and post comments to github pull request if needed", - Example: ` # Diff two local coverage profile and display - goc diff --new-profile= --base-profile= - - # Diff local coverage profile with the remote one in prow job using default qiniu-credential - goc diff --prow-postsubmit-job= --new-profile= - - # Calculate and display full diff coverage between new-profile and base-profile, not concerned github changed files - goc diff --prow-postsubmit-job= --new-profile= --full-diff=true - - # Diff local coverage profile with the remote one in prow job - goc diff --prow-postsubmit-job= --prow-remote-profile-name= - --qiniu-credential= --new-profile= - - # Diff coverage profile with the remote one in prow job, and post comments to github PR - goc diff --prow-postsubmit-job= --prow-profile= - --github-token= --github-user= --github-comment-prefix= - --qiniu-credential= --coverage-threshold-percentage= --new-profile= - `, - Run: func(cmd *cobra.Command, args []string) { - if baseProfile != "" { - doDiffForLocalProfiles(cmd, args) - } else if prowPostSubmitJob != "" { - doDiffUnderProw(cmd, args) - } else { - logrus.Fatalf("either base-profile or prow-postsubmit-job must be provided") - } - }, -} - -var ( - newProfile string - baseProfile string - coverageThreshold int - - prowPostSubmitJob string - prowProfile string - - githubToken string - githubUser string - githubCommentPrefix string - - qiniuCredential string - - robotName string - fullDiff bool -) - -func init() { - diffCmd.Flags().StringVarP(&newProfile, "new-profile", "n", "", "local profile which works as the target to analysis") - diffCmd.MarkFlagRequired("new-profile") - diffCmd.Flags().StringVarP(&baseProfile, "base-profile", "b", "", "another local profile which works as baseline to compare with the target") - diffCmd.Flags().IntVarP(&coverageThreshold, "coverage-threshold-percentage", "", 0, "coverage threshold percentage") - diffCmd.Flags().StringVarP(&prowPostSubmitJob, "prow-postsubmit-job", "", "", "prow postsubmit job which used to find the base profile") - diffCmd.Flags().StringVarP(&prowProfile, "prow-remote-profile-name", "", "filtered.cov", "the name of profile in prow postsubmit job, which used as the base profile to compare") - diffCmd.Flags().StringVarP(&githubToken, "github-token", "", "/etc/github/oauth", "path to token to access github repo") - diffCmd.Flags().StringVarP(&githubUser, "github-user", "", "", "github user name when comments in github") - diffCmd.Flags().StringVarP(&githubCommentPrefix, "github-comment-prefix", "", "", "specific comment flag you provided") - diffCmd.Flags().StringVarP(&qiniuCredential, "qiniu-credential", "", "/etc/qiniuconfig/qiniu.json", "path to credential file to access qiniu cloud") - diffCmd.Flags().StringVarP(&robotName, "robot-name", "", "qiniu-bot", "github user name for coverage robot") - diffCmd.Flags().BoolVarP(&fullDiff, "full-diff", "", false, "when set true,calculate and display full diff coverage between new-profile and base-profile") - - rootCmd.AddCommand(diffCmd) -} - -//goc diff --new-profile=./new.cov --base-profile=./base.cov -//+------------------------------------------------------+---------------+--------------+--------+ -//| File | Base Coverage | New Coverage | Delta | -//+------------------------------------------------------+---------------+--------------+--------+ -//| qiniu.com/kodo/bd/pfd/pfdstg/cursor/mgr.go | 53.5% | 50.5% | -3.0% | -//| qiniu.com/kodo/bd/pfd/pfdstg/svr/getstripe.go | 0.5% | 0.0% | -0.5% | -//| Total | 35.7% | 35.7% | -0.0% | -//+------------------------------------------------------+---------------+--------------+--------+ -func doDiffForLocalProfiles(cmd *cobra.Command, args []string) { - localP, err := cover.ReadFileToCoverList(newProfile) - if err != nil { - logrus.Fatal(err) - } - - baseP, err := cover.ReadFileToCoverList(baseProfile) - if err != nil { - logrus.Fatal(err) - } - - //calculate diff file cov and display - rows := cover.GetDeltaCov(localP, baseP) - rows.Sort() - table := tablewriter.NewWriter(os.Stdout) - table.SetHeader([]string{"File", "Base Coverage", "New Coverage", "Delta"}) - table.SetAutoFormatHeaders(false) - table.SetColumnAlignment([]int{tablewriter.ALIGN_LEFT, tablewriter.ALIGN_CENTER, tablewriter.ALIGN_CENTER, tablewriter.ALIGN_CENTER}) - for _, row := range rows { - table.Append([]string{row.FileName, row.BasePer, row.NewPer, row.DeltaPer}) - } - totalDelta := cover.PercentStr(cover.TotalDelta(localP, baseP)) - table.Append([]string{"Total", baseP.TotalPercentage(), localP.TotalPercentage(), totalDelta}) - table.Render() -} - -func doDiffUnderProw(cmd *cobra.Command, args []string) { - var ( - prNumStr = os.Getenv("PULL_NUMBER") - pullSha = os.Getenv("PULL_PULL_SHA") - baseSha = os.Getenv("PULL_BASE_SHA") - repoOwner = os.Getenv("REPO_OWNER") - repoName = os.Getenv("REPO_NAME") - jobType = os.Getenv("JOB_TYPE") - jobName = os.Getenv("JOB_NAME") - buildStr = os.Getenv("BUILD_NUMBER") - artifacts = os.Getenv("ARTIFACTS") - ) - logrus.Printf("Running coverage for PR = %s; PR commit SHA = %s;base SHA = %s", prNumStr, pullSha, baseSha) - - switch jobType { - case "periodic": - logrus.Printf("job type %s, do nothing", jobType) - case "postsubmit": - logrus.Printf("job type %s, do nothing", jobType) - case "presubmit": - if githubToken == "" { - logrus.Fatalf("github token not provided") - } - prClient := github.NewPrClient(githubToken, repoOwner, repoName, prNumStr, robotName, githubCommentPrefix) - - if qiniuCredential == "" { - logrus.Fatalf("qiniu credential not provided") - } - var qc qiniu.Client - var conf qiniu.Config - files, err := ioutil.ReadFile(*&qiniuCredential) - if err != nil { - logrus.WithError(err).Fatal("Error reading qiniu config file") - } - if err := json.Unmarshal(files, &conf); err != nil { - logrus.Fatal("Error unmarshal qiniu config file") - } - if conf.Bucket == "" { - logrus.Fatal("no qiniu bucket provided") - } - if conf.AccessKey == "" || conf.SecretKey == "" { - logrus.Fatal("either qiniu access key or secret key was not provided") - } - if conf.Domain == "" { - logrus.Fatal("no qiniu bucket domain was provided") - } - qc = qiniu.NewClient(&conf) - - localArtifacts := qiniu.ProfileArtifacts{ - Directory: artifacts, - ProfileName: newProfile, - ChangedProfileName: qiniu.ChangedProfileName, - } - - job := prow.Job{ - JobName: jobName, - BuildId: buildStr, - Org: repoOwner, - RepoName: repoName, - PRNumStr: prNumStr, - PostSubmitJob: prowPostSubmitJob, - LocalProfilePath: newProfile, - PostSubmitCoverProfile: prowProfile, - QiniuClient: qc, - LocalArtifacts: &localArtifacts, - GithubComment: prClient, - FullDiff: fullDiff, - } - if err := job.RunPresubmit(); err != nil { - logrus.Fatalf("run presubmit job failed, err: %v", err) - } - default: - logrus.Printf("Unknown job type: %s, do nothing.", jobType) - } -} diff --git a/cmd/diff_test.go b/cmd/diff_test.go deleted file mode 100644 index d8a6426..0000000 --- a/cmd/diff_test.go +++ /dev/null @@ -1,106 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.com) - - 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 cmd - -import ( - "bytes" - "fmt" - "io" - "io/ioutil" - "os" - "testing" - - "github.com/sirupsen/logrus" - "github.com/spf13/cobra" - "github.com/stretchr/testify/assert" -) - -type diffFunc func(cmd *cobra.Command, args []string) - -func captureStdout(f diffFunc, cmd *cobra.Command, args []string) string { - r, w, err := os.Pipe() - if err != nil { - logrus.WithError(err).Fatal("os pipe fail") - } - stdout := os.Stdout - os.Stdout = w - defer func() { - os.Stdout = stdout - }() - - f(cmd, args) - w.Close() - - var buf bytes.Buffer - io.Copy(&buf, r) - - return buf.String() -} - -func TestDoDiffForLocalProfiles(t *testing.T) { - items := []struct { - newCovFile string - newProfile string - baseCovFile string - baseProfile string - expectOutput string - }{ - { - newCovFile: "new.cov", - baseCovFile: "base.cov", - newProfile: "mode: atomic\n" + - "qiniu.com/kodo/apiserver/server/main.go:32.49,33.13 1 30\n" + - "qiniu.com/kodo/apiserver/server/main.go:42.49,43.13 1 1\n", - baseProfile: "mode: atomic\n" + - "qiniu.com/kodo/apiserver/server/main.go:32.49,33.13 1 30\n" + - "qiniu.com/kodo/apiserver/server/main.go:42.49,43.13 1 0\n", - expectOutput: `+-----------------------------------------+---------------+--------------+-------+ -| File | Base Coverage | New Coverage | Delta | -+-----------------------------------------+---------------+--------------+-------+ -| qiniu.com/kodo/apiserver/server/main.go | 50.0% | 100.0% | 50.0% | -| Total | 50.0% | 100.0% | 50.0% | -+-----------------------------------------+---------------+--------------+-------+ -`, - }, - } - - for _, tc := range items { - err := ioutil.WriteFile(tc.newCovFile, []byte(tc.newProfile), 0644) - if err != nil { - logrus.WithError(err).Fatalf("write file %s failed", tc.newCovFile) - } - err = ioutil.WriteFile(tc.baseCovFile, []byte(tc.baseProfile), 0644) - if err != nil { - logrus.WithError(err).Fatalf("write file %s failed", tc.baseCovFile) - } - defer func() { - os.Remove(tc.newCovFile) - os.Remove(tc.baseCovFile) - }() - - pwd, err := os.Getwd() - if err != nil { - logrus.WithError(err).Fatalf("get pwd failed") - } - - diffCmd.Flags().Set("new-profile", fmt.Sprintf("%s/%s", pwd, tc.newCovFile)) - diffCmd.Flags().Set("base-profile", fmt.Sprintf("%s/%s", pwd, tc.baseCovFile)) - out := captureStdout(doDiffForLocalProfiles, diffCmd, nil) - assert.Equal(t, out, tc.expectOutput) - } - -} diff --git a/cmd/init.go b/cmd/init.go deleted file mode 100644 index c489f80..0000000 --- a/cmd/init.go +++ /dev/null @@ -1,39 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.com) - - 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 cmd - -import ( - log "github.com/sirupsen/logrus" - - "github.com/qiniu/goc/pkg/cover" - "github.com/spf13/cobra" -) - -var initCmd = &cobra.Command{ - Use: "init", - Short: "Clear the register information in order to start a new round of tests", - Run: func(cmd *cobra.Command, args []string) { - if res, err := cover.NewWorker(center).InitSystem(); err != nil { - log.Fatalf("call host %v failed, err: %v, response: %v", center, err, string(res)) - } - }, -} - -func init() { - addBasicFlags(initCmd.Flags()) - rootCmd.AddCommand(initCmd) -} diff --git a/cmd/install.go b/cmd/install.go deleted file mode 100644 index 5d84569..0000000 --- a/cmd/install.go +++ /dev/null @@ -1,89 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.com) - - 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 cmd - -import ( - "os" - - "github.com/qiniu/goc/pkg/build" - "github.com/qiniu/goc/pkg/cover" - log "github.com/sirupsen/logrus" - "github.com/spf13/cobra" -) - -var installCmd = &cobra.Command{ - Use: "install", - Short: "Do cover for all go files and execute go install command", - Long: ` -Install command will copy the project code and its necessary dependencies to a temporary directory, then do cover for the target, binaries will be generated to their original place. -`, - Example: ` -# Install all binaries with cover variables injected. The binary will be installed in $GOPATH/bin or $HOME/go/bin if directory existed. -goc install ./... - -# Install the current binary with cover variables injected, and set the registry center to http://127.0.0.1:7777. -goc install --center=http://127.0.0.1:7777 - -# Install the current binary with cover variables injected, and set necessary build flags: -ldflags "-extldflags -static" -tags="embed kodo". -goc build --buildflags="-ldflags '-extldflags -static' -tags='embed kodo'" -`, - Run: func(cmd *cobra.Command, args []string) { - wd, err := os.Getwd() - if err != nil { - log.Fatalf("Fail to build: %v", err) - } - runInstall(args, wd) - }, -} - -func init() { - addBuildFlags(installCmd.Flags()) - rootCmd.AddCommand(installCmd) -} - -func runInstall(args []string, wd string) { - gocBuild, err := build.NewInstall(buildFlags, args, wd) - if err != nil { - log.Fatalf("Fail to install: %v", err) - } - // remove temporary directory if needed - defer gocBuild.Clean() - // doCover with original buildFlags, with new GOPATH( tmp:original ) - // in the tmp directory - ci := &cover.CoverInfo{ - Args: buildFlags, - GoPath: gocBuild.NewGOPATH, - Target: gocBuild.TmpDir, - Mode: coverMode.String(), - AgentPort: agentPort.String(), - Center: center, - IsMod: gocBuild.IsMod, - ModRootPath: gocBuild.ModRootPath, - OneMainPackage: false, - GlobalCoverVarImportPath: gocBuild.GlobalCoverVarImportPath, - } - err = cover.Execute(ci) - if err != nil { - log.Fatalf("Fail to install: %v", err) - } - // do install in the temporary directory - err = gocBuild.Install() - if err != nil { - log.Fatalf("Fail to install: %v", err) - } - return -} diff --git a/cmd/install_test.go b/cmd/install_test.go deleted file mode 100644 index 5b94c97..0000000 --- a/cmd/install_test.go +++ /dev/null @@ -1,84 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.com) - - 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 cmd - -import ( - "os" - "os/exec" - "path/filepath" - "strings" - "testing" - "time" - - "github.com/stretchr/testify/assert" -) - -func TestInstalledBinaryForMod(t *testing.T) { - startTime := time.Now() - - workingDir := filepath.Join(baseDir, "../tests/samples/simple_project") - gopath := filepath.Join(baseDir, "../tests/samples/simple_project", "testhome") - - os.Setenv("GOPATH", gopath) - os.Setenv("GO111MODULE", "on") - - buildFlags, buildOutput = "", "" - args := []string{"."} - runInstall(args, workingDir) - - obj := filepath.Join(gopath, "bin", "simple-project") - fInfo, err := os.Lstat(obj) - assert.Equal(t, err, nil, "the binary should be generated.") - assert.Equal(t, startTime.Before(fInfo.ModTime()), true, obj+"new binary should be generated, not the old one") - - cmd := exec.Command("go", "tool", "objdump", "simple-project") - cmd.Dir = workingDir - out, _ := cmd.CombinedOutput() - cnt := strings.Count(string(out), "main.registerSelf") - assert.Equal(t, cnt > 0, true, "main.registerSelf function should be in the binary") - - cnt = strings.Count(string(out), "GoCover") - assert.Equal(t, cnt > 0, true, "GoCover variable should be in the binary") -} - -func TestInstalledBinaryForLegacy(t *testing.T) { - startTime := time.Now() - - workingDir := filepath.Join(baseDir, "../tests/samples/simple_gopath_project/src/qiniu.com/simple_gopath_project") - gopath := filepath.Join(baseDir, "../tests/samples/simple_gopath_project") - - os.Setenv("GOPATH", gopath) - os.Setenv("GO111MODULE", "off") - - buildFlags, buildOutput = "", "" - args := []string{"."} - runInstall(args, workingDir) - - obj := filepath.Join(gopath, "bin", "simple_gopath_project") - fInfo, err := os.Lstat(obj) - assert.Equal(t, err, nil, "the binary should be generated.") - assert.Equal(t, startTime.Before(fInfo.ModTime()), true, obj+"new binary should be generated, not the old one") - - cmd := exec.Command("go", "tool", "objdump", obj) - cmd.Dir = workingDir - out, _ := cmd.CombinedOutput() - cnt := strings.Count(string(out), "main.registerSelf") - assert.Equal(t, cnt > 0, true, "main.registerSelf function should be in the binary") - - cnt = strings.Count(string(out), "GoCover") - assert.Equal(t, cnt > 0, true, "GoCover variable should be in the binary") -} diff --git a/cmd/list.go b/cmd/list.go deleted file mode 100644 index 101b4fe..0000000 --- a/cmd/list.go +++ /dev/null @@ -1,49 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.com) - - 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 cmd - -import ( - "fmt" - "os" - - log "github.com/sirupsen/logrus" - - "github.com/qiniu/goc/pkg/cover" - "github.com/spf13/cobra" -) - -var listCmd = &cobra.Command{ - Use: "list", - Short: "Lists all the registered services", - Long: "Lists all the registered services", - Example: ` -goc list [flags] -`, - Run: func(cmd *cobra.Command, args []string) { - res, err := cover.NewWorker(center).ListServices() - if err != nil { - log.Fatalf("list failed, err: %v", err) - } - log.Infoln(string(res)) - fmt.Fprint(os.Stdout, string(res)) - }, -} - -func init() { - addBasicFlags(listCmd.Flags()) - rootCmd.AddCommand(listCmd) -} diff --git a/cmd/merge.go b/cmd/merge.go deleted file mode 100644 index 64e6495..0000000 --- a/cmd/merge.go +++ /dev/null @@ -1,76 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.com) - - 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 cmd - -import ( - log "github.com/sirupsen/logrus" - - "github.com/spf13/cobra" - "golang.org/x/tools/cover" - "k8s.io/test-infra/gopherage/pkg/cov" - "k8s.io/test-infra/gopherage/pkg/util" -) - -var mergeCmd = &cobra.Command{ - Use: "merge [files...]", - Short: "Merge multiple coherent Go coverage files into a single file.", - Long: `merge will merge multiple Go coverage files into a single coverage file. -merge requires that the files are 'coherent', meaning that if they both contain references to the -same paths, then the contents of those source files were identical for the binary that generated -each file. -`, - Run: func(cmd *cobra.Command, args []string) { - runMerge(args, outputMergeProfile) - }, -} - -var outputMergeProfile string - -func init() { - mergeCmd.Flags().StringVarP(&outputMergeProfile, "output", "o", "mergeprofile.cov", "output file") - - rootCmd.AddCommand(mergeCmd) -} - -func runMerge(args []string, output string) { - if len(args) == 0 { - log.Fatalln("Expected at least one coverage file.") - return - } - - profiles := make([][]*cover.Profile, len(args)) - for _, path := range args { - profile, err := util.LoadProfile(path) - if err != nil { - log.Fatalf("failed to open %s: %v", path, err) - return - } - profiles = append(profiles, profile) - } - - merged, err := cov.MergeMultipleProfiles(profiles) - if err != nil { - log.Fatalf("failed to merge files: %v", err) - return - } - - err = util.DumpProfile(output, merged) - if err != nil { - log.Fatalln(err) - return - } -} diff --git a/cmd/merge_test.go b/cmd/merge_test.go deleted file mode 100644 index afb7302..0000000 --- a/cmd/merge_test.go +++ /dev/null @@ -1,156 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.com) - - 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 cmd - -import ( - "io/ioutil" - "os" - "path/filepath" - "testing" - - log "github.com/sirupsen/logrus" - "github.com/stretchr/testify/assert" -) - -// use a variable to record if the tested function has failed -// so unittest can only be executed sequential -var fatal = false -var fatalStr string - -type TestLogHook struct{} - -func (h *TestLogHook) Levels() []log.Level { - return []log.Level{log.FatalLevel} -} - -func (h *TestLogHook) Fire(e *log.Entry) error { - fatalStr = e.Message - return nil -} - -func TestMain(m *testing.M) { - // setup - originalExitFunc := log.StandardLogger().ExitFunc - defer func() { - log.StandardLogger().ExitFunc = originalExitFunc - log.StandardLogger().Hooks = make(log.LevelHooks) - }() - - // replace exit function, so log.Fatal wont exit - log.StandardLogger().ExitFunc = func(int) { fatal = true } - // add hook, so fatal string will be recorded - log.StandardLogger().Hooks.Add(&TestLogHook{}) - - code := m.Run() - - os.Exit(code) -} - -func TestMergeNormalProfiles(t *testing.T) { - profileA := filepath.Join(baseDir, "../tests/samples/merge_profile_samples/a.voc") - profileB := filepath.Join(baseDir, "../tests/samples/merge_profile_samples/b.voc") - mergeprofile := filepath.Join(baseDir, "../tests/samples/merge_profile_samples/merge.cov") - - runMerge([]string{profileA, profileB}, mergeprofile) - - contents, err := ioutil.ReadFile(mergeprofile) - assert.NoError(t, err) - assert.Contains(t, string(contents), "qiniu.com/kodo/apiserver/server/main.go:32.49,33.13 1 60") - assert.Contains(t, string(contents), "qiniu.com/kodo/apiserver/server/main.go:42.49,43.13 1 2") - assert.Equal(t, fatal, false) -} - -// test with no profiles -func TestMergeWithNoProfiles(t *testing.T) { - mergeprofile := filepath.Join(baseDir, "../tests/samples/merge_profile_samples/merge.cov") - - // clear fatal string in setup - fatalStr = "" - fatal = false - - runMerge([]string{}, mergeprofile) - - // there is fatal - assert.Equal(t, fatal, true) - assert.Equal(t, fatalStr, "Expected at least one coverage file.") -} - -// pass a non-existed profile to runMerge -func TestWithWrongProfileName(t *testing.T) { - profileA := filepath.Join(baseDir, "../tests/samples/merge_profile_samples/notexist.voc") - mergeprofile := filepath.Join(baseDir, "../tests/samples/merge_profile_samples/merge.cov") - - // clear fatal string in setup - fatalStr = "" - fatal = false - - runMerge([]string{profileA}, mergeprofile) - - // there is fatal - assert.Equal(t, fatal, true) - assert.Contains(t, fatalStr, "failed to open") -} - -// merge two different modes' profiles should fail -func TestMergeTwoDifferentModeProfile(t *testing.T) { - profileA := filepath.Join(baseDir, "../tests/samples/merge_profile_samples/a.voc") - profileSet := filepath.Join(baseDir, "../tests/samples/merge_profile_samples/setmode.voc") - mergeprofile := filepath.Join(baseDir, "../tests/samples/merge_profile_samples/merge.cov") - - // clear fatal string in setup - fatalStr = "" - fatal = false - - runMerge([]string{profileA, profileSet}, mergeprofile) - - // there is fatal - assert.Equal(t, fatal, true) - assert.Contains(t, fatalStr, "mode for qiniu.com/kodo/apiserver/server/main.go mismatches") -} - -// merge two overlaped profiles should fail -func TestMergeTwoOverLapProfile(t *testing.T) { - profileA := filepath.Join(baseDir, "../tests/samples/merge_profile_samples/a.voc") - profileOverlap := filepath.Join(baseDir, "../tests/samples/merge_profile_samples/overlap.voc") - mergeprofile := filepath.Join(baseDir, "../tests/samples/merge_profile_samples/merge.cov") - - // clear fatal string in setup - fatalStr = "" - fatal = false - - runMerge([]string{profileA, profileOverlap}, mergeprofile) - - // there is fatal - assert.Equal(t, fatal, true) - assert.Contains(t, fatalStr, "coverage block mismatch") -} - -// merge empty file should fail -func TestMergeEmptyProfile(t *testing.T) { - profileA := filepath.Join(baseDir, "../tests/samples/merge_profile_samples/empty.voc") - mergeprofile := filepath.Join(baseDir, "../tests/samples/merge_profile_samples/merge.cov") - - // clear fatal string in setup - fatalStr = "" - fatal = false - - runMerge([]string{profileA}, mergeprofile) - - // there is fatal - assert.Equal(t, fatal, true) - assert.Contains(t, fatalStr, "failed to dump profile") -} diff --git a/cmd/profile.go b/cmd/profile.go deleted file mode 100644 index 502372e..0000000 --- a/cmd/profile.go +++ /dev/null @@ -1,112 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.com) - - 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 cmd - -import ( - "bytes" - "fmt" - "io" - "os" - "path" - - "github.com/qiniu/goc/pkg/cover" - log "github.com/sirupsen/logrus" - "github.com/spf13/cobra" -) - -var profileCmd = &cobra.Command{ - Use: "profile", - Short: "Get coverage profile from service registry center", - Long: `Get code coverage profile for the services under test at runtime.`, - Example: ` -# Get coverage counter from default register center http://127.0.0.1:7777, the result output to stdout. -goc profile - -# Get coverage counter from specified register center, the result output to specified file. -goc profile --center=http://192.168.1.1:8080 --output=./coverage.cov - -# Get coverage counter of several specified services. You can get all available service names from command 'goc list'. Use 'service' and 'address' flag at the same time may cause ambiguity, please use them separately. -goc profile --service=service1,service2,service3 - -# Get coverage counter of several specified addresses. You can get all available addresses from command 'goc list'. Use 'service' and 'address' flag at the same time may cause ambiguity, please use them separately. -goc profile --address=address1,address2,address3 - -# Only get the coverage data of files matching the special patterns -goc profile --coverfile=pattern1,pattern2,pattern3 - -# Force fetching all available profiles. -goc profile --force -`, - Run: func(cmd *cobra.Command, args []string) { - p := cover.ProfileParam{ - Force: force, - Service: svrList, - Address: addrList, - CoverFilePatterns: coverFilePatterns, - SkipFilePatterns: skipFilePatterns, - } - res, err := cover.NewWorker(center).Profile(p) - if err != nil { - log.Fatalf("Goc server %v return an error: %v", center, err) - } - - if output == "" { - fmt.Fprint(os.Stdout, string(res)) - } else { - var dir, filename string = path.Split(output) - if dir != "" { - err = os.MkdirAll(dir, os.ModePerm) - if err != nil { - log.Fatalf("failed to create directory %s, err:%v", dir, err) - } - } - if filename == "" { - output += "coverage.cov" - } - - f, err := os.Create(output) - if err != nil { - log.Fatalf("failed to create file %s, err:%v", output, err) - } - defer f.Close() - _, err = io.Copy(f, bytes.NewReader(res)) - if err != nil { - log.Fatalf("failed to write file: %v, err: %v", output, err) - } - } - }, -} - -var ( - svrList []string // --service flag - addrList []string // --address flag - force bool // --force flag - output string // --output flag - coverFilePatterns []string // --coverfile flag - skipFilePatterns []string // --skipfile flag -) - -func init() { - profileCmd.Flags().StringVarP(&output, "output", "o", "", "download cover profile") - profileCmd.Flags().StringSliceVarP(&svrList, "service", "", nil, "service name to fetch profile, see 'goc list' for all services.") - profileCmd.Flags().StringSliceVarP(&addrList, "address", "", nil, "address to fetch profile, see 'goc list' for all addresses.") - profileCmd.Flags().BoolVarP(&force, "force", "f", false, "force fetching all available profiles") - profileCmd.Flags().StringSliceVarP(&coverFilePatterns, "coverfile", "", nil, "only output coverage data of the files matching the patterns") - profileCmd.Flags().StringSliceVarP(&skipFilePatterns, "skipfile", "", nil, "skip the files matching the patterns when outputing coverage data") - addBasicFlags(profileCmd.Flags()) - rootCmd.AddCommand(profileCmd) -} diff --git a/cmd/register.go b/cmd/register.go deleted file mode 100644 index ab0518b..0000000 --- a/cmd/register.go +++ /dev/null @@ -1,60 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.com) - - 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 cmd - -import ( - "fmt" - "log" - "os" - - "github.com/qiniu/goc/pkg/cover" - "github.com/spf13/cobra" -) - -var registerCmd = &cobra.Command{ - Use: "register", - Short: "Register a service into service center", - Long: "Register a service into service center", - Example: ` -goc register [flags] -`, - Run: func(cmd *cobra.Command, args []string) { - s := cover.ServiceUnderTest{ - Name: name, - Address: address, - } - res, err := cover.NewWorker(center).RegisterService(s) - if err != nil { - log.Fatalf("register service failed, err: %v", err) - } - fmt.Fprint(os.Stdout, string(res)) - }, -} - -var ( - name string - address string -) - -func init() { - registerCmd.Flags().StringVarP(¢er, "center", "", "http://127.0.0.1:7777", "cover profile host center") - registerCmd.Flags().StringVarP(&name, "name", "n", "", "service name") - registerCmd.Flags().StringVarP(&address, "address", "a", "", "service address") - registerCmd.MarkFlagRequired("name") - registerCmd.MarkFlagRequired("address") - rootCmd.AddCommand(registerCmd) -} diff --git a/cmd/remove.go b/cmd/remove.go deleted file mode 100644 index 6d21eea..0000000 --- a/cmd/remove.go +++ /dev/null @@ -1,58 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.com) - - 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 cmd - -import ( - "fmt" - "os" - - log "github.com/sirupsen/logrus" - - "github.com/qiniu/goc/pkg/cover" - "github.com/spf13/cobra" -) - -var removeCmd = &cobra.Command{ - Use: "remove", - Short: "Remove the specified service from the register center.", - Long: `Remove the specified service from the register center, after that, goc profile will not collect coverage data from this service anymore`, - Example: ` -# Remove the service 'mongo' from the default register center http://127.0.0.1:7777. -goc remove --service=mongo - -# Remove the service 'http://127.0.0.1:53' from the specified register center. -goc remove --address="http://127.0.0.1:53" --center=http://192.168.1.1:8080 -`, - Run: func(cmd *cobra.Command, args []string) { - p := cover.ProfileParam{ - Service: svrList, - Address: addrList, - } - res, err := cover.NewWorker(center).Remove(p) - if err != nil { - log.Fatalf("call host %v failed, err: %v, response: %v", center, err, string(res)) - } - fmt.Fprint(os.Stdout, string(res)) - }, -} - -func init() { - addBasicFlags(removeCmd.Flags()) - removeCmd.Flags().StringSliceVarP(&svrList, "service", "", nil, "service name to clear profile, see 'goc list' for all services.") - removeCmd.Flags().StringSliceVarP(&addrList, "address", "", nil, "address to clear profile, see 'goc list' for all addresses.") - rootCmd.AddCommand(removeCmd) -} diff --git a/cmd/root.go b/cmd/root.go deleted file mode 100644 index 1316cfa..0000000 --- a/cmd/root.go +++ /dev/null @@ -1,88 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.com) - - 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 cmd - -import ( - "os" - "path/filepath" - "runtime" - "strconv" - "time" - - log "github.com/sirupsen/logrus" - "github.com/spf13/cobra" - "github.com/spf13/viper" -) - -var rootCmd = &cobra.Command{ - Use: "goc", - Short: "goc is a comprehensive coverage testing tool for go language", - Long: `goc is a comprehensive coverage testing tool for go language. - -Find more information at: - https://github.com/qiniu/goc -`, - PersistentPreRun: func(cmd *cobra.Command, args []string) { - log.SetReportCaller(true) - log.SetLevel(log.InfoLevel) - log.SetFormatter(&log.TextFormatter{ - FullTimestamp: true, - CallerPrettyfier: func(f *runtime.Frame) (string, string) { - dirname, filename := filepath.Split(f.File) - lastelem := filepath.Base(dirname) - filename = filepath.Join(lastelem, filename) - line := strconv.Itoa(f.Line) - return "", "[" + filename + ":" + line + "]" - }, - }) - if debugGoc == false { - // we only need log in debug mode - log.SetLevel(log.FatalLevel) - log.SetFormatter(&log.TextFormatter{ - DisableTimestamp: true, - CallerPrettyfier: func(f *runtime.Frame) (string, string) { - return "", "" - }, - }) - } - }, - PersistentPostRun: func(cmd *cobra.Command, args []string) { - if debugInCISyncFile != "" { - f, err := os.Create(debugInCISyncFile) - if err != nil { - log.Fatalln(err) - } - defer f.Close() - - time.Sleep(5 * time.Second) - } - }, -} - -func init() { - rootCmd.PersistentFlags().BoolVar(&debugGoc, "debug", false, "run goc in debug mode") - rootCmd.PersistentFlags().StringVar(&debugInCISyncFile, "debugcisyncfile", "", "internal use only, no explain") - rootCmd.PersistentFlags().MarkHidden("debugcisyncfile") - viper.BindPFlags(rootCmd.PersistentFlags()) -} - -// Execute the goc tool -func Execute() { - if err := rootCmd.Execute(); err != nil { - log.Fatalln(err) - } -} diff --git a/cmd/run.go b/cmd/run.go deleted file mode 100644 index f78207c..0000000 --- a/cmd/run.go +++ /dev/null @@ -1,103 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.com) - - 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 cmd - -import ( - "fmt" - "io/ioutil" - "net" - "os" - - "github.com/qiniu/goc/pkg/build" - "github.com/qiniu/goc/pkg/cover" - log "github.com/sirupsen/logrus" - "github.com/spf13/cobra" -) - -var runCmd = &cobra.Command{ - Use: "run", - Short: "Run covers and runs the named main Go package", - Long: `Run covers and runs the named main Go package, -It is exactly behave as 'go run .' in addition of some internal goc features.`, - Example: ` -goc run . -goc run . [--buildflags] [--exec] [--arguments] -`, - Run: func(cmd *cobra.Command, args []string) { - wd, err := os.Getwd() - if err != nil { - log.Fatalf("Fail to build: %v", err) - } - gocBuild, err := build.NewBuild(buildFlags, args, wd, buildOutput) - if err != nil { - log.Fatalf("Fail to run: %v", err) - } - gocBuild.GoRunExecFlag = goRunExecFlag - gocBuild.GoRunArguments = goRunArguments - defer gocBuild.Clean() - - server := cover.NewMemoryBasedServer() // only save services in memory - - // start goc server - var l = newLocalListener() - go func() { - err = server.Route(ioutil.Discard).RunListener(l) - if err != nil { - log.Fatalf("Start goc server failed: %v", err) - } - }() - gocServer := fmt.Sprintf("http://%s", l.Addr().String()) - fmt.Printf("[goc] goc server started: %s \n", gocServer) - - // execute covers for the target source with original buildFlags and new GOPATH( tmp:original ) - ci := &cover.CoverInfo{ - Args: buildFlags, - GoPath: gocBuild.NewGOPATH, - Target: gocBuild.TmpDir, - Mode: coverMode.String(), - Center: gocServer, - AgentPort: "", - IsMod: gocBuild.IsMod, - ModRootPath: gocBuild.ModRootPath, - OneMainPackage: true, // go run is similar with go build, build only one main package - GlobalCoverVarImportPath: gocBuild.GlobalCoverVarImportPath, - } - err = cover.Execute(ci) - if err != nil { - log.Fatalf("Fail to run: %v", err) - } - - if err := gocBuild.Run(); err != nil { - log.Fatalf("Fail to run: %v", err) - } - }, -} - -func init() { - addRunFlags(runCmd.Flags()) - rootCmd.AddCommand(runCmd) -} - -func newLocalListener() net.Listener { - l, err := net.Listen("tcp", "127.0.0.1:0") - if err != nil { - if l, err = net.Listen("tcp6", "[::1]:0"); err != nil { - log.Fatalf("failed to listen on a port: %v", err) - } - } - return l -} diff --git a/cmd/server.go b/cmd/server.go deleted file mode 100644 index 36d5b5e..0000000 --- a/cmd/server.go +++ /dev/null @@ -1,54 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.com) - - 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 cmd - -import ( - "github.com/qiniu/goc/pkg/cover" - "github.com/spf13/cobra" - "log" -) - -var serverCmd = &cobra.Command{ - Use: "server", - Short: "Start a service registry center", - Long: `Start a service registry center.`, - Example: ` -# Start a service registry center, default port :7777. -goc server - -# Start a service registry center with port :8080. -goc server --port=:8080 - -# Start a service registry center with localhost:8080. -goc server --port=localhost:8080 -`, - Run: func(cmd *cobra.Command, args []string) { - server, err := cover.NewFileBasedServer(localPersistence) - if err != nil { - log.Fatalf("New file based server failed, err: %v", err) - } - server.Run(port) - }, -} - -var port, localPersistence string - -func init() { - serverCmd.Flags().StringVarP(&port, "port", "", ":7777", "listen port to start a coverage host center") - serverCmd.Flags().StringVarP(&localPersistence, "local-persistence", "", "_svrs_address.txt", "the file to save services address information") - rootCmd.AddCommand(serverCmd) -} diff --git a/cmd/version.go b/cmd/version.go deleted file mode 100644 index 5345341..0000000 --- a/cmd/version.go +++ /dev/null @@ -1,51 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.com) - - 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 cmd - -import ( - "fmt" - "runtime/debug" - - "github.com/spf13/cobra" -) - -// the version value will be injected when publishing -var version = "Unstable" - -var versionCmd = &cobra.Command{ - Use: "version", - Short: "Print the goc version information", - Example: ` -# Print the client and server versions for the current context -goc version - `, - Run: func(cmd *cobra.Command, args []string) { - // if it is "Unstable", means user build local or with go get - if version == "Unstable" { - if info, ok := debug.ReadBuildInfo(); ok { - fmt.Println(info.Main.Version) - } - } else { - // otherwise the value is injected in CI - fmt.Println(version) - } - }, -} - -func init() { - rootCmd.AddCommand(versionCmd) -} diff --git a/codecov.yaml b/codecov.yaml deleted file mode 100644 index 42f72f4..0000000 --- a/codecov.yaml +++ /dev/null @@ -1,8 +0,0 @@ -comment: - layout: "reach, diff, flags, files" - behavior: new - require_changes: false # if true: only post the comment if coverage changes - require_base: no # [yes :: must have a base report to post] - require_head: yes # [yes :: must have a head report to post] - branches: # branch names that can post comment - - "master" diff --git a/docs/images/goc-vscode.gif b/docs/images/goc-vscode.gif deleted file mode 100644 index a1c2312..0000000 Binary files a/docs/images/goc-vscode.gif and /dev/null differ diff --git a/docs/images/intro.gif b/docs/images/intro.gif deleted file mode 100644 index aeef5b2..0000000 Binary files a/docs/images/intro.gif and /dev/null differ diff --git a/docs/images/wechat.png b/docs/images/wechat.png deleted file mode 100644 index 1cc2126..0000000 Binary files a/docs/images/wechat.png and /dev/null differ diff --git a/go.mod b/go.mod deleted file mode 100644 index 5359025..0000000 --- a/go.mod +++ /dev/null @@ -1,24 +0,0 @@ -module github.com/qiniu/goc - -go 1.13 - -require ( - github.com/gin-gonic/gin v1.6.3 - github.com/google/go-github v17.0.0+incompatible - github.com/hashicorp/go-retryablehttp v0.6.6 - github.com/julienschmidt/httprouter v1.2.0 - github.com/mattn/go-runewidth v0.0.9 // indirect - github.com/olekukonko/tablewriter v0.0.4 - github.com/qiniu/api.v7/v7 v7.5.0 - github.com/sirupsen/logrus v1.6.0 - github.com/spf13/cobra v1.0.0 - github.com/spf13/pflag v1.0.5 - github.com/spf13/viper v1.6.2 - github.com/stretchr/testify v1.5.1 - github.com/tongjingran/copy v1.4.2 - golang.org/x/mod v0.3.0 - golang.org/x/net v0.0.0-20200625001655-4c5254603344 - golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d - golang.org/x/tools v0.0.0-20200730221956-1ac65761fe2c - k8s.io/test-infra v0.0.0-20200511080351-8ac9dbfab055 -) diff --git a/go.sum b/go.sum deleted file mode 100644 index 9682ae1..0000000 --- a/go.sum +++ /dev/null @@ -1,1143 +0,0 @@ -bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= -bazil.org/fuse v0.0.0-20180421153158-65cc252bf669/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.39.0/go.mod h1:rVLT6fkc8chs9sfPtFc1SBH6em7n+ZoXaG+87tDISts= -cloud.google.com/go v0.40.0/go.mod h1:Tk58MuI9rbLMKlAjeO/bDnteAx7tX2gJIXw4T5Jwlro= -cloud.google.com/go v0.43.0/go.mod h1:BOSR3VbTLkk6FDC/TcffxP4NF/FFBGA5ku+jvKOP7pg= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.47.0/go.mod h1:5p3Ky/7f3N10VBkhuR5LFtddroTiMyjZV/Kj5qOQFxU= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/logging v1.0.0/go.mod h1:V1cc3ogwobYzQq5f2R7DS/GvRIrI4FKj01Gs5glwAls= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -contrib.go.opencensus.io/exporter/aws v0.0.0-20181029163544-2befc13012d0/go.mod h1:uu1P0UCM/6RbsMrgPa98ll8ZcHM858i/AD06a9aLRCA= -contrib.go.opencensus.io/exporter/ocagent v0.4.12/go.mod h1:450APlNTSR6FrvC3CTRqYosuDstRB9un7SOx2k/9ckA= -contrib.go.opencensus.io/exporter/ocagent v0.5.0/go.mod h1:ImxhfLRpxoYiSq891pBrLVhN+qmP8BTVvdH2YLs7Gl0= -contrib.go.opencensus.io/exporter/prometheus v0.1.0/go.mod h1:cGFniUXGZlKRjzOyuZJ6mgB+PgBcCIa79kEKR8YCW+A= -contrib.go.opencensus.io/exporter/stackdriver v0.12.1/go.mod h1:iwB6wGarfphGGe/e5CWqyUk/cLzKnWsOKPVW3no6OTw= -contrib.go.opencensus.io/exporter/stackdriver v0.12.8/go.mod h1:XyyafDnFOsqoxHJgTFycKZMrRUrPThLh2iYTJF6uoO0= -contrib.go.opencensus.io/integrations/ocsql v0.1.4/go.mod h1:8DsSdjz3F+APR+0z0WkU1aRorQCFfRxvqjUUPMbF3fE= -contrib.go.opencensus.io/resource v0.1.1/go.mod h1:F361eGI91LCmW1I/Saf+rX0+OFcigGlFvXwEGEnkRLA= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -git.apache.org/thrift.git v0.12.0/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= -github.com/Azure/azure-amqp-common-go/v2 v2.1.0/go.mod h1:R8rea+gJRuJR6QxTir/XuEd+YuKoUiazDC/N96FiDEU= -github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4= -github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/azure-sdk-for-go v29.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/azure-sdk-for-go v30.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/azure-sdk-for-go v35.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/azure-sdk-for-go v38.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/azure-service-bus-go v0.9.1/go.mod h1:yzBx6/BUGfjfeqbRZny9AQIbIe3AcV9WZbAdpkoXOa0= -github.com/Azure/azure-storage-blob-go v0.8.0/go.mod h1:lPI3aLPpuLTeUwh1sViKXFxwl2B6teiRqI0deQUvsw0= -github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= -github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= -github.com/Azure/go-autorest v12.0.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= -github.com/Azure/go-autorest/autorest v0.2.0/go.mod h1:AKyIcETwSUFxIcs/Wnq/C+kwCtlEYGUVd7FPNb2slmg= -github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= -github.com/Azure/go-autorest/autorest v0.9.3/go.mod h1:GsRuLYvwzLjjjRoWEIyMUaYq8GNUx2nRB378IPt/1p0= -github.com/Azure/go-autorest/autorest v0.9.6/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630= -github.com/Azure/go-autorest/autorest/adal v0.1.0/go.mod h1:MeS4XhScH55IST095THyTxElntu7WqB7pNbZo8Q5G3E= -github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= -github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= -github.com/Azure/go-autorest/autorest/adal v0.8.1/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= -github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= -github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= -github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= -github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= -github.com/Azure/go-autorest/autorest/to v0.2.0/go.mod h1:GunWKJp1AEqgMaGLV+iocmRAJWqST1wQYhyyjXJ3SJc= -github.com/Azure/go-autorest/autorest/to v0.3.0/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA= -github.com/Azure/go-autorest/autorest/validation v0.1.0/go.mod h1:Ha3z/SqBeaalWQvokg3NZAlQTalVMtOIAs1aGK7G6u8= -github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= -github.com/Azure/go-autorest/tracing v0.1.0/go.mod h1:ROEEAFwXycQw7Sn3DXNtEedEvdeRAgDr0izn4z5Ij88= -github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= -github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/DataDog/zstd v1.3.6-0.20190409195224-796139022798/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= -github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= -github.com/GoogleCloudPlatform/cloud-builders/gcs-fetcher v0.0.0-20191203181535-308b93ad1f39/go.mod h1:yfGmCjKuUzk9WzubMlW2zwjhCraIc/J+M40cufdemRM= -github.com/GoogleCloudPlatform/cloudsql-proxy v0.0.0-20191009163259-e802c2cb94ae/go.mod h1:mjwGPas4yKduTyubHvD1Atl9r1rUq8DfVy+gkVvZ+oo= -github.com/GoogleCloudPlatform/k8s-cloud-provider v0.0.0-20190822182118-27a4ced34534/go.mod h1:iroGtC8B3tQiqtds1l+mgk/BBOrxbqjH+eUfFQYRc14= -github.com/GoogleCloudPlatform/testgrid v0.0.7/go.mod h1:lmtHGBL0M/MLbu1tR9BWV7FGZ1FEFIdPqmJiHNCL7y8= -github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E= -github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= -github.com/Masterminds/semver/v3 v3.0.3/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= -github.com/Masterminds/sprig/v3 v3.0.2/go.mod h1:oesJ8kPONMONaZgtiHNzUShJbksypC5kWczhZAf6+aU= -github.com/Masterminds/vcs v1.13.1/go.mod h1:N09YCmOQr6RLxC6UNHzuVwAdodYbbnycGHSmwVJjcKA= -github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= -github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= -github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ= -github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= -github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= -github.com/Shopify/sarama v1.23.1/go.mod h1:XLH1GYJnLVE0XCr6KdJGVJRTwY30moWNJ4sERjXX6fs= -github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= -github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= -github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= -github.com/andybalholm/brotli v0.0.0-20190621154722-5f990b63d2d6/go.mod h1:+lx6/Aqd1kLJ1GQfkvOnaZ1WGmLpMpbprPuIOOZX30U= -github.com/andygrunwald/go-gerrit v0.0.0-20190120104749-174420ebee6c/go.mod h1:0iuRQp6WJ44ts+iihy5E/WlPqfg5RNeQxOmzRkxCdtk= -github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= -github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= -github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= -github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= -github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= -github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= -github.com/aws/aws-k8s-tester v1.0.0/go.mod h1:NUNd9k43+h9O5tvwL+4N1Ctb//SapmeeFX1G0/2/0Qc= -github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= -github.com/aws/aws-sdk-go v1.15.27/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= -github.com/aws/aws-sdk-go v1.16.26/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go v1.19.18/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go v1.19.45/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go v1.23.20/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go v1.27.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go v1.30.4/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= -github.com/aws/aws-sdk-go v1.30.5/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= -github.com/bazelbuild/buildtools v0.0.0-20190917191645-69366ca98f89/go.mod h1:5JP0TXzWDHXv8qvxRC4InIazwdyDseBDbzESUMKk1yU= -github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= -github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= -github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= -github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= -github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= -github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= -github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= -github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= -github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= -github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= -github.com/bwmarrin/snowflake v0.0.0/go.mod h1:NdZxfVWX+oR6y2K0o6qAYv6gIOP9rjG0/E9WsDpxqwE= -github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw= -github.com/cihub/seelog v0.0.0-20170130134532-f561c5e57575/go.mod h1:9d6lWj8KzO/fd/NrVaLscBKmPigpZpn5YawRPw+e3Yo= -github.com/clarketm/json v1.13.4/go.mod h1:ynr2LRfb0fQU34l07csRNBTcivjySLLiY1YzQqKVfdo= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cloudevents/sdk-go v1.0.0/go.mod h1:3TkmM0cFqkhCHOq5JzzRU/RxRkwzoS8TZ+G448qVTog= -github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= -github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko= -github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= -github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= -github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= -github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= -github.com/containerd/containerd v1.3.3/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= -github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= -github.com/containerd/continuity v0.0.0-20200107194136-26c1120b8d41/go.mod h1:Dq467ZllaHgAtVp4p1xUQWBrFXR9s/wyoTpG8zOJGkY= -github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= -github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= -github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= -github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= -github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= -github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= -github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= -github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= -github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= -github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1:dv4zxwHi5C/8AeI+4gX4dCWOIvNi7I6JCSX0HvlKPgE= -github.com/deislabs/oras v0.8.1/go.mod h1:Mx0rMSbBNaNfY9hjpccEnxkOqJL6KGjtxNHPLC4G4As= -github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= -github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0= -github.com/devigned/tab v0.1.1/go.mod h1:XG9mPq0dFghrYvoBF3xdRrJzSTX1b7IQrvaL9mzjeJY= -github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= -github.com/djherbis/atime v1.0.0/go.mod h1:5W+KBIuTwVGcqjIfaTwt+KSYX1o6uep8dtevevQP/f8= -github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= -github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= -github.com/docker/cli v0.0.0-20200130152716-5d0cf8839492/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= -github.com/docker/distribution v0.0.0-20191216044856-a8371794149d/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY= -github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/docker v1.4.2-0.20200203170920-46ec8731fbce/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= -github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= -github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI= -github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= -github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= -github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= -github.com/dsnet/compress v0.0.1/go.mod h1:Aw8dCMJ7RioblQeTqt88akK31OvO8Dhf5JflhBbQEHo= -github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY= -github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= -github.com/eapache/go-resiliency v1.2.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= -github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= -github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= -github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= -github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= -github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= -github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= -github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= -github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= -github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= -github.com/fortytw2/leaktest v1.2.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= -github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= -github.com/frankban/quicktest v1.8.1/go.mod h1:ui7WezCLWMWxVWr1GETZY3smRy0G4KWq9vcPtJmFl7Y= -github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsouza/fake-gcs-server v0.0.0-20180612165233-e85be23bdaa8/go.mod h1:1/HufuJ+eaDf4KTnYdS6HJMGvMRU8d4cYTuu/1QaBbI= -github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= -github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= -github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= -github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= -github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= -github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= -github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= -github.com/go-bindata/go-bindata/v3 v3.1.3/go.mod h1:1/zrpXsLD8YDIbhZRqXzm1Ghc7NhEvIN9+Z6R5/xH4I= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= -github.com/go-ini/ini v1.55.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= -github.com/go-logr/zapr v0.1.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk= -github.com/go-logr/zapr v0.1.1/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk= -github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI= -github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= -github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= -github.com/go-openapi/analysis v0.19.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk= -github.com/go-openapi/analysis v0.19.5/go.mod h1:hkEAkxagaIvIP7VTn8ygJNkd4kAYON2rCu0v0ObL0AU= -github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= -github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= -github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94= -github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= -github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= -github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= -github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= -github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= -github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= -github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= -github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= -github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= -github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= -github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= -github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= -github.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix5jWFxsNPs= -github.com/go-openapi/loads v0.19.4/go.mod h1:zZVHonKd8DXyxyw4yfnVjPzBjIQcLt0CCsn0N0ZrQsk= -github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA= -github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64= -github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4= -github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= -github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= -github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= -github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY= -github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= -github.com/go-openapi/spec v0.19.4/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= -github.com/go-openapi/spec v0.19.6/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk= -github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= -github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= -github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY= -github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU= -github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= -github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= -github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= -github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.19.7/go.mod h1:ao+8BpOPyKdpQz3AOJfbeEVpLmWAvlT1IfTe5McPyhY= -github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= -github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA= -github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= -github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= -github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= -github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= -github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= -github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= -github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY= -github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= -github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= -github.com/gobuffalo/envy v1.6.5/go.mod h1:N+GkhhZ/93bGZc6ZKhJLP6+m+tCNPKwgSpH9kaifseQ= -github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= -github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= -github.com/gofrs/flock v0.7.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= -github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= -github.com/gogo/protobuf v1.0.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= -github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= -github.com/gogo/protobuf v1.2.2-0.20190730201129-28a6bbf47e48/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= -github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= -github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= -github.com/golang/gddo v0.0.0-20190419222130-af0f2af80721/go.mod h1:xEhNfoBDX1hzLm2Nf80qUvZ2sVwoMZ8d6IE2SrsQfh4= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20180513044358-24b0969c4cb7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1 h1:qGJ6qTW+x6xX/my+8YUVl4WNpX9B7+/l2tRsHGZ7f2s= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.4 h1:87PNWwrRvUSnqS4dlcBU/ftvOIBep4sYuBLlh6rX2wk= -github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golangplus/bytes v0.0.0-20160111154220-45c989fe5450/go.mod h1:Bk6SMAONeMXrxql8uvOKuAZSu8aM5RUGv+1C6IJaEho= -github.com/golangplus/fmt v0.0.0-20150411045040-2a5d6d7d2995/go.mod h1:lJgMEyOkYFkPcDKwRXegd+iM6E7matEszMG5HhwytU8= -github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e/go.mod h1:0AA//k/eakGydO4jKRoRL2j92ZKSzTgj9tclaCrvXHk= -github.com/gomodule/redigo v1.7.0/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-containerregistry v0.0.0-20200115214256-379933c9c22b/go.mod h1:Wtl/v6YdQxv397EREtzwgd9+Ud7Q5D8XMbi3Zazgkrs= -github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY= -github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= -github.com/google/go-licenses v0.0.0-20191112164736-212ea350c932/go.mod h1:16wa6pRqNDUIhOtwF0GcROVqMeXHZJ7H6eGDFUh5Pfk= -github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= -github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= -github.com/google/go-replayers/grpcreplay v0.1.0/go.mod h1:8Ig2Idjpr6gifRd6pNVggX6TC1Zw6Jx74AKp7QNH2QE= -github.com/google/go-replayers/httpreplay v0.1.0/go.mod h1:YKZViNhiGgqdBlUbI2MwGpq4pXxNmhJLPHQ7cv2b5no= -github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/licenseclassifier v0.0.0-20190926221455-842c0d70d702/go.mod h1:qsqn2hxC+vURpyBRygGUuinTO42MFRLcsmQ/P8v94+M= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian v2.1.1-0.20190517191504-25dcb96d9e51+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190723021845-34ac40c74b70/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= -github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/wire v0.3.0/go.mod h1:i1DMg/Lu8Sz5yYl25iOdmc5CT5qusaa+zmRWs16741s= -github.com/googleapis/gax-go v2.0.2+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= -github.com/googleapis/gnostic v0.2.2/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= -github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU= -github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= -github.com/gorilla/csrf v1.6.2/go.mod h1:7tSf8kmjNYr7IWDCYhd3U8Ck34iQ/Yw5CJu7bAkHEGI= -github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= -github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= -github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= -github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gosuri/uitable v0.0.4/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo= -github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= -github.com/gregjones/httpcache v0.0.0-20190212212710-3befbb6ad0cc/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/grpc-ecosystem/grpc-gateway v1.9.2/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/h2non/gock v1.0.9/go.mod h1:CZMcB0Lg5IWnr9bF79pPMg9WeV6WumxQiUJ1UvdO1iE= -github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM= -github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI= -github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= -github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I= -github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-retryablehttp v0.6.6 h1:HJunrbHTDDbBb/ay4kxa1n+dLmttUlnP3V9oNE4hmsM= -github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= -github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -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 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4= -github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/influxdata/influxdb v0.0.0-20161215172503-049f9b42e9a5/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY= -github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= -github.com/jcmturner/gofork v0.0.0-20190328161633-dc7c13fece03/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= -github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= -github.com/jenkins-x/go-scm v1.5.79/go.mod h1:PCT338UhP/pQ0IeEeMEf/hoLTYKcH7qjGEKd7jPkeYg= -github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jinzhu/gorm v1.9.12/go.mod h1:vhTjlKSJUTWNtcbQtrMBFCxy7eXTzeCAzfL5fBZT/Qs= -github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= -github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= -github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= -github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= -github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= -github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= -github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik= -github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8= -github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= -github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= -github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= -github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= -github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/julienschmidt/httprouter v1.2.0 h1:TDTW5Yz1mjftljbcKqRcrYhd4XeOoI98t+9HbQbYf7g= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= -github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= -github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= -github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/klauspost/compress v1.9.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/klauspost/compress v1.10.2/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= -github.com/klauspost/pgzip v1.2.1/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s= -github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8= -github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= -github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= -github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= -github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= -github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= -github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc= -github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= -github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= -github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= -github.com/markbates/inflect v1.0.4/go.mod h1:1fR9+pO2KHEO9ZRtto13gDwwZaAKstQzferVeWqbgNs= -github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho= -github.com/mattbaird/jsonpatch v0.0.0-20171005235357-81af80346b1a/go.mod h1:M1qoD/MqPgTZIk0EWKB38wE28ACRfVcn+cU08jyArI0= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= -github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= -github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mattn/go-runewidth v0.0.8 h1:3tS41NlGYSmhhe/8fhGRzc+z3AYCw1Fe1WAyLuujKs0= -github.com/mattn/go-runewidth v0.0.8/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= -github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mattn/go-shellwords v1.0.9/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= -github.com/mattn/go-sqlite3 v2.0.1+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= -github.com/mattn/go-zglob v0.0.1/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= -github.com/mholt/archiver/v3 v3.3.0/go.mod h1:YnQtqsp+94Rwd0D/rk5cnLrxusUBUXg+08Ebtr1Mqao= -github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= -github.com/mitchellh/ioprogress v0.0.0-20180201004757-6a23b12fa88e/go.mod h1:waEya8ee1Ro/lgxpVhkJI4BVASzkm3UZqkx/cFJiYHM= -github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A= -github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= -github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= -github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= -github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= -github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= -github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= -github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= -github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= -github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= -github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms= -github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= -github.com/nwaples/rardecode v1.0.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= -github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= -github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5 h1:58+kh9C6jJVXYjt8IE48G2eWl6BjwU5Gj0gqY84fy78= -github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= -github.com/olekukonko/tablewriter v0.0.4 h1:vHD/YYe1Wolo78koG299f7V/VAS08c6IpCLn+Ejf/w8= -github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA= -github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.11.0 h1:JAKSXpt1YjtLA7YpPiqO9ss6sNXEsPfSGdwN0UHqzrw= -github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= -github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.8.1 h1:C5Dqfs/LeauYDX0jJXIe2SWmwCbGzx9yF8C8xy3Lh34= -github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= -github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= -github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= -github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= -github.com/opencontainers/image-spec v1.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= -github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= -github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs= -github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= -github.com/openzipkin/zipkin-go v0.2.0/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= -github.com/otiai10/copy v1.0.2 h1:DDNipYy6RkIkjMwy+AWzgKiNTyj2RUI9yEMeETEpVyc= -github.com/otiai10/copy v1.0.2/go.mod h1:c7RpqBkwMom4bYTSkLSym4VSJz/XtncWRAj/J4PEIMY= -github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95 h1:+OLn68pqasWca0z5ryit9KGfp3sUsW4Lqg32iRMJyzs= -github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= -github.com/otiai10/curr v1.0.0 h1:TJIWdbX0B+kpNagQrjgq8bCMrbhiuX73M2XwgtDMoOI= -github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs= -github.com/otiai10/mint v1.3.0 h1:Ady6MKVezQwHBkGzLFbrsywyp09Ah7rkmfjV3Bcr5uc= -github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= -github.com/otiai10/mint v1.3.2 h1:VYWnrP5fXmz1MXvjuUvcBrXSjGE6xjON+axB/UrpO3E= -github.com/otiai10/mint v1.3.2/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= -github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= -github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pelletier/go-toml v1.6.0 h1:aetoXYr0Tv7xRU/V4B4IZJ2QcbtMUFoNb3ORp7TzIK4= -github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys= -github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= -github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= -github.com/pierrec/lz4 v0.0.0-20190327172049-315a67e90e41/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= -github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= -github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= -github.com/pierrec/lz4 v2.2.6+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= -github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= -github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= -github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= -github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= -github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= -github.com/prometheus/client_golang v1.5.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= -github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= -github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= -github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= -github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= -github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= -github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= -github.com/prometheus/procfs v0.0.10/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= -github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/qiniu/api.v7/v7 v7.5.0 h1:DY6NrIp6FZ1GP4Roc9hRnO2m+OLzASYNnvz5Mbgw1rk= -github.com/qiniu/api.v7/v7 v7.5.0/go.mod h1:VE5oC5rkE1xul0u1S2N0b2Uxq9/6hZzhyqjgK25XDcM= -github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= -github.com/rcrowley/go-metrics v0.0.0-20190706150252-9beb055b7962/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= -github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= -github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.3.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto= -github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= -github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U= -github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= -github.com/shurcooL/githubv4 v0.0.0-20190718010115-4ba037080260/go.mod h1:hAF0iLZy4td2EX+/8Tw+4nodhlMrwN3HupfaXj3zkGo= -github.com/shurcooL/githubv4 v0.0.0-20191102174205-af46314aec7b/go.mod h1:hAF0iLZy4td2EX+/8Tw+4nodhlMrwN3HupfaXj3zkGo= -github.com/shurcooL/graphql v0.0.0-20181231061246-d48a9a75455f/go.mod h1:AuYgA5Kyo4c7HfUmvRGs/6rGlMMV/6B1bVnB9JxJEEg= -github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= -github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I= -github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= -github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc= -github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= -github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= -github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8= -github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= -github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= -github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= -github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= -github.com/spf13/viper v1.6.2 h1:7aKfF+e8/k68gda3LOjo5RxiUqddoFxVq4BKBPrxk5E= -github.com/spf13/viper v1.6.2/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k= -github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI= -github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= -github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/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.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= -github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= -github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= -github.com/tektoncd/pipeline v0.11.0/go.mod h1:hlkH32S92+/UODROH0dmxzyuMxfRFp/Nc3e29MewLn8= -github.com/tektoncd/plumbing v0.0.0-20200217163359-cd0db6e567d2/go.mod h1:QZHgU07PRBTRF6N57w4+ApRu8OgfYLFNqCDlfEZaD9Y= -github.com/tektoncd/plumbing/pipelinerun-logs v0.0.0-20191206114338-712d544c2c21/go.mod h1:S62EUWtqmejjJgUMOGB1CCCHRp6C706laH06BoALkzU= -github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= -github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tongjingran/copy v1.4.2 h1:faPaod07yG6Z+o1B52Vu1KTvRb8il5VDNKLprC1BmsE= -github.com/tongjingran/copy v1.4.2/go.mod h1:Njma1OR5OuzB8pLAmQSzonHXzba+DDiPVmMSonpSpy4= -github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= -github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= -github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= -github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= -github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= -github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= -github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= -github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= -github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/vdemeester/k8s-pkg-credentialprovider v0.0.0-20200107171650-7c61ffa44238/go.mod h1:JwQJCMWpUDqjZrB5jpw0f5VbN7U95zxFy1ZDpoEarGo= -github.com/vdemeester/k8s-pkg-credentialprovider v1.13.12-1/go.mod h1:Fko0rTxEtDW2kju5Ky7yFJNS3IcNvW8IPsp4/e9oev0= -github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= -github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= -github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= -github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= -github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= -github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= -github.com/xeipuuv/gojsonschema v1.1.0/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= -github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= -github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -github.com/xlab/handysort v0.0.0-20150421192137-fb3537ed64a1/go.mod h1:QcJo0QPSfTONNIgpN5RA8prR7fF8nkF6cTWTcNerRO8= -github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= -github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= -github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= -go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= -go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= -go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= -go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= -go.opencensus.io v0.15.0/go.mod h1:UffZAU+4sDEINUGP/B7UfBBkq4fqLu9zXAX7ke6CHW0= -go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= -go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/atomic v1.5.1/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= -go.uber.org/multierr v1.4.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= -go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= -go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= -go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= -gocloud.dev v0.19.0/go.mod h1:SmKwiR8YwIMMJvQBKLsC3fHNyMwXLw3PMDO+VVteJMI= -golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073 h1:xMPOj6Pz6UipU1wXLkrtqpHbR0AVFnyPEQq/wRWz9lM= -golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190312203227-4b39c73a6495/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191002040644-a1355ae1e2c3/go.mod h1:NOZ3BPKG0ec/BKJQgnvsSFpcKLM5xXVWnvZS97DWHgE= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mobile v0.0.0-20190806162312-597adff16ade/go.mod h1:AlhUtkH4DA4asiFC5RgK7ZKmauvtkAVcy9L0epCzlWo= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190912160710-24e19bdeb0f2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190620070143-6f217b454f45/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190912141932-bc967efca4b8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 h1:uYVVQ9WP/Ds2ROhcaGPeIdVq0RIXVLwsHlnvJ+cT1So= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd h1:/e+gpKk9r3dJobndpTytxS2gOy6m5uvpg+ISQoEcusQ= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190422233926-fe54fb35175b/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= -golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= -golang.org/x/tools v0.0.0-20190807223507-b346f7fd45de/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190927191325-030b2cf1153e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191010171213-8abd42400456/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191112005509-a3f652f18032/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200115165105-de0b1760071a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200214144324-88be01311a71/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200303214625-2b0b585e22fe h1:Kh3iY7o/2bMfQXZdwLdL9jDMU1k9HoVn0P1mGCfoFLc= -golang.org/x/tools v0.0.0-20200303214625-2b0b585e22fe/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200730221956-1ac65761fe2c h1:c5JjBOQWM2pRemVbog00sS+oAdi8tTR+NNRFDwUOrTQ= -golang.org/x/tools v0.0.0-20200730221956-1ac65761fe2c/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gomodules.xyz/jsonpatch/v2 v2.0.1/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU= -gomodules.xyz/jsonpatch/v2 v2.1.0/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU= -gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= -gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= -gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ= -google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= -google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.5.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.6.0/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4= -google.golang.org/api v0.6.1-0.20190607001116-5213b8090861/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.10.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.2/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190508193815-b515fa19cec8/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= -google.golang.org/genproto v0.0.0-20190620144150-6af8c5fc6601/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= -google.golang.org/genproto v0.0.0-20190708153700-3bdd9d9f5532/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= -google.golang.org/genproto v0.0.0-20190716160619-c506a9f90610/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191009194640-548a555dbc03/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= -google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.19.1/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/gcfg.v1 v1.2.0/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= -gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= -gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/ini.v1 v1.46.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/ini.v1 v1.52.0 h1:j+Lt/M1oPPejkniCg1TkWE2J3Eh1oZTsHSXzMTzUXn4= -gopkg.in/ini.v1 v1.52.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/jcmturner/aescts.v1 v1.0.1/go.mod h1:nsR8qBOg+OucoIW+WMhB3GspUQXq9XorLnQb9XtvcOo= -gopkg.in/jcmturner/dnsutils.v1 v1.0.1/go.mod h1:m3v+5svpVOhtFAP/wSz+yzh4Mc0Fg7eRhxkJMWSIz9Q= -gopkg.in/jcmturner/gokrb5.v7 v7.2.3/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM= -gopkg.in/jcmturner/gokrb5.v7 v7.3.0/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM= -gopkg.in/jcmturner/rpc.v1 v1.1.0/go.mod h1:YIdkC4XfD6GXbzje11McwsDuOlZQSb9W4vfLvuNnlv8= -gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= -gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= -gopkg.in/robfig/cron.v2 v2.0.0-20150107220207-be2e0b0deed5/go.mod h1:hiOFpYm0ZJbusNj2ywpbrXowU3G8U6GIQzqn2mw1UIE= -gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= -gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98= -gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g= -gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/warnings.v0 v0.1.1/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= -gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= -gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20190709130402-674ba3eaed22/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= -helm.sh/helm/v3 v3.1.1/go.mod h1:WYsFJuMASa/4XUqLyv54s0U/f3mlAaRErGmyy4z921g= -honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.2/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -k8s.io/api v0.17.0/go.mod h1:npsyOePkeP0CPwyGfXDHxvypiYMJxBWAMpQxCaJ4ZxI= -k8s.io/api v0.17.2/go.mod h1:BS9fjjLc4CMuqfSO8vgbHPKMt5+SF0ET6u/RVDihTo4= -k8s.io/api v0.17.3/go.mod h1:YZ0OTkuw7ipbe305fMpIdf3GLXZKRigjtZaV5gzC2J0= -k8s.io/apiextensions-apiserver v0.17.2/go.mod h1:4KdMpjkEjjDI2pPfBA15OscyNldHWdBCfsWMDWAmSTs= -k8s.io/apimachinery v0.0.0-20190703205208-4cfb76a8bf76/go.mod h1:M2fZgZL9DbLfeJaPBCDqSqNsdsmLN+V29knYJnIXlMA= -k8s.io/apimachinery v0.17.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= -k8s.io/apimachinery v0.17.2/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= -k8s.io/apimachinery v0.17.3 h1:f+uZV6rm4/tHE7xXgLyToprg6xWairaClGVkm2t8omg= -k8s.io/apimachinery v0.17.3/go.mod h1:gxLnyZcGNdZTCLnq3fgzyg2A5BVCHTNDFrw8AmuJ+0g= -k8s.io/apiserver v0.17.0/go.mod h1:ABM+9x/prjINN6iiffRVNCBR2Wk7uY4z+EtEGZD48cg= -k8s.io/apiserver v0.17.2/go.mod h1:lBmw/TtQdtxvrTk0e2cgtOxHizXI+d0mmGQURIHQZlo= -k8s.io/cli-runtime v0.17.2/go.mod h1:aa8t9ziyQdbkuizkNLAw3qe3srSyWh9zlSB7zTqRNPI= -k8s.io/cli-runtime v0.17.3/go.mod h1:X7idckYphH4SZflgNpOOViSxetiMj6xI0viMAjM81TA= -k8s.io/client-go v0.17.0/go.mod h1:TYgR6EUHs6k45hb6KWjVD6jFZvJV4gHDikv/It0xz+k= -k8s.io/client-go v0.17.2/go.mod h1:QAzRgsa0C2xl4/eVpeVAZMvikCn8Nm81yqVx3Kk9XYI= -k8s.io/client-go v0.17.3/go.mod h1:cLXlTMtWHkuK4tD360KpWz2gG2KtdWEr/OT02i3emRQ= -k8s.io/client-go v9.0.0+incompatible/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s= -k8s.io/cloud-provider v0.17.0/go.mod h1:Ze4c3w2C0bRsjkBUoHpFi+qWe3ob1wI2/7cUn+YQIDE= -k8s.io/code-generator v0.17.1/go.mod h1:DVmfPQgxQENqDIzVR2ddLXMH34qeszkKSdH/N+s+38s= -k8s.io/code-generator v0.17.2/go.mod h1:DVmfPQgxQENqDIzVR2ddLXMH34qeszkKSdH/N+s+38s= -k8s.io/code-generator v0.17.3/go.mod h1:l8BLVwASXQZTo2xamW5mQNFCe1XPiAesVq7Y1t7PiQQ= -k8s.io/component-base v0.17.0/go.mod h1:rKuRAokNMY2nn2A6LP/MiwpoaMRHpfRnrPaUJJj1Yoc= -k8s.io/component-base v0.17.2/go.mod h1:zMPW3g5aH7cHJpKYQ/ZsGMcgbsA/VyhEugF3QT1awLs= -k8s.io/csi-translation-lib v0.17.0/go.mod h1:HEF7MEz7pOLJCnxabi45IPkhSsE/KmxPQksuCrHKWls= -k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= -k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= -k8s.io/gengo v0.0.0-20191108084044-e500ee069b5c/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= -k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/klog v0.3.1/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= -k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= -k8s.io/kube-openapi v0.0.0-20190228160746-b3a7cee44a30/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc= -k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= -k8s.io/kubectl v0.17.2/go.mod h1:y4rfLV0n6aPmvbRCqZQjvOp3ezxsFgpqL+zF5jH/lxk= -k8s.io/kubernetes v1.13.0 h1:qTfB+u5M92k2fCCCVP2iuhgwwSOv1EkAkvQY1tQODD8= -k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= -k8s.io/legacy-cloud-providers v0.17.0/go.mod h1:DdzaepJ3RtRy+e5YhNtrCYwlgyK87j/5+Yfp0L9Syp8= -k8s.io/metrics v0.17.2/go.mod h1:3TkNHET4ROd+NfzNxkjoVfQ0Ob4iZnaHmSEA4vYpwLw= -k8s.io/test-infra v0.0.0-20200511080351-8ac9dbfab055 h1:tdigZYWTCLlgNqogEip0dS2hF7bdxnobwuwX73mmXQk= -k8s.io/test-infra v0.0.0-20200511080351-8ac9dbfab055/go.mod h1:bW6thaPZfL2hW7ecjx2WYwlP9KQLM47/xIJyttkVk5s= -k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= -knative.dev/caching v0.0.0-20200116200605-67bca2c83dfa/go.mod h1:dHXFU6CGlLlbzaWc32g80cR92iuBSpsslDNBWI8C7eg= -knative.dev/eventing-contrib v0.11.2/go.mod h1:SnXZgSGgMSMLNFTwTnpaOH7hXDzTFtw0J8OmHflNx3g= -knative.dev/pkg v0.0.0-20200207155214-fef852970f43/go.mod h1:pgODObA1dTyhNoFxPZTTjNWfx6F0aKsKzn+vaT9XO/Q= -modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= -modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= -modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= -modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= -modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= -mvdan.cc/xurls/v2 v2.0.0/go.mod h1:2/webFPYOXN9jp/lzuj0zuAVlF+9g4KPFJANH1oJhRU= -pack.ag/amqp v0.11.0/go.mod h1:4/cbmt4EJXSKlG6LCfWHoqmN0uFdy5i/+YFz+fTfhV4= -pack.ag/amqp v0.11.2/go.mod h1:4/cbmt4EJXSKlG6LCfWHoqmN0uFdy5i/+YFz+fTfhV4= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/letsencrypt v0.0.3/go.mod h1:buyQKZ6IXrRnB7TdkHP0RyEybLx18HHyOSoTyoOLqNY= -sigs.k8s.io/controller-runtime v0.5.0/go.mod h1:REiJzC7Y00U+2YkMbT8wxgrsX5USpXKGhb2sCtAXiT8= -sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU= -sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= -sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= -sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= -sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= -vbom.ml/util v0.0.0-20160121211510-db5cfe13f5cc/go.mod h1:so/NYdZXCz+E3ZpW0uAoCj6uzU2+8OWDFv/HxUSs7kI= -vbom.ml/util v0.0.0-20180919145318-efcd4e0f9787/go.mod h1:so/NYdZXCz+E3ZpW0uAoCj6uzU2+8OWDFv/HxUSs7kI= diff --git a/goc.go b/goc.go deleted file mode 100644 index 4ffade7..0000000 --- a/goc.go +++ /dev/null @@ -1,23 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.com) - - 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 "github.com/qiniu/goc/cmd" - -func main() { - cmd.Execute() -} diff --git a/pkg/build/build.go b/pkg/build/build.go deleted file mode 100644 index 4fcbe40..0000000 --- a/pkg/build/build.go +++ /dev/null @@ -1,168 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.com) - - 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 build - -import ( - "fmt" - "os" - "os/exec" - "path/filepath" - "strings" - - "github.com/qiniu/goc/pkg/cover" - log "github.com/sirupsen/logrus" -) - -// Build is to describe the building/installing process of a goc build/install -type Build struct { - Pkgs map[string]*cover.Package // Pkg list parsed from "go list -json ./..." command - NewGOPATH string // the new GOPATH - OriGOPATH string // the original GOPATH - WorkingDir string // the working directory - TmpDir string // the temporary directory to build the project - TmpWorkingDir string // the working directory in the temporary directory, which is corresponding to the current directory in the project directory - IsMod bool // determine whether it is a Mod project - Root string - // go 1.11, go 1.12 has no Root - // Project Root: - // 1. legacy, root == GOPATH - // 2. mod, root == go.mod Dir - ModRoot string // path for go.mod - ModRootPath string // import path for the whole project - Target string // the binary name that go build generate - // keep compatible with go commands: - // go run [build flags] [-exec xprog] package [arguments...] - // go build [-o output] [-i] [build flags] [packages] - // go install [-i] [build flags] [packages] - BuildFlags string // Build flags - Packages string // Packages that needs to build - GoRunExecFlag string // for the -exec flags in go run command - GoRunArguments string // for the '[arguments]' parameters in go run command - - OneMainPackage bool // whether this build is a go build or go install? true: build, false: install - GlobalCoverVarImportPath string // Importpath for storing cover variables - GlobalCoverVarFilePath string // Importpath for storing cover variables -} - -// NewBuild creates a Build struct which can build from goc temporary directory, -// and generate binary in current working directory -func NewBuild(buildflags string, args []string, workingDir string, outputDir string) (*Build, error) { - if err := checkParameters(args, workingDir); err != nil { - return nil, err - } - // buildflags = buildflags + " -o " + outputDir - b := &Build{ - BuildFlags: buildflags, - Packages: strings.Join(args, " "), - WorkingDir: workingDir, - } - if false == b.validatePackageForBuild() { - log.Errorln(ErrWrongPackageTypeForBuild) - return nil, ErrWrongPackageTypeForBuild - } - if err := b.MvProjectsToTmp(); err != nil { - return nil, err - } - dir, err := b.determineOutputDir(outputDir) - b.Target = dir - if err != nil { - return nil, err - } - return b, nil -} - -// Build calls 'go build' tool to do building -func (b *Build) Build() error { - log.Infoln("Go building in temp...") - // new -o will overwrite previous ones - b.BuildFlags = b.BuildFlags + " -o " + b.Target - cmd := exec.Command("/bin/bash", "-c", "go build "+b.BuildFlags+" "+b.Packages) - cmd.Dir = b.TmpWorkingDir - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - - if b.NewGOPATH != "" { - // Change to temp GOPATH for go install command - cmd.Env = append(os.Environ(), fmt.Sprintf("GOPATH=%v", b.NewGOPATH)) - } - - log.Printf("go build cmd is: %v", cmd.Args) - err := cmd.Start() - if err != nil { - return fmt.Errorf("fail to execute: %v, err: %w", cmd.Args, err) - } - if err = cmd.Wait(); err != nil { - return fmt.Errorf("fail to execute: %v, err: %w", cmd.Args, err) - } - log.Infoln("Go build exit successful.") - return nil -} - -// determineOutputDir, as we only allow . as package name, -// the binary name is always same as the directory name of current directory -func (b *Build) determineOutputDir(outputDir string) (string, error) { - if b.TmpDir == "" { - return "", fmt.Errorf("can only be called after Build.MvProjectsToTmp(): %w", ErrEmptyTempWorkingDir) - } - - // fix #43 - if outputDir != "" { - abs, err := filepath.Abs(outputDir) - if err != nil { - return "", fmt.Errorf("Fail to transform the path: %v to absolute path: %v", outputDir, err) - - } - return abs, nil - } - // fix #43 - // use target name from `go list -json ./...` of the main module - targetName := "" - for _, pkg := range b.Pkgs { - if pkg.Name == "main" { - if pkg.Target != "" { - targetName = filepath.Base(pkg.Target) - } else { - targetName = filepath.Base(pkg.Dir) - } - break - } - } - - return filepath.Join(b.WorkingDir, targetName), nil -} - -// validatePackageForBuild only allow . as package name -func (b *Build) validatePackageForBuild() bool { - if b.Packages == "." || b.Packages == "" { - return true - } - return false -} - -func checkParameters(args []string, workingDir string) error { - if len(args) > 1 { - log.Errorln(ErrTooManyArgs) - return ErrTooManyArgs - } - - if workingDir == "" { - return ErrInvalidWorkingDir - } - - log.Infof("Working directory: %v", workingDir) - return nil -} diff --git a/pkg/build/build_test.go b/pkg/build/build_test.go deleted file mode 100644 index 3237277..0000000 --- a/pkg/build/build_test.go +++ /dev/null @@ -1,101 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.com) - - 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 build - -import ( - "errors" - "fmt" - "os" - "path/filepath" - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestInvalidPackage(t *testing.T) { - - workingDir := filepath.Join(baseDir, "../../tests/samples/simple_project") - gopath := "" - - os.Setenv("GOPATH", gopath) - os.Setenv("GO111MODULE", "on") - - _, err := NewBuild("", []string{"example.com/simple-project"}, workingDir, "") - if !assert.Equal(t, err, ErrWrongPackageTypeForBuild) { - assert.FailNow(t, "the package name should be invalid") - } -} - -func TestBasicBuildForModProject(t *testing.T) { - workingDir := filepath.Join(baseDir, "../../tests/samples/simple_project") - gopath := "" - - os.Setenv("GOPATH", gopath) - os.Setenv("GO111MODULE", "on") - fmt.Println(workingDir) - buildFlags, args, buildOutput := "", []string{"."}, "" - gocBuild, err := NewBuild(buildFlags, args, workingDir, buildOutput) - if !assert.Equal(t, err, nil) { - assert.FailNow(t, "should create temporary directory successfully") - } - - err = gocBuild.Build() - if !assert.Equal(t, err, nil) { - assert.FailNow(t, "temporary directory should build successfully") - } -} - -func TestCheckParameters(t *testing.T) { - err := checkParameters([]string{"aa", "bb"}, "aa") - assert.Equal(t, err, ErrTooManyArgs, "too many arguments should failed") - - err = checkParameters([]string{"aa"}, "") - assert.Equal(t, err, ErrInvalidWorkingDir, "empty working directory should failed") -} - -func TestDetermineOutputDir(t *testing.T) { - b := &Build{} - _, err := b.determineOutputDir("") - assert.Equal(t, errors.Is(err, ErrEmptyTempWorkingDir), true, "called before Build.MvProjectsToTmp() should fail") - - b.TmpDir = "fake" - _, err = b.determineOutputDir("xx") - assert.Equal(t, err, nil, "should return a directory") -} - -func TestInvalidPackageNameForBuild(t *testing.T) { - workingDir := filepath.Join(baseDir, "../../tests/samples/simple_project") - gopath := filepath.Join(baseDir, "../../tests/samples/simple_project", "testhome") - - os.Setenv("GOPATH", gopath) - os.Setenv("GO111MODULE", "on") - - buildFlags, packages := "", []string{"main.go"} - _, err := NewBuild(buildFlags, packages, workingDir, "") - if !assert.Equal(t, err, ErrWrongPackageTypeForBuild) { - assert.FailNow(t, "should not success with non . or ./... package") - } -} - -// test NewBuild with wrong parameters -func TestNewBuildWithWrongParameters(t *testing.T) { - _, err := NewBuild("", []string{"a.go", "b.go"}, "cur", "cur") - assert.Equal(t, err, ErrTooManyArgs) - - _, err = NewBuild("", []string{"a.go"}, "", "cur") - assert.Equal(t, err, ErrInvalidWorkingDir) -} diff --git a/pkg/build/errors.go b/pkg/build/errors.go deleted file mode 100644 index e0376bd..0000000 --- a/pkg/build/errors.go +++ /dev/null @@ -1,24 +0,0 @@ -package build - -import ( - "errors" -) - -var ( - // ErrShouldNotReached represents the logic should not be reached in normal flow - ErrShouldNotReached = errors.New("should never be reached") - // ErrGocShouldExecInProject represents goc currently not support for the project - ErrGocShouldExecInProject = errors.New("goc not support for such project directory") - // ErrWrongPackageTypeForInstall represents goc install command only support limited arguments - ErrWrongPackageTypeForInstall = errors.New("packages only support \".\" and \"./...\"") - // ErrWrongPackageTypeForBuild represents goc build command only support limited arguments - ErrWrongPackageTypeForBuild = errors.New("packages only support \".\"") - // ErrTooManyArgs represents goc CLI only support limited arguments - ErrTooManyArgs = errors.New("too many args") - // ErrInvalidWorkingDir represents the working directory is invalid - ErrInvalidWorkingDir = errors.New("the working directory is invalid") - // ErrEmptyTempWorkingDir represent the error that temporary working directory is empty - ErrEmptyTempWorkingDir = errors.New("temporary working directory is empty") - // ErrNoPlaceToInstall represents the err that no place to install the generated binary - ErrNoPlaceToInstall = errors.New("don't know where to install") -) diff --git a/pkg/build/gomodules.go b/pkg/build/gomodules.go deleted file mode 100644 index 82081f7..0000000 --- a/pkg/build/gomodules.go +++ /dev/null @@ -1,90 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.com) - - 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 build - -import ( - "io/ioutil" - "path/filepath" - - log "github.com/sirupsen/logrus" - "github.com/tongjingran/copy" - "golang.org/x/mod/modfile" -) - -func (b *Build) cpGoModulesProject() { - for _, v := range b.Pkgs { - if v.Name == "main" { - dst := b.TmpDir - src := v.Module.Dir - - if err := copy.Copy(src, dst, copy.Options{Skip: skipCopy}); err != nil { - log.Errorf("Failed to Copy the folder from %v to %v, the error is: %v ", src, dst, err) - } - break - } else { - continue - } - } -} - -// updateGoModFile rewrites the go.mod file in the temporary directory, -// if it has a 'replace' directive, and the directive has a relative local path -// it will be rewritten with a absolute path. -// ex. -// suppose original project is located at /path/to/aa/bb/cc, go.mod contains a directive: -// 'replace github.com/qiniu/bar => ../home/foo/bar' -// after the project is copied to temporary directory, it should be rewritten as -// 'replace github.com/qiniu/bar => /path/to/aa/bb/home/foo/bar' -func (b *Build) updateGoModFile() (updateFlag bool, newModFile []byte, err error) { - tempModfile := filepath.Join(b.TmpDir, "go.mod") - buf, err := ioutil.ReadFile(tempModfile) - if err != nil { - return - } - oriGoModFile, err := modfile.Parse(tempModfile, buf, nil) - if err != nil { - return - } - - updateFlag = false - for index := range oriGoModFile.Replace { - replace := oriGoModFile.Replace[index] - oldPath := replace.Old.Path - oldVersion := replace.Old.Version - newPath := replace.New.Path - newVersion := replace.New.Version - // replace to a local filesystem does not have a version - // absolute path no need to rewrite - if newVersion == "" && !filepath.IsAbs(newPath) { - var absPath string - fullPath := filepath.Join(b.ModRoot, newPath) - absPath, _ = filepath.Abs(fullPath) - // DropReplace & AddReplace will not return error - // so no need to check the error - _ = oriGoModFile.DropReplace(oldPath, oldVersion) - _ = oriGoModFile.AddReplace(oldPath, oldVersion, absPath, newVersion) - updateFlag = true - } - } - oriGoModFile.Cleanup() - // Format will not return error, so ignore the returned error - // func (f *File) Format() ([]byte, error) { - // return Format(f.Syntax), nil - // } - newModFile, _ = oriGoModFile.Format() - return -} diff --git a/pkg/build/gomodules_test.go b/pkg/build/gomodules_test.go deleted file mode 100644 index e0e6a6d..0000000 --- a/pkg/build/gomodules_test.go +++ /dev/null @@ -1,103 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.com) - - 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 build - -import ( - "bytes" - "errors" - "os" - "path/filepath" - "strings" - "testing" - - "github.com/qiniu/goc/pkg/cover" - log "github.com/sirupsen/logrus" - "github.com/stretchr/testify/assert" -) - -func captureOutput(f func()) string { - var buf bytes.Buffer - log.SetOutput(&buf) - f() - log.SetOutput(os.Stderr) - return buf.String() -} - -// copy in cpGoModulesProject of invalid src, dst name -func TestModProjectCopyWithUnexistedDir(t *testing.T) { - pkgs := make(map[string]*cover.Package) - pkgs["main"] = &cover.Package{ - Name: "main", - Module: &cover.ModulePublic{ - Dir: "not exied, ia mas duser", // not real one, should fail copy - }, - } - pkgs["another"] = &cover.Package{} - b := &Build{ - TmpDir: "sdfsfev2234444", // not real one, should fail copy - Pkgs: pkgs, - } - - output := captureOutput(b.cpGoModulesProject) - assert.Equal(t, strings.Contains(output, "Failed to Copy"), true) -} - -// test go mod file udpate -func TestUpdateModFileIfContainsReplace(t *testing.T) { - workingDir := filepath.Join(baseDir, "../../tests/samples/gomod_samples/a") - b := &Build{ - TmpDir: workingDir, - ModRoot: "/aa/bb/cc", - } - - // replace with relative local file path should be rewrite - updated, newmod, err := b.updateGoModFile() - assert.Equal(t, err, nil) - assert.Equal(t, updated, true) - assert.Contains(t, string(newmod), "replace github.com/qiniu/bar => /aa/bb/home/foo/bar") - - // old replace should be removed - assert.NotContains(t, string(newmod), "github.com/qiniu/bar => ../home/foo/bar") - - // normal replace should not be rewrite - assert.Contains(t, string(newmod), "github.com/qiniu/bar2 => github.com/baniu/bar3 v1.2.3") -} - -// test wrong go mod file -func TestWithWrongGoModFile(t *testing.T) { - // go.mod not exist - workingDir := filepath.Join(baseDir, "../../tests/samples/xxxxxxxxxxxx/a") - b := &Build{ - TmpDir: workingDir, - ModRoot: "/aa/bb/cc", - } - - updated, _, err := b.updateGoModFile() - assert.Equal(t, errors.Is(err, os.ErrNotExist), true) - assert.Equal(t, updated, false) - - // a wrong format go mod - workingDir = filepath.Join(baseDir, "../../tests/samples/gomod_samples/b") - b = &Build{ - TmpDir: workingDir, - ModRoot: "/aa/bb/cc", - } - - updated, _, err = b.updateGoModFile() - assert.NotEqual(t, err, nil) - assert.Equal(t, updated, false) -} diff --git a/pkg/build/install.go b/pkg/build/install.go deleted file mode 100644 index b5cb823..0000000 --- a/pkg/build/install.go +++ /dev/null @@ -1,87 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.com) - - 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 build - -import ( - "fmt" - "os" - "os/exec" - "strings" - - log "github.com/sirupsen/logrus" -) - -// NewInstall creates a Build struct which can install from goc temporary directory -func NewInstall(buildflags string, args []string, workingDir string) (*Build, error) { - if err := checkParameters(args, workingDir); err != nil { - return nil, err - } - b := &Build{ - BuildFlags: buildflags, - Packages: strings.Join(args, " "), - WorkingDir: workingDir, - } - if false == b.validatePackageForInstall() { - log.Errorln(ErrWrongPackageTypeForInstall) - return nil, ErrWrongPackageTypeForInstall - } - if err := b.MvProjectsToTmp(); err != nil { - return nil, err - } - return b, nil -} - -// Install use the 'go install' tool to install packages -func (b *Build) Install() error { - log.Println("Go building in temp...") - cmd := exec.Command("/bin/bash", "-c", "go install "+b.BuildFlags+" "+b.Packages) - cmd.Dir = b.TmpWorkingDir - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - - whereToInstall, err := b.findWhereToInstall() - if err != nil { - // ignore the err - log.Errorf("No place to install: %v", err) - } - // Change the temp GOBIN, to force binary install to original place - cmd.Env = append(os.Environ(), fmt.Sprintf("GOBIN=%v", whereToInstall)) - if b.NewGOPATH != "" { - // Change to temp GOPATH for go install command - cmd.Env = append(cmd.Env, fmt.Sprintf("GOPATH=%v", b.NewGOPATH)) - } - - log.Infof("go install cmd is: %v", cmd.Args) - err = cmd.Start() - if err != nil { - log.Errorf("Fail to execute: %v. The error is: %v", cmd.Args, err) - return err - } - if err = cmd.Wait(); err != nil { - log.Errorf("go install failed. The error is: %v", err) - return err - } - log.Infof("Go install successful. Binary installed in: %v", whereToInstall) - return nil -} - -func (b *Build) validatePackageForInstall() bool { - if b.Packages == "." || b.Packages == "" || b.Packages == "./..." { - return true - } - return false -} diff --git a/pkg/build/install_test.go b/pkg/build/install_test.go deleted file mode 100644 index 30e996b..0000000 --- a/pkg/build/install_test.go +++ /dev/null @@ -1,42 +0,0 @@ -package build - -import ( - "os" - "path/filepath" - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestBasicInstallForModProject(t *testing.T) { - workingDir := filepath.Join(baseDir, "../../tests/samples/simple_project") - gopath := filepath.Join(baseDir, "../../tests/samples/simple_project", "testhome") - - os.Setenv("GOPATH", gopath) - os.Setenv("GO111MODULE", "on") - - buildFlags, packages := "", []string{"."} - gocBuild, err := NewInstall(buildFlags, packages, workingDir) - if !assert.Equal(t, err, nil) { - assert.FailNow(t, "should create temporary directory successfully") - } - - err = gocBuild.Install() - if !assert.Equal(t, err, nil) { - assert.FailNow(t, "temporary directory should build successfully") - } -} - -func TestInvalidPackageNameForInstall(t *testing.T) { - workingDir := filepath.Join(baseDir, "../../tests/samples/simple_project") - gopath := filepath.Join(baseDir, "../../tests/samples/simple_project", "testhome") - - os.Setenv("GOPATH", gopath) - os.Setenv("GO111MODULE", "on") - - buildFlags, packages := "", []string{"main.go"} - _, err := NewInstall(buildFlags, packages, workingDir) - if !assert.Equal(t, err, ErrWrongPackageTypeForInstall) { - assert.FailNow(t, "should not success with non . or ./... package") - } -} diff --git a/pkg/build/legacy.go b/pkg/build/legacy.go deleted file mode 100644 index 5e20d68..0000000 --- a/pkg/build/legacy.go +++ /dev/null @@ -1,104 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.com) - - 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 build - -import ( - "os" - "path/filepath" - "strings" - - log "github.com/sirupsen/logrus" - - "github.com/qiniu/goc/pkg/cover" - "github.com/tongjingran/copy" -) - -func (b *Build) cpLegacyProject() { - visited := make(map[string]bool) - for k, v := range b.Pkgs { - dst := filepath.Join(b.TmpDir, "src", k) - src := v.Dir - - if _, ok := visited[src]; ok { - // Skip if already copied - continue - } - - if err := copy.Copy(src, dst, copy.Options{Skip: skipCopy}); err != nil { - log.Errorf("Failed to Copy the folder from %v to %v, the error is: %v ", src, dst, err) - } - - visited[src] = true - - b.cpDepPackages(v, visited) - } -} - -// only cp dependency in root(current gopath), -// skip deps in other GOPATHs -func (b *Build) cpDepPackages(pkg *cover.Package, visited map[string]bool) { - gopath := pkg.Root - for _, dep := range pkg.Deps { - src := filepath.Join(gopath, "src", dep) - // Check if copied - if _, ok := visited[src]; ok { - // Skip if already copied - continue - } - // Check if we can found in the root gopath - _, err := os.Stat(src) - if err != nil { - continue - } - - dst := filepath.Join(b.TmpDir, "src", dep) - - if err := copy.Copy(src, dst, copy.Options{Skip: skipCopy}); err != nil { - log.Errorf("Failed to Copy the folder from %v to %v, the error is: %v ", src, dst, err) - } - - visited[src] = true - } -} - -func (b *Build) cpNonStandardLegacy() { - for _, v := range b.Pkgs { - if v.Name == "main" { - dst := b.TmpDir - src := v.Dir - - if err := copy.Copy(src, dst, copy.Options{Skip: skipCopy}); err != nil { - log.Printf("Failed to Copy the folder from %v to %v, the error is: %v ", src, dst, err) - } - break - } - } -} - -// skipCopy skip copy .git dir and irregular files -func skipCopy(src string, info os.FileInfo) (bool, error) { - irregularModeType := os.ModeNamedPipe | os.ModeSocket | os.ModeDevice | os.ModeCharDevice | os.ModeIrregular - if strings.HasSuffix(src, "/.git") { - log.Infof("Skip .git dir [%s]", src) - return true, nil - } - if info.Mode()&irregularModeType != 0 { - log.Warnf("Skip file [%s], the file mode is [%s]", src, info.Mode().String()) - return true, nil - } - return false, nil -} diff --git a/pkg/build/legacy_test.go b/pkg/build/legacy_test.go deleted file mode 100644 index ae2e5cc..0000000 --- a/pkg/build/legacy_test.go +++ /dev/null @@ -1,133 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.com) - - 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 build - -import ( - "os" - "path/filepath" - "strings" - "testing" - "time" - - "github.com/qiniu/goc/pkg/cover" - "github.com/stretchr/testify/assert" -) - -// copy in cpLegacyProject/cpNonStandardLegacy of invalid src, dst name -func TestLegacyProjectCopyWithUnexistedDir(t *testing.T) { - pkgs := make(map[string]*cover.Package) - pkgs["main"] = &cover.Package{ - Module: &cover.ModulePublic{ - Dir: "not exied, ia mas duser", // not real one, should fail copy - }, - Dir: "not exit, iasdfs", - Name: "main", - } - pkgs["another"] = &cover.Package{} - b := &Build{ - TmpDir: "sdfsfev2234444", // not real one, should fail copy - Pkgs: pkgs, - } - - output := captureOutput(b.cpLegacyProject) - assert.Equal(t, strings.Contains(output, "Failed to Copy"), true) - - output = captureOutput(b.cpNonStandardLegacy) - assert.Equal(t, strings.Contains(output, "Failed to Copy"), true) -} - -// copy in cpDepPackages of invalid dst name -func TestDepPackagesCopyWithInvalidDir(t *testing.T) { - gopath := filepath.Join(baseDir, "../../tests/samples/simple_gopath_project") - pkg := &cover.Package{ - Module: &cover.ModulePublic{ - Dir: "not exied, ia mas duser", - }, - Root: gopath, - Deps: []string{"qiniu.com", "ddfee 2344234"}, - } - b := &Build{ - TmpDir: "/", // "/" is invalid dst in Linux, it should fail - } - - output := captureOutput(func() { - visited := make(map[string]bool) - - b.cpDepPackages(pkg, visited) - }) - assert.Equal(t, strings.Contains(output, "Failed to Copy"), true) -} - -type MockFile struct { - name string - size int64 - mode os.FileMode - modTime time.Time - isDir bool -} - -func (m MockFile) Name() string { - return m.name -} - -func (m MockFile) Size() int64 { - return m.size -} - -func (m MockFile) Mode() os.FileMode { - return m.mode -} - -func (m MockFile) ModTime() time.Time { - return m.modTime -} - -func (m MockFile) IsDir() bool { - return m.isDir -} - -func (m MockFile) Sys() interface{} { - return nil -} - -// skipCopy verify -func TestSkipCopy(t *testing.T) { - testCases := map[string]struct { - inputSrc string - inputInfo MockFile - expected bool - }{ - "src with /.git suffix": {inputSrc: "/test/.git", inputInfo: MockFile{mode: 0}, expected: true}, - "src with ./git suffix": {inputSrc: "/test.git", inputInfo: MockFile{mode: 0}, expected: false}, - "src with /.gita suffix": {inputSrc: "/test/.gita", inputInfo: MockFile{mode: 0}, expected: false}, - "src with /.git in middle": {inputSrc: "/test/.git/test", inputInfo: MockFile{mode: 0}, expected: false}, - "irregular file": {inputSrc: "/test", inputInfo: MockFile{mode: os.ModeIrregular}, expected: true}, - "dir file": {inputSrc: "/test", inputInfo: MockFile{isDir: true, mode: os.ModeDir}, expected: false}, - "temporary file": {inputSrc: "/test", inputInfo: MockFile{mode: os.ModeTemporary}, expected: false}, - "symlink file": {inputSrc: "/test", inputInfo: MockFile{mode: os.ModeSymlink}, expected: false}, - "device file": {inputSrc: "/test", inputInfo: MockFile{mode: os.ModeDevice}, expected: true}, - "named pipe file": {inputSrc: "/test", inputInfo: MockFile{mode: os.ModeNamedPipe}, expected: true}, - "socket file": {inputSrc: "/test", inputInfo: MockFile{mode: os.ModeSocket}, expected: true}, - } - for name, tc := range testCases { - t.Run(name, func(t *testing.T) { - output, err := skipCopy(tc.inputSrc, tc.inputInfo) - assert.NoError(t, err) - assert.Equal(t, output, tc.expected) - }) - } -} diff --git a/pkg/build/run.go b/pkg/build/run.go deleted file mode 100644 index 1a59219..0000000 --- a/pkg/build/run.go +++ /dev/null @@ -1,50 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.com) - - 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 build - -import ( - "fmt" - "os" - "os/exec" - - log "github.com/sirupsen/logrus" -) - -// Run excutes the main package in addition with the internal goc features -func (b *Build) Run() error { - cmd := exec.Command("/bin/bash", "-c", "go run "+b.BuildFlags+" "+b.GoRunExecFlag+" "+b.Packages+" "+b.GoRunArguments) - cmd.Dir = b.TmpWorkingDir - - if b.NewGOPATH != "" { - // Change to temp GOPATH for go install command - cmd.Env = append(os.Environ(), fmt.Sprintf("GOPATH=%v", b.NewGOPATH)) - } - - log.Infof("go build cmd is: %v", cmd.Args) - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - err := cmd.Start() - if err != nil { - return fmt.Errorf("fail to execute: %v, err: %w", cmd.Args, err) - } - - if err = cmd.Wait(); err != nil { - return fmt.Errorf("fail to execute: %v, err: %w", cmd.Args, err) - } - - return nil -} diff --git a/pkg/build/tmpfolder.go b/pkg/build/tmpfolder.go deleted file mode 100644 index 89b6ea2..0000000 --- a/pkg/build/tmpfolder.go +++ /dev/null @@ -1,212 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.com) - - 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 build - -import ( - "crypto/sha256" - "errors" - "fmt" - "io/ioutil" - "os" - "path/filepath" - "strings" - - "github.com/qiniu/goc/pkg/cover" - log "github.com/sirupsen/logrus" - "github.com/spf13/viper" -) - -// MvProjectsToTmp moves the projects into a temporary directory -func (b *Build) MvProjectsToTmp() error { - listArgs := []string{"-json"} - if len(b.BuildFlags) != 0 { - listArgs = append(listArgs, b.BuildFlags) - } - listArgs = append(listArgs, "./...") - var err error - b.Pkgs, err = cover.ListPackages(b.WorkingDir, strings.Join(listArgs, " "), "") - if err != nil { - log.Errorln(err) - return err - } - - err = b.mvProjectsToTmp() - if err != nil { - log.Errorf("Fail to move the project to temporary directory") - return err - } - b.OriGOPATH = os.Getenv("GOPATH") - if b.IsMod == true { - b.NewGOPATH = "" - } else if b.OriGOPATH == "" { - b.NewGOPATH = b.TmpDir - } else { - b.NewGOPATH = fmt.Sprintf("%v:%v", b.TmpDir, b.OriGOPATH) - } - // fix #14: unable to build project not in GOPATH in legacy mode - // this kind of project does not have a pkg.Root value - // go 1.11, 1.12 has no pkg.Root, - // so add b.IsMod == false as secondary judgement - if b.Root == "" && b.IsMod == false { - b.NewGOPATH = b.OriGOPATH - } - log.Infof("New GOPATH: %v", b.NewGOPATH) - return nil -} - -func (b *Build) mvProjectsToTmp() error { - b.TmpDir = filepath.Join(os.TempDir(), tmpFolderName(b.WorkingDir)) - - // Delete previous tmp folder and its content - os.RemoveAll(b.TmpDir) - // Create a new tmp folder and a new importpath for storing cover variables - b.GlobalCoverVarImportPath = filepath.Join("src", tmpPackageName(b.WorkingDir)) - err := os.MkdirAll(filepath.Join(b.TmpDir, b.GlobalCoverVarImportPath), os.ModePerm) - if err != nil { - return fmt.Errorf("Fail to create the temporary build directory. The err is: %v", err) - } - log.Infof("Tmp project generated in: %v", b.TmpDir) - - // traverse pkg list to get project meta info - b.IsMod, b.Root, err = b.traversePkgsList() - log.Infof("mod project? %v", b.IsMod) - if errors.Is(err, ErrShouldNotReached) { - return fmt.Errorf("mvProjectsToTmp with a empty project: %w", err) - } - // we should get corresponding working directory in temporary directory - b.TmpWorkingDir, err = b.getTmpwd() - if err != nil { - return fmt.Errorf("getTmpwd failed with error: %w", err) - } - // issue #14 - // if b.Root == "", then the project is non-standard project - // known cases: - // 1. a legacy project, but not in any GOPATH, will cause the b.Root == "" - if b.IsMod == false && b.Root != "" { - b.cpLegacyProject() - } else if b.IsMod == true { // go 1.11, 1.12 has no Build.Root - b.cpGoModulesProject() - updated, newGoModContent, err := b.updateGoModFile() - if err != nil { - return fmt.Errorf("fail to generate new go.mod: %v", err) - } - if updated { - log.Infoln("go.mod needs rewrite") - tmpModFile := filepath.Join(b.TmpDir, "go.mod") - err := ioutil.WriteFile(tmpModFile, newGoModContent, os.ModePerm) - if err != nil { - return fmt.Errorf("fail to update go.mod: %v", err) - } - } - } else if b.IsMod == false && b.Root == "" { - b.TmpWorkingDir = b.TmpDir - b.cpNonStandardLegacy() - } - - log.Infof("New workingdir in tmp directory in: %v", b.TmpWorkingDir) - return nil -} - -// tmpFolderName uses the first six characters of the input path's SHA256 checksum -// as the suffix. -func tmpFolderName(path string) string { - sum := sha256.Sum256([]byte(path)) - h := fmt.Sprintf("%x", sum[:6]) - - return "goc-build-" + h -} - -// tmpPackageName uses the first six characters of the input path's SHA256 checksum -// as the suffix. -func tmpPackageName(path string) string { - sum := sha256.Sum256([]byte(path)) - h := fmt.Sprintf("%x", sum[:6]) - - return "gocbuild" + h -} - -// traversePkgsList travse the Build.Pkgs list -// return Build.IsMod, tell if the project is a mod project -// return Build.Root: -// 1. the project root if it is a mod project, -// 2. current GOPATH if it is a legacy project, -// 3. some non-standard project, which Build.IsMod == false, Build.Root == nil -func (b *Build) traversePkgsList() (isMod bool, root string, err error) { - for _, v := range b.Pkgs { - // get root - root = v.Root - if v.Module == nil { - return - } - isMod = true - b.ModRoot = v.Module.Dir - b.ModRootPath = v.Module.Path - return - } - log.Error(ErrShouldNotReached) - err = ErrShouldNotReached - return -} - -// getTmpwd get the corresponding working directory in the temporary working directory -// and store it in the Build.tmpWorkdingDir -func (b *Build) getTmpwd() (string, error) { - for _, pkg := range b.Pkgs { - var index int - var parentPath string - if b.IsMod == false { - index = strings.Index(b.WorkingDir, pkg.Root) - parentPath = pkg.Root - } else { - index = strings.Index(b.WorkingDir, pkg.Module.Dir) - parentPath = pkg.Module.Dir - } - - if index == -1 { - return "", ErrGocShouldExecInProject - } - // b.TmpWorkingDir = filepath.Join(b.TmpDir, path[len(parentPath):]) - return filepath.Join(b.TmpDir, b.WorkingDir[len(parentPath):]), nil - } - - return "", ErrShouldNotReached -} - -func (b *Build) findWhereToInstall() (string, error) { - if GOBIN := os.Getenv("GOBIN"); GOBIN != "" { - return GOBIN, nil - } - - if false == b.IsMod { - if b.Root == "" { - return "", ErrNoPlaceToInstall - } - return filepath.Join(b.Root, "bin"), nil - } - if b.OriGOPATH != "" { - return filepath.Join(strings.Split(b.OriGOPATH, ":")[0], "bin"), nil - } - return filepath.Join(os.Getenv("HOME"), "go", "bin"), nil -} - -// Clean clears up the temporary workspace -func (b *Build) Clean() error { - if !viper.GetBool("debug") { - return os.RemoveAll(b.TmpDir) - } - return nil -} diff --git a/pkg/build/tmpfolder_test.go b/pkg/build/tmpfolder_test.go deleted file mode 100644 index 2183280..0000000 --- a/pkg/build/tmpfolder_test.go +++ /dev/null @@ -1,150 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.com) - - 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 build - -import ( - "fmt" - "os" - "path/filepath" - "strings" - "testing" - - "github.com/stretchr/testify/assert" -) - -var baseDir string - -func init() { - baseDir, _ = os.Getwd() -} - -func TestNewDirParseInLegacyProject(t *testing.T) { - workingDir := filepath.Join(baseDir, "../../tests/samples/simple_gopath_project/src/qiniu.com/simple_gopath_project") - gopath := filepath.Join(baseDir, "../../tests/samples/simple_gopath_project") - - os.Setenv("GOPATH", gopath) - os.Setenv("GO111MODULE", "off") - - b, _ := NewInstall("", []string{"."}, workingDir) - if -1 == strings.Index(b.TmpWorkingDir, b.TmpDir) { - t.Fatalf("Directory parse error. newwd: %v, tmpdir: %v", b.TmpWorkingDir, b.TmpDir) - } - - if -1 == strings.Index(b.NewGOPATH, ":") || -1 == strings.Index(b.NewGOPATH, b.TmpDir) { - t.Fatalf("The New GOPATH is wrong. newgopath: %v, tmpdir: %v", b.NewGOPATH, b.TmpDir) - } - - b, _ = NewBuild("", []string{"."}, workingDir, "") - if -1 == strings.Index(b.TmpWorkingDir, b.TmpDir) { - t.Fatalf("Directory parse error. newwd: %v, tmpdir: %v", b.TmpWorkingDir, b.TmpDir) - } - - if -1 == strings.Index(b.NewGOPATH, ":") || -1 == strings.Index(b.NewGOPATH, b.TmpDir) { - t.Fatalf("The New GOPATH is wrong. newgopath: %v, tmpdir: %v", b.NewGOPATH, b.TmpDir) - } -} - -func TestNewDirParseInModProject(t *testing.T) { - workingDir := filepath.Join(baseDir, "../../tests/samples/simple_project") - gopath := "" - - fmt.Println(gopath) - os.Setenv("GOPATH", gopath) - os.Setenv("GO111MODULE", "on") - - b, _ := NewInstall("", []string{"."}, workingDir) - if -1 == strings.Index(b.TmpWorkingDir, b.TmpDir) { - t.Fatalf("Directory parse error. newwd: %v, tmpdir: %v", b.TmpWorkingDir, b.TmpDir) - } - - if b.NewGOPATH != "" { - t.Fatalf("The New GOPATH is wrong. newgopath: %v, tmpdir: %v", b.NewGOPATH, b.TmpDir) - } - - b, _ = NewBuild("", []string{"."}, workingDir, "") - if -1 == strings.Index(b.TmpWorkingDir, b.TmpDir) { - t.Fatalf("Directory parse error. newwd: %v, tmpdir: %v", b.TmpWorkingDir, b.TmpDir) - } - - if b.NewGOPATH != "" { - t.Fatalf("The New GOPATH is wrong. newgopath: %v, tmpdir: %v", b.NewGOPATH, b.TmpDir) - } -} - -// Test #14 -func TestLegacyProjectNotInGoPATH(t *testing.T) { - workingDir := filepath.Join(baseDir, "../../tests/samples/simple_gopath_project/src/qiniu.com/simple_gopath_project") - gopath := "" - - fmt.Println(gopath) - os.Setenv("GOPATH", gopath) - os.Setenv("GO111MODULE", "off") - - b, _ := NewBuild("", []string{"."}, workingDir, "") - if b.OriGOPATH != b.NewGOPATH { - t.Fatalf("New GOPATH should be same with old GOPATH, for this kind of project. New: %v, old: %v", b.NewGOPATH, b.OriGOPATH) - } - - _, err := os.Stat(filepath.Join(b.TmpDir, "main.go")) - if err != nil { - t.Fatalf("There should be a main.go in temporary directory directly, the error: %v", err) - } -} - -// test traversePkgsList error case -func TestTraversePkgsList(t *testing.T) { - b := &Build{ - Pkgs: nil, - } - _, _, err := b.traversePkgsList() - assert.EqualError(t, err, ErrShouldNotReached.Error()) -} - -// test getTmpwd error case -func TestGetTmpwd(t *testing.T) { - b := &Build{ - Pkgs: nil, - } - _, err := b.getTmpwd() - assert.EqualError(t, err, ErrShouldNotReached.Error()) -} - -// test findWhereToInstall -func TestFindWhereToInstall(t *testing.T) { - // if a legacy project without project root find - // should find no plcae to install - b := &Build{ - Pkgs: nil, - IsMod: false, - Root: "", - } - _, err := b.findWhereToInstall() - assert.EqualError(t, err, ErrNoPlaceToInstall.Error()) - - // if $GOBIN not found - // and if $GOPATH not found - // should install to $HOME/go/bin - b = &Build{ - Pkgs: nil, - IsMod: true, - OriGOPATH: "", - } - placeToInstall, err := b.findWhereToInstall() - assert.NoError(t, err) - expectedPlace := filepath.Join(os.Getenv("HOME"), "go", "bin") - assert.Equal(t, placeToInstall, expectedPlace) -} diff --git a/pkg/cover/client.go b/pkg/cover/client.go deleted file mode 100644 index 827c7c8..0000000 --- a/pkg/cover/client.go +++ /dev/null @@ -1,188 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.com) - - 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 cover - -import ( - "bytes" - "encoding/json" - "fmt" - "io" - "io/ioutil" - "net" - "net/http" - "net/url" - "strings" - - log "github.com/sirupsen/logrus" -) - -// Action provides methods to contact with the covered service under test -type Action interface { - Profile(param ProfileParam) ([]byte, error) - Clear(param ProfileParam) ([]byte, error) - Remove(param ProfileParam) ([]byte, error) - InitSystem() ([]byte, error) - ListServices() ([]byte, error) - RegisterService(svr ServiceUnderTest) ([]byte, error) -} - -const ( - //CoverInitSystemAPI prepare a new round of testing - CoverInitSystemAPI = "/v1/cover/init" - //CoverProfileAPI is provided by the covered service to get profiles - CoverProfileAPI = "/v1/cover/profile" - //CoverProfileClearAPI is provided by the covered service to clear profiles - CoverProfileClearAPI = "/v1/cover/clear" - //CoverServicesListAPI list all the registered services - CoverServicesListAPI = "/v1/cover/list" - //CoverRegisterServiceAPI register a service into service center - CoverRegisterServiceAPI = "/v1/cover/register" - //CoverServicesRemoveAPI remove one services from the service center - CoverServicesRemoveAPI = "/v1/cover/remove" -) - -type client struct { - Host string - client *http.Client -} - -// NewWorker creates a worker to contact with service -func NewWorker(host string) Action { - _, err := url.ParseRequestURI(host) - if err != nil { - log.Fatalf("Parse url %s failed, err: %v", host, err) - } - return &client{ - Host: host, - client: http.DefaultClient, - } -} - -func (c *client) RegisterService(srv ServiceUnderTest) ([]byte, error) { - if _, err := url.ParseRequestURI(srv.Address); err != nil { - return nil, err - } - if strings.TrimSpace(srv.Name) == "" { - return nil, fmt.Errorf("invalid service name") - } - u := fmt.Sprintf("%s%s?name=%s&address=%s", c.Host, CoverRegisterServiceAPI, srv.Name, srv.Address) - _, res, err := c.do("POST", u, "", nil) - return res, err -} - -func (c *client) ListServices() ([]byte, error) { - u := fmt.Sprintf("%s%s", c.Host, CoverServicesListAPI) - _, services, err := c.do("GET", u, "", nil) - if err != nil && isNetworkError(err) { - _, services, err = c.do("GET", u, "", nil) - } - - return services, err -} - -func (c *client) Profile(param ProfileParam) ([]byte, error) { - u := fmt.Sprintf("%s%s", c.Host, CoverProfileAPI) - if len(param.Service) != 0 && len(param.Address) != 0 { - return nil, fmt.Errorf("use 'service' flag and 'address' flag at the same time may cause ambiguity, please use them separately") - } - - // the json.Marshal function can return two types of errors: UnsupportedTypeError or UnsupportedValueError - // so no need to check here - body, _ := json.Marshal(param) - - res, profile, err := c.do("POST", u, "application/json", bytes.NewReader(body)) - if err != nil && isNetworkError(err) { - res, profile, err = c.do("POST", u, "application/json", bytes.NewReader(body)) - } - - if err == nil && res.StatusCode != 200 { - err = fmt.Errorf(string(profile)) - } - return profile, err -} - -func (c *client) Clear(param ProfileParam) ([]byte, error) { - u := fmt.Sprintf("%s%s", c.Host, CoverProfileClearAPI) - if len(param.Service) != 0 && len(param.Address) != 0 { - return nil, fmt.Errorf("use 'service' flag and 'address' flag at the same time may cause ambiguity, please use them separately") - } - - // the json.Marshal function can return two types of errors: UnsupportedTypeError or UnsupportedValueError - // so no need to check here - body, _ := json.Marshal(param) - _, resp, err := c.do("POST", u, "application/json", bytes.NewReader(body)) - if err != nil && isNetworkError(err) { - _, resp, err = c.do("POST", u, "application/json", bytes.NewReader(body)) - } - return resp, err -} - -func (c *client) Remove(param ProfileParam) ([]byte, error) { - u := fmt.Sprintf("%s%s", c.Host, CoverServicesRemoveAPI) - if len(param.Service) != 0 && len(param.Address) != 0 { - return nil, fmt.Errorf("use 'service' flag and 'address' flag at the same time may cause ambiguity, please use them separately") - } - - // the json.Marshal function can return two types of errors: UnsupportedTypeError or UnsupportedValueError - // so no need to check here - body, err := json.Marshal(param) - if err != nil { - return nil, err - } - _, resp, err := c.do("POST", u, "application/json", bytes.NewReader(body)) - if err != nil && isNetworkError(err) { - _, resp, err = c.do("POST", u, "application/json", bytes.NewReader(body)) - } - return resp, err -} - -func (c *client) InitSystem() ([]byte, error) { - u := fmt.Sprintf("%s%s", c.Host, CoverInitSystemAPI) - _, body, err := c.do("POST", u, "", nil) - return body, err -} - -func (c *client) do(method, url, contentType string, body io.Reader) (*http.Response, []byte, error) { - req, err := http.NewRequest(method, url, body) - if err != nil { - return nil, nil, err - } - - if contentType != "" { - req.Header.Set("Content-Type", contentType) - } - - res, err := c.client.Do(req) - if err != nil { - return nil, nil, err - } - defer res.Body.Close() - - responseBody, err := ioutil.ReadAll(res.Body) - if err != nil { - return res, nil, err - } - return res, responseBody, nil -} - -func isNetworkError(err error) bool { - if err == io.EOF { - return true - } - _, ok := err.(net.Error) - return ok -} diff --git a/pkg/cover/client_test.go b/pkg/cover/client_test.go deleted file mode 100644 index 4313dfe..0000000 --- a/pkg/cover/client_test.go +++ /dev/null @@ -1,257 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.com) - - 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 cover - -import ( - "fmt" - "net/http/httptest" - "os" - "testing" - - "net/http" - - "github.com/stretchr/testify/assert" -) - -func TestClientAction(t *testing.T) { - // mock goc server - server, err := NewFileBasedServer("_svrs_address.txt") - assert.NoError(t, err) - ts := httptest.NewServer(server.Route(os.Stdout)) - defer ts.Close() - var client = NewWorker(ts.URL) - - // mock profile server - profileMockResponse := []byte("mode: count\nmockService/main.go:30.13,48.33 13 1\nb/b.go:30.13,48.33 13 1") - profileSuccessMockSvr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusOK) - _, _ = w.Write(profileMockResponse) - })) - defer profileSuccessMockSvr.Close() - - profileErrMockSvr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusOK) - w.Write([]byte("error")) - })) - defer profileErrMockSvr.Close() - - // register service into goc server - var src ServiceUnderTest - src.Name = "serviceSuccess" - src.Address = profileSuccessMockSvr.URL - res, err := client.RegisterService(src) - assert.NoError(t, err) - assert.Contains(t, string(res), "success") - - // do list and check server - res, err = client.ListServices() - assert.NoError(t, err) - assert.Contains(t, string(res), src.Address) - assert.Contains(t, string(res), src.Name) - - // get profile from goc server - tcs := []struct { - name string - service ServiceUnderTest - param ProfileParam - expected string - expectedErr bool - }{ - { - name: "both server and address existed", - service: ServiceUnderTest{Name: "serviceOK", Address: profileSuccessMockSvr.URL}, - param: ProfileParam{Force: false, Service: []string{"serviceOK"}, Address: []string{profileSuccessMockSvr.URL}}, - expectedErr: true, - }, - { - name: "valid test with no server flag provide", - service: ServiceUnderTest{Name: "serviceOK", Address: profileSuccessMockSvr.URL}, - param: ProfileParam{}, - expected: "mockService/main.go:30.13,48.33 13 1", - }, - { - name: "valid test with server flag provide", - service: ServiceUnderTest{Name: "serviceOK", Address: profileSuccessMockSvr.URL}, - param: ProfileParam{Service: []string{"serviceOK"}}, - expected: "mockService/main.go:30.13,48.33 13 1", - }, - { - name: "valid test with address flag provide", - service: ServiceUnderTest{Name: "serviceOK", Address: profileSuccessMockSvr.URL}, - param: ProfileParam{Address: []string{profileSuccessMockSvr.URL}}, - expected: "mockService/main.go:30.13,48.33 13 1", - }, - { - name: "invalid test with invalid server flag provide", - service: ServiceUnderTest{Name: "serviceOK", Address: profileSuccessMockSvr.URL}, - param: ProfileParam{Service: []string{"unknown"}}, - expected: "server [unknown] not found", - expectedErr: true, - }, - { - name: "invalid test with invalid profile got by server", - service: ServiceUnderTest{Name: "serviceErr", Address: profileErrMockSvr.URL}, - expected: "bad mode line: error", - expectedErr: true, - }, - { - name: "invalid test with disconnected server", - service: ServiceUnderTest{Name: "serviceNotExist", Address: "http://172.0.0.2:7777"}, - expected: "connection refused", - expectedErr: true, - }, - { - name: "invalid test with empty profile", - service: ServiceUnderTest{Name: "serviceNotExist", Address: "http://172.0.0.2:7777"}, - param: ProfileParam{Force: true}, - expectedErr: true, - expected: "no profiles", - }, - { - name: "valid test with coverfile flag provide", - service: ServiceUnderTest{Name: "serviceOK", Address: profileSuccessMockSvr.URL}, - param: ProfileParam{CoverFilePatterns: []string{"b.go$"}}, - expected: "b/b.go", - }, - { - name: "valid test with skipfile flag provided", - service: ServiceUnderTest{Name: "serviceOK", Address: profileSuccessMockSvr.URL}, - param: ProfileParam{SkipFilePatterns: []string{"b.go$"}}, - expected: "main.go", - }, - { - name: "valid test with both skipfile and coverfile flags provided", - service: ServiceUnderTest{Name: "serviceOK", Address: profileSuccessMockSvr.URL}, - param: ProfileParam{SkipFilePatterns: []string{"main.go"}, CoverFilePatterns: []string{".go$"}}, - expected: "b.go", - }, - } - for _, tc := range tcs { - t.Run(tc.name, func(t *testing.T) { - // init server - _, err = client.InitSystem() - assert.NoError(t, err) - // register server - res, err = client.RegisterService(tc.service) - assert.NoError(t, err) - assert.Contains(t, string(res), "success") - res, err = client.Profile(tc.param) - if err != nil { - if !tc.expectedErr { - t.Errorf("unexpected err got: %v", err) - } - return - } - - if tc.expectedErr { - t.Errorf("Expected an error, but got value %s", string(res)) - } - - assert.Regexp(t, tc.expected, string(res)) - }) - } - - // init system and check server again - _, err = client.InitSystem() - assert.NoError(t, err) - res, err = client.ListServices() - assert.NoError(t, err) - assert.Equal(t, "{}", string(res)) -} - -func TestClientRegisterService(t *testing.T) { - c := &client{} - - // client register with empty address - testService1 := ServiceUnderTest{ - Address: "", - Name: "abc", - } - _, err := c.RegisterService(testService1) - assert.Contains(t, err.Error(), "empty url") - - // client register with empty name - testService2 := ServiceUnderTest{ - Address: "http://127.0.0.1:444", - Name: "", - } - _, err = c.RegisterService(testService2) - assert.EqualError(t, err, "invalid service name") -} - -func TestClientListServices(t *testing.T) { - c := &client{ - Host: "http://127.0.0.1:64445", // a invalid host - client: http.DefaultClient, - } - _, err := c.ListServices() - assert.Contains(t, err.Error(), "connect: connection refused") -} - -func TestClientDo(t *testing.T) { - c := &client{ - client: http.DefaultClient, - } - _, _, err := c.do(" ", "http://127.0.0.1:7777", "", nil) // a invalid method - assert.Contains(t, err.Error(), "invalid method") -} - -func TestClientClearWithInvalidParam(t *testing.T) { - p := ProfileParam{ - Service: []string{"goc"}, - Address: []string{"http://127.0.0.1:777"}, - } - c := &client{ - client: http.DefaultClient, - } - _, err := c.Clear(p) - assert.Error(t, err) - assert.Contains(t, err.Error(), "use 'service' flag and 'address' flag at the same time may cause ambiguity, please use them separately") -} - -func TestClientRemove(t *testing.T) { - // remove by invalid param - p := ProfileParam{ - Service: []string{"goc"}, - Address: []string{"http://127.0.0.1:777"}, - } - c := &client{ - client: http.DefaultClient, - } - _, err := c.Remove(p) - assert.Error(t, err) - assert.Contains(t, err.Error(), "use 'service' flag and 'address' flag at the same time may cause ambiguity, please use them separately") - - // remove by valid param - ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - fmt.Fprintln(w, "Hello, client") - })) - defer ts.Close() - - c.Host = ts.URL - p = ProfileParam{ - Address: []string{"http://127.0.0.1:777"}, - } - res, err := c.Remove(p) - assert.NoError(t, err) - assert.Equal(t, string(res), "Hello, client\n") - - // remove from a invalid center - c.Host = "http://127.0.0.1:11111" - _, err = c.Remove(p) - assert.Error(t, err) -} diff --git a/pkg/cover/cover.go b/pkg/cover/cover.go deleted file mode 100644 index 742e352..0000000 --- a/pkg/cover/cover.go +++ /dev/null @@ -1,574 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.com) - - 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 cover - -import ( - "bufio" - "bytes" - "crypto/sha256" - "encoding/json" - "errors" - "fmt" - "io" - "io/ioutil" - "os" - "os/exec" - "path" - "path/filepath" - "sort" - "strconv" - "strings" - "time" - - log "github.com/sirupsen/logrus" - - "github.com/qiniu/goc/pkg/cover/internal/tool" - "github.com/sirupsen/logrus" -) - -var ( - // ErrCoverPkgFailed represents the error that fails to inject the package - ErrCoverPkgFailed = errors.New("fail to inject code to project") - // ErrCoverListFailed represents the error that fails to list package dependencies - ErrCoverListFailed = errors.New("fail to list package dependencies") -) - -// TestCover is a collection of all counters -type TestCover struct { - Mode string - AgentPort string - Center string // cover profile host center - MainPkgCover *PackageCover - DepsCover []*PackageCover - CacheCover map[string]*PackageCover - GlobalCoverVarImportPath string -} - -// PackageCover holds all the generate coverage variables of a package -type PackageCover struct { - Package *Package - Vars map[string]*FileVar -} - -// FileVar holds the name of the generated coverage variables targeting the named file. -type FileVar struct { - File string - Var string -} - -// Package map a package output by go list -// this is subset of package struct in: https://github.com/golang/go/blob/master/src/cmd/go/internal/load/pkg.go#L58 -type Package struct { - Dir string `json:"Dir"` // directory containing package sources - ImportPath string `json:"ImportPath"` // import path of package in dir - Name string `json:"Name"` // package name - Target string `json:",omitempty"` // installed target for this package (may be executable) - Root string `json:",omitempty"` // Go root, Go path dir, or module root dir containing this package - - Module *ModulePublic `json:",omitempty"` // info about package's module, if any - Goroot bool `json:"Goroot,omitempty"` // is this package in the Go root? - Standard bool `json:"Standard,omitempty"` // is this package part of the standard Go library? - DepOnly bool `json:"DepOnly,omitempty"` // package is only a dependency, not explicitly listed - - // Source files - GoFiles []string `json:"GoFiles,omitempty"` // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles) - CgoFiles []string `json:"CgoFiles,omitempty"` // .go source files that import "C" - - // Dependency information - Deps []string `json:"Deps,omitempty"` // all (recursively) imported dependencies - Imports []string `json:",omitempty"` // import paths used by this package - ImportMap map[string]string `json:",omitempty"` // map from source import to ImportPath (identity entries omitted) - - // Error information - Incomplete bool `json:"Incomplete,omitempty"` // this package or a dependency has an error - Error *PackageError `json:"Error,omitempty"` // error loading package - DepsErrors []*PackageError `json:"DepsErrors,omitempty"` // errors loading dependencies -} - -// ModulePublic represents the package info of a module -type ModulePublic struct { - Path string `json:",omitempty"` // module path - Version string `json:",omitempty"` // module version - Versions []string `json:",omitempty"` // available module versions - Replace *ModulePublic `json:",omitempty"` // replaced by this module - Time *time.Time `json:",omitempty"` // time version was created - Update *ModulePublic `json:",omitempty"` // available update (with -u) - Main bool `json:",omitempty"` // is this the main module? - Indirect bool `json:",omitempty"` // module is only indirectly needed by main module - Dir string `json:",omitempty"` // directory holding local copy of files, if any - GoMod string `json:",omitempty"` // path to go.mod file describing module, if any - GoVersion string `json:",omitempty"` // go version used in module - Error *ModuleError `json:",omitempty"` // error loading module -} - -// ModuleError represents the error loading module -type ModuleError struct { - Err string // error text -} - -// PackageError is the error info for a package when list failed -type PackageError struct { - ImportStack []string // shortest path from package named on command line to this one - Pos string // position of error (if present, file:line:col) - Err string // the error itself -} - -// CoverBuildInfo retreives some info from build -type CoverInfo struct { - Target string - GoPath string - IsMod bool - ModRootPath string - GlobalCoverVarImportPath string // path for the injected global cover var file - OneMainPackage bool - Args string - Mode string - AgentPort string - Center string -} - -//Execute inject cover variables for all the .go files in the target folder -func Execute(coverInfo *CoverInfo) error { - target := coverInfo.Target - newGopath := coverInfo.GoPath - // oneMainPackage := coverInfo.OneMainPackage - args := coverInfo.Args - mode := coverInfo.Mode - agentPort := coverInfo.AgentPort - center := coverInfo.Center - globalCoverVarImportPath := coverInfo.GlobalCoverVarImportPath - - if coverInfo.IsMod { - globalCoverVarImportPath = filepath.Join(coverInfo.ModRootPath, globalCoverVarImportPath) - } else { - globalCoverVarImportPath = filepath.Base(globalCoverVarImportPath) - } - - if !isDirExist(target) { - log.Errorf("Target directory %s not exist", target) - return ErrCoverPkgFailed - } - listArgs := []string{"-json"} - if len(args) != 0 { - listArgs = append(listArgs, args) - } - listArgs = append(listArgs, "./...") - pkgs, err := ListPackages(target, strings.Join(listArgs, " "), newGopath) - if err != nil { - log.Errorf("Fail to list all packages, the error: %v", err) - return err - } - - var seen = make(map[string]*PackageCover) - // var seenCache = make(map[string]*PackageCover) - allDecl := "" - for _, pkg := range pkgs { - if pkg.Name == "main" { - log.Printf("handle package: %v", pkg.ImportPath) - // inject the main package - mainCover, mainDecl := AddCounters(pkg, mode, globalCoverVarImportPath) - allDecl += mainDecl - // new a testcover for this service - tc := TestCover{ - Mode: mode, - AgentPort: agentPort, - Center: center, - MainPkgCover: mainCover, - GlobalCoverVarImportPath: globalCoverVarImportPath, - } - - // handle its dependency - // var internalPkgCache = make(map[string][]*PackageCover) - tc.CacheCover = make(map[string]*PackageCover) - for _, dep := range pkg.Deps { - if packageCover, ok := seen[dep]; ok { - tc.DepsCover = append(tc.DepsCover, packageCover) - continue - } - - //only focus package neither standard Go library nor dependency library - if depPkg, ok := pkgs[dep]; ok { - packageCover, depDecl := AddCounters(depPkg, mode, globalCoverVarImportPath) - allDecl += depDecl - tc.DepsCover = append(tc.DepsCover, packageCover) - seen[dep] = packageCover - } - } - - // inject Http Cover APIs - var httpCoverApis = fmt.Sprintf("%s/http_cover_apis_auto_generated.go", pkg.Dir) - if err := InjectCountersHandlers(tc, httpCoverApis); err != nil { - log.Errorf("failed to inject counters for package: %s, err: %v", pkg.ImportPath, err) - return ErrCoverPkgFailed - } - } - } - - return injectGlobalCoverVarFile(coverInfo, allDecl) -} - -// ListPackages list all packages under specific via go list command -// The argument newgopath is if you need to go list in a different GOPATH -func ListPackages(dir string, args string, newgopath string) (map[string]*Package, error) { - cmd := exec.Command("/bin/bash", "-c", "go list "+args) - log.Printf("go list cmd is: %v", cmd.Args) - cmd.Dir = dir - if newgopath != "" { - cmd.Env = append(os.Environ(), fmt.Sprintf("GOPATH=%v", newgopath)) - } - var errbuf bytes.Buffer - cmd.Stderr = &errbuf - out, err := cmd.Output() - if err != nil { - log.Errorf("excute `go list -json ./...` command failed, err: %v, stdout: %v, stderr: %v", err, string(out), errbuf.String()) - return nil, ErrCoverListFailed - } - log.Infof("\n%v", errbuf.String()) - dec := json.NewDecoder(bytes.NewReader(out)) - pkgs := make(map[string]*Package, 0) - for { - var pkg Package - if err := dec.Decode(&pkg); err != nil { - if err == io.EOF { - break - } - log.Errorf("reading go list output: %v", err) - return nil, ErrCoverListFailed - } - if pkg.Error != nil { - log.Errorf("list package %s failed with output: %v", pkg.ImportPath, pkg.Error) - return nil, ErrCoverPkgFailed - } - - // for _, err := range pkg.DepsErrors { - // log.Fatalf("dependency package list failed, err: %v", err) - // } - - pkgs[pkg.ImportPath] = &pkg - } - return pkgs, nil -} - -// AddCounters is different from official go tool cover -// 1. only inject covervar++ into source file -// 2. no declarartions for these covervars -// 3. return the declarations as string -func AddCounters(pkg *Package, mode string, globalCoverVarImportPath string) (*PackageCover, string) { - coverVarMap := declareCoverVars(pkg) - - decl := "" - for file, coverVar := range coverVarMap { - decl += "\n" + tool.Annotate(path.Join(pkg.Dir, file), mode, coverVar.Var, globalCoverVarImportPath) + "\n" - } - - return &PackageCover{ - Package: pkg, - Vars: coverVarMap, - }, decl -} - -func isDirExist(path string) bool { - s, err := os.Stat(path) - if err != nil { - return false - } - return s.IsDir() -} - -// Refer: https://github.com/golang/go/blob/master/src/cmd/go/internal/load/pkg.go#L1334:6 -// hasInternalPath looks for the final "internal" path element in the given import path. -// If there isn't one, hasInternalPath returns ok=false. -// Otherwise, hasInternalPath returns ok=true and the index of the "internal". -func hasInternalPath(path string) bool { - // Three cases, depending on internal at start/end of string or not. - // The order matters: we must return the index of the final element, - // because the final one produces the most restrictive requirement - // on the importer. - switch { - case strings.HasSuffix(path, "/internal"): - return true - case strings.Contains(path, "/internal/"): - return true - case path == "internal", strings.HasPrefix(path, "internal/"): - return true - } - return false -} - -func getInternalParent(path string) string { - switch { - case strings.HasSuffix(path, "/internal"): - return strings.Split(path, "/internal")[0] - case strings.Contains(path, "/internal/"): - return strings.Split(path, "/internal/")[0] - case path == "internal": - return "" - case strings.HasPrefix(path, "internal/"): - return strings.Split(path, "internal/")[0] - } - return "" -} - -func buildCoverCmd(file string, coverVar *FileVar, pkg *Package, mode, newgopath string) *exec.Cmd { - // to construct: go tool cover -mode=atomic -o dest src (note: dest==src) - var newArgs = []string{"tool", "cover"} - newArgs = append(newArgs, "-mode", mode) - newArgs = append(newArgs, "-var", coverVar.Var) - longPath := path.Join(pkg.Dir, file) - newArgs = append(newArgs, "-o", longPath, longPath) - cmd := exec.Command("go", newArgs...) - if newgopath != "" { - cmd.Env = append(os.Environ(), fmt.Sprintf("GOPATH=%v", newgopath)) - } - return cmd -} - -// declareCoverVars attaches the required cover variables names -// to the files, to be used when annotating the files. -func declareCoverVars(p *Package) map[string]*FileVar { - coverVars := make(map[string]*FileVar) - coverIndex := 0 - // We create the cover counters as new top-level variables in the package. - // We need to avoid collisions with user variables (GoCover_0 is unlikely but still) - // and more importantly with dot imports of other covered packages, - // so we append 12 hex digits from the SHA-256 of the import path. - // The point is only to avoid accidents, not to defeat users determined to - // break things. - sum := sha256.Sum256([]byte(p.ImportPath)) - h := fmt.Sprintf("%x", sum[:6]) - for _, file := range p.GoFiles { - // These names appear in the cmd/cover HTML interface. - var longFile = path.Join(p.ImportPath, file) - coverVars[file] = &FileVar{ - File: longFile, - Var: fmt.Sprintf("GoCover_%d_%x", coverIndex, h), - } - coverIndex++ - } - - for _, file := range p.CgoFiles { - // These names appear in the cmd/cover HTML interface. - var longFile = path.Join(p.ImportPath, file) - coverVars[file] = &FileVar{ - File: longFile, - Var: fmt.Sprintf("GoCover_%d_%x", coverIndex, h), - } - coverIndex++ - } - - return coverVars -} - -func declareCacheVars(in *PackageCover) map[string]*FileVar { - sum := sha256.Sum256([]byte(in.Package.ImportPath)) - h := fmt.Sprintf("%x", sum[:5]) - - vars := make(map[string]*FileVar) - coverIndex := 0 - for _, v := range in.Vars { - cacheVar := fmt.Sprintf("GoCacheCover_%d_%x", coverIndex, h) - vars[cacheVar] = v - coverIndex++ - } - return vars -} - -func cacheInternalCover(in *PackageCover) *PackageCover { - c := &PackageCover{} - vars := declareCacheVars(in) - c.Package = in.Package - c.Vars = vars - return c -} - -func addCacheCover(pkg *Package, in *PackageCover) *PackageCover { - c := &PackageCover{} - sum := sha256.Sum256([]byte(pkg.ImportPath)) - h := fmt.Sprintf("%x", sum[:6]) - goFile := fmt.Sprintf("cache_vars_auto_generated_%x.go", h) - p := &Package{ - Dir: fmt.Sprintf("%s/cache_%x", pkg.Dir, h), - ImportPath: fmt.Sprintf("%s/cache_%x", pkg.ImportPath, h), - Name: fmt.Sprintf("cache_%x", h), - } - p.GoFiles = append(p.GoFiles, goFile) - c.Package = p - c.Vars = declareCacheVars(in) - return c -} - -// CoverageList is a collection and summary over multiple file Coverage objects -type CoverageList []Coverage - -// Coverage stores test coverage summary data for one file -type Coverage struct { - FileName string - NCoveredStmts int - NAllStmts int - LineCovLink string -} - -type codeBlock struct { - fileName string // the file the code block is in - numStatements int // number of statements in the code block - coverageCount int // number of times the block is covered -} - -// CovList converts profile to CoverageList struct -func CovList(f io.Reader) (g CoverageList, err error) { - scanner := bufio.NewScanner(f) - scanner.Scan() // discard first line - g = NewCoverageList() - - for scanner.Scan() { - row := scanner.Text() - blk, err := toBlock(row) - if err != nil { - return nil, err - } - blk.addToGroupCov(&g) - } - return -} - -// ReadFileToCoverList coverts profile file to CoverageList struct -func ReadFileToCoverList(path string) (g CoverageList, err error) { - f, err := ioutil.ReadFile(path) - if err != nil { - logrus.Errorf("Open file %s failed!", path) - return nil, err - } - g, err = CovList(bytes.NewReader(f)) - return -} - -// NewCoverageList return empty CoverageList -func NewCoverageList() CoverageList { - return CoverageList{} - -} - -func newCoverage(name string) *Coverage { - return &Coverage{name, 0, 0, ""} -} - -// convert a line in profile file to a codeBlock struct -func toBlock(line string) (res *codeBlock, err error) { - slice := strings.Split(line, " ") - if len(slice) != 3 { - return nil, fmt.Errorf("the profile line %s is not expected", line) - } - blockName := slice[0] - nStmts, _ := strconv.Atoi(slice[1]) - coverageCount, _ := strconv.Atoi(slice[2]) - return &codeBlock{ - fileName: blockName[:strings.Index(blockName, ":")], - numStatements: nStmts, - coverageCount: coverageCount, - }, nil -} - -// add blk Coverage to file group Coverage -func (blk *codeBlock) addToGroupCov(g *CoverageList) { - if g.size() == 0 || g.lastElement().Name() != blk.fileName { - // when a new file name is processed - coverage := newCoverage(blk.fileName) - g.append(coverage) - } - cov := g.lastElement() - cov.NAllStmts += blk.numStatements - if blk.coverageCount > 0 { - cov.NCoveredStmts += blk.numStatements - } -} - -func (g CoverageList) size() int { - return len(g) -} - -func (g CoverageList) lastElement() *Coverage { - return &g[g.size()-1] -} - -func (g *CoverageList) append(c *Coverage) { - *g = append(*g, *c) -} - -// Sort sorts CoverageList with filenames -func (g CoverageList) Sort() { - sort.SliceStable(g, func(i, j int) bool { - return g[i].Name() < g[j].Name() - }) -} - -// TotalPercentage returns the total percentage of coverage -func (g CoverageList) TotalPercentage() string { - ratio, err := g.TotalRatio() - if err == nil { - return PercentStr(ratio) - } - return "N/A" -} - -// TotalRatio returns the total ratio of covered statements -func (g CoverageList) TotalRatio() (ratio float32, err error) { - var total Coverage - for _, c := range g { - total.NCoveredStmts += c.NCoveredStmts - total.NAllStmts += c.NAllStmts - } - return total.Ratio() -} - -// Map returns maps the file name to its coverage for faster retrieval -// & membership check -func (g CoverageList) Map() map[string]Coverage { - m := make(map[string]Coverage) - for _, c := range g { - m[c.Name()] = c - } - return m -} - -// Name returns the file name -func (c *Coverage) Name() string { - return c.FileName -} - -// Percentage returns the percentage of statements covered -func (c *Coverage) Percentage() string { - ratio, err := c.Ratio() - if err == nil { - return PercentStr(ratio) - } - return "N/A" -} - -// Ratio calculates the ratio of statements in a profile -func (c *Coverage) Ratio() (ratio float32, err error) { - if c.NAllStmts == 0 { - err = fmt.Errorf("[%s] has 0 statement", c.Name()) - } else { - ratio = float32(c.NCoveredStmts) / float32(c.NAllStmts) - } - return -} - -// PercentStr converts a fraction number to percentage string representation -func PercentStr(f float32) string { - return fmt.Sprintf("%.1f%%", f*100) -} diff --git a/pkg/cover/cover_test.go b/pkg/cover/cover_test.go deleted file mode 100644 index e48e048..0000000 --- a/pkg/cover/cover_test.go +++ /dev/null @@ -1,388 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.com) - - 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 cover - -import ( - "fmt" - "os" - "os/exec" - "path/filepath" - "reflect" - "strings" - "testing" - - log "github.com/sirupsen/logrus" - - "github.com/stretchr/testify/assert" - "github.com/tongjingran/copy" -) - -func testCoverage() (c *Coverage) { - return &Coverage{FileName: "fake-coverage", NCoveredStmts: 200, NAllStmts: 300} -} - -func TestCoverageRatio(t *testing.T) { - c := testCoverage() - actualRatio, _ := c.Ratio() - assert.Equal(t, float32(c.NCoveredStmts)/float32(c.NAllStmts), actualRatio) -} - -func TestRatioErr(t *testing.T) { - c := &Coverage{FileName: "fake-coverage", NCoveredStmts: 200, NAllStmts: 0} - _, err := c.Ratio() - assert.NotEqual(t, err, nil) -} - -func TestPercentageNA(t *testing.T) { - c := &Coverage{FileName: "fake-coverage", NCoveredStmts: 200, NAllStmts: 0} - assert.Equal(t, "N/A", c.Percentage()) -} - -func TestCovList(t *testing.T) { - fileName := "qiniu.com/kodo/apiserver/server/main.go" - fileName1 := "qiniu.com/kodo/apiserver/server/svr.go" - - items := []struct { - profile string - expectPer []string - }{ - // percentage is 100% - { - profile: "mode: atomic\n" + - fileName + ":32.49,33.13 1 30\n", - expectPer: []string{"100.0%"}, - }, - // percentage is 50% - {profile: "mode: atomic\n" + - fileName + ":32.49,33.13 1 30\n" + - fileName + ":42.49,43.13 1 0\n", - expectPer: []string{"50.0%"}, - }, - // two files - { - profile: "mode: atomic\n" + - fileName + ":32.49,33.13 1 30\n" + - fileName1 + ":42.49,43.13 1 0\n", - expectPer: []string{"100.0%", "0.0%"}, - }, - } - - for _, tc := range items { - r := strings.NewReader(tc.profile) - c, err := CovList(r) - c.Sort() - assert.Equal(t, err, nil) - for k, v := range c { - assert.Equal(t, tc.expectPer[k], v.Percentage()) - } - } -} - -func TestReadFileToCoverList(t *testing.T) { - path := "unknown" - _, err := ReadFileToCoverList(path) - assert.Equal(t, err.Error(), "open unknown: no such file or directory") -} - -func TestTotalPercentage(t *testing.T) { - items := []struct { - list CoverageList - expectPer string - }{ - { - list: CoverageList{Coverage{FileName: "fake-coverage", NCoveredStmts: 15, NAllStmts: 0}}, - expectPer: "N/A", - }, - { - list: CoverageList{Coverage{FileName: "fake-coverage", NCoveredStmts: 15, NAllStmts: 20}}, - expectPer: "75.0%", - }, - { - list: CoverageList{Coverage{FileName: "fake-coverage", NCoveredStmts: 15, NAllStmts: 20}, - Coverage{FileName: "fake-coverage-1", NCoveredStmts: 10, NAllStmts: 30}}, - expectPer: "50.0%", - }, - } - - for _, tc := range items { - assert.Equal(t, tc.expectPer, tc.list.TotalPercentage()) - } -} - -func TestBuildCoverCmd(t *testing.T) { - var testCases = []struct { - name string - file string - coverVar *FileVar - pkg *Package - mode string - newgopath string - expectCmd *exec.Cmd - }{ - { - name: "normal", - file: "c.go", - coverVar: &FileVar{ - File: "example/b/c/c.go", - Var: "GoCover_0_643131623532653536333031", - }, - pkg: &Package{ - Dir: "/go/src/goc/cmd/example-project/b/c", - }, - mode: "count", - newgopath: "", - expectCmd: &exec.Cmd{ - Path: lookCmdPath("go"), - Args: []string{"go", "tool", "cover", "-mode", "count", "-var", "GoCover_0_643131623532653536333031", "-o", - "/go/src/goc/cmd/example-project/b/c/c.go", "/go/src/goc/cmd/example-project/b/c/c.go"}, - }, - }, - { - name: "normal with gopath", - file: "c.go", - coverVar: &FileVar{ - File: "example/b/c/c.go", - Var: "GoCover_0_643131623532653536333031", - }, - pkg: &Package{ - Dir: "/go/src/goc/cmd/example-project/b/c", - }, - mode: "set", - newgopath: "/go/src/goc", - expectCmd: &exec.Cmd{ - Path: lookCmdPath("go"), - Args: []string{"go", "tool", "cover", "-mode", "set", "-var", "GoCover_0_643131623532653536333031", "-o", - "/go/src/goc/cmd/example-project/b/c/c.go", "/go/src/goc/cmd/example-project/b/c/c.go"}, - Env: append(os.Environ(), fmt.Sprintf("GOPATH=%v", "/go/src/goc")), - }, - }, - } - for _, testCase := range testCases { - t.Run(testCase.name, func(t *testing.T) { - cmd := buildCoverCmd(testCase.file, testCase.coverVar, testCase.pkg, testCase.mode, testCase.newgopath) - if !reflect.DeepEqual(cmd, testCase.expectCmd) { - t.Errorf("generated incorrect commands:\nGot: %#v\nExpected:%#v", cmd, testCase.expectCmd) - } - }) - } - -} - -func lookCmdPath(name string) string { - if filepath.Base(name) == name { - if lp, err := exec.LookPath(name); err != nil { - log.Fatalf("find exec %s err: %v", name, err) - } else { - return lp - } - } - return "" -} - -func TestDeclareCoverVars(t *testing.T) { - var testCases = []struct { - name string - pkg *Package - expectCoverVar map[string]*FileVar - }{ - { - name: "normal", - pkg: &Package{ - Dir: "/go/src/goc/cmd/example-project/b/c", - GoFiles: []string{"c.go"}, - ImportPath: "example/b/c", - }, - expectCoverVar: map[string]*FileVar{ - "c.go": {File: "example/b/c/c.go", Var: "GoCover_0_643131623532653536333031"}, - }, - }, - { - name: "more go files", - pkg: &Package{ - Dir: "/go/src/goc/cmd/example-project/a/b", - GoFiles: []string{"printf.go", "printf1.go"}, - ImportPath: "example/a/b", - }, - expectCoverVar: map[string]*FileVar{ - "printf.go": {File: "example/a/b/printf.go", Var: "GoCover_0_326535623364613565313464"}, - "printf1.go": {File: "example/a/b/printf1.go", Var: "GoCover_1_326535623364613565313464"}, - }, - }, - } - for _, testCase := range testCases { - t.Run(testCase.name, func(t *testing.T) { - coverVar := declareCoverVars(testCase.pkg) - if !reflect.DeepEqual(coverVar, testCase.expectCoverVar) { - t.Errorf("generated incorrect cover vars:\nGot: %#v\nExpected:%#v", coverVar, testCase.expectCoverVar) - } - }) - } - -} - -func TestGetInternalParent(t *testing.T) { - var tcs = []struct { - ImportPath string - expectedParent string - }{ - { - ImportPath: "a/internal/b", - expectedParent: "a", - }, - { - ImportPath: "internal/b", - expectedParent: "", - }, - { - ImportPath: "a/b/internal/b", - expectedParent: "a/b", - }, - { - ImportPath: "a/b/internal", - expectedParent: "a/b", - }, - { - ImportPath: "a/b/internal/c", - expectedParent: "a/b", - }, - { - ImportPath: "a/b/c", - expectedParent: "", - }, - { - ImportPath: "", - expectedParent: "", - }, - } - - for _, tc := range tcs { - actual := getInternalParent(tc.ImportPath) - if actual != tc.expectedParent { - t.Errorf("getInternalParent failed for importPath %s, expected %s, got %s", tc.ImportPath, tc.expectedParent, actual) - } - } -} - -func TestFindInternal(t *testing.T) { - var tcs = []struct { - ImportPath string - expectedParent bool - }{ - { - ImportPath: "a/internal/b", - expectedParent: true, - }, - { - ImportPath: "internal/b", - expectedParent: true, - }, - { - ImportPath: "a/b/internal", - expectedParent: true, - }, - { - ImportPath: "a/b/c", - expectedParent: false, - }, - { - ImportPath: "internal", - expectedParent: true, - }, - } - - for _, tc := range tcs { - actual := hasInternalPath(tc.ImportPath) - if actual != tc.expectedParent { - t.Errorf("hasInternalPath check failed for importPath %s", tc.ImportPath) - } - } -} - -func TestExecuteForSimpleModProject(t *testing.T) { - workingDir := "../../tests/samples/simple_project" - gopath := "" - - os.Setenv("GOPATH", gopath) - os.Setenv("GO111MODULE", "on") - - testDir := filepath.Join(os.TempDir(), "goc-build-test") - copy.Copy(workingDir, testDir) - - bi := &CoverInfo{ - Args: "", - GoPath: gopath, - Target: testDir, - Mode: "count", - AgentPort: "", - Center: "http://127.0.0.1:7777", - OneMainPackage: false, - } - _ = Execute(bi) - - _, err := os.Lstat(filepath.Join(testDir, "http_cover_apis_auto_generated.go")) - if !assert.Equal(t, err, nil) { - assert.FailNow(t, "should generate http_cover_apis_auto_generated.go") - } -} - -func TestListPackagesForSimpleModProject(t *testing.T) { - workingDir := "../../tests/samples/simple_project" - gopath := "" - - os.Setenv("GOPATH", gopath) - os.Setenv("GO111MODULE", "on") - - pkgs, _ := ListPackages(workingDir, "-json ./...", "") - if !assert.Equal(t, len(pkgs), 1) { - assert.FailNow(t, "should only have one pkg") - } - if pkg, ok := pkgs["example.com/simple-project"]; ok { - assert.Equal(t, pkg.Module.Path, "example.com/simple-project") - } else { - assert.FailNow(t, "cannot get the pkg: example.com/simple-project") - } - -} - -// test if goc can get variables in internal package -func TestCoverResultForInternalPackage(t *testing.T) { - - workingDir := "../../tests/samples/simple_project_with_internal" - gopath := "" - - os.Setenv("GOPATH", gopath) - os.Setenv("GO111MODULE", "on") - - testDir := filepath.Join(os.TempDir(), "goc-build-test") - copy.Copy(workingDir, testDir) - - bi := &CoverInfo{ - Target: testDir, - GoPath: gopath, - Args: "", - Mode: "count", - Center: "http://127.0.0.1:7777", - OneMainPackage: false, - AgentPort: "", - } - _ = Execute(bi) - - _, err := os.Lstat(filepath.Join(testDir, "http_cover_apis_auto_generated.go")) - if !assert.Equal(t, err, nil) { - assert.FailNow(t, "should generate http_cover_apis_auto_generated.go") - } -} diff --git a/pkg/cover/delta.go b/pkg/cover/delta.go deleted file mode 100644 index 729f2c5..0000000 --- a/pkg/cover/delta.go +++ /dev/null @@ -1,136 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.com) - - 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 cover - -import "sort" - -// DeltaCov contains the info of a delta coverage -type DeltaCov struct { - FileName string - BasePer string - NewPer string - DeltaPer string - LineCovLink string -} - -// DeltaCovList is the list of DeltaCov -type DeltaCovList []DeltaCov - -// GetFullDeltaCov get full delta coverage between new and base profile -func GetFullDeltaCov(newList CoverageList, baseList CoverageList) (delta DeltaCovList) { - newMap := newList.Map() - baseMap := baseList.Map() - - for file, n := range newMap { - b, ok := baseMap[file] - //if the file not in base profile, set None - if !ok { - delta = append(delta, DeltaCov{ - FileName: file, - BasePer: "None", - NewPer: n.Percentage(), - DeltaPer: PercentStr(Delta(n, b))}) - continue - } - delta = append(delta, DeltaCov{ - FileName: file, - BasePer: b.Percentage(), - NewPer: n.Percentage(), - DeltaPer: PercentStr(Delta(n, b))}) - } - - for file, b := range baseMap { - //if the file not in new profile, set None - if n, ok := newMap[file]; !ok { - delta = append(delta, DeltaCov{ - FileName: file, - BasePer: b.Percentage(), - NewPer: "None", - DeltaPer: PercentStr(Delta(n, b))}) - } - } - return -} - -// GetDeltaCov get two profile diff cov -func GetDeltaCov(newList CoverageList, baseList CoverageList) (delta DeltaCovList) { - d := GetFullDeltaCov(newList, baseList) - for _, v := range d { - if v.DeltaPer == "0.0%" { - continue - } - delta = append(delta, v) - } - return -} - -// GetChFileDeltaCov get two profile diff cov of changed files -func GetChFileDeltaCov(newList CoverageList, baseList CoverageList, changedFiles []string) (list DeltaCovList) { - d := GetFullDeltaCov(newList, baseList) - dMap := d.Map() - for _, file := range changedFiles { - if _, ok := dMap[file]; ok { - list = append(list, dMap[file]) - } - } - return -} - -// Delta calculate two coverage delta -func Delta(new Coverage, base Coverage) float32 { - baseRatio, _ := base.Ratio() - newRatio, _ := new.Ratio() - return newRatio - baseRatio -} - -// TotalDelta calculate two coverage delta -func TotalDelta(new CoverageList, base CoverageList) float32 { - baseRatio, _ := base.TotalRatio() - newRatio, _ := new.TotalRatio() - return newRatio - baseRatio -} - -// Map returns maps the file name to its DeltaCov for faster retrieval & membership check -func (d DeltaCovList) Map() map[string]DeltaCov { - m := make(map[string]DeltaCov) - for _, c := range d { - m[c.FileName] = c - } - return m -} - -// Sort sort DeltaCovList with filenames -func (d DeltaCovList) Sort() { - sort.SliceStable(d, func(i, j int) bool { - return d[i].Name() < d[j].Name() - }) -} - -// Name returns the file name -func (c *DeltaCov) Name() string { - return c.FileName -} - -// GetLineCovLink get the LineCovLink of the DeltaCov -func (c *DeltaCov) GetLineCovLink() string { - return c.LineCovLink -} - -// SetLineCovLink set LineCovLink of the DeltaCov -func (c *DeltaCov) SetLineCovLink(link string) { - c.LineCovLink = link -} diff --git a/pkg/cover/delta_test.go b/pkg/cover/delta_test.go deleted file mode 100644 index 5982d5d..0000000 --- a/pkg/cover/delta_test.go +++ /dev/null @@ -1,133 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.com) - - 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 cover - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestGetDeltaCov(t *testing.T) { - items := []struct { - newList CoverageList - baseList CoverageList - expectDelta DeltaCovList - rows int - }{ - //coverage increase - { - newList: CoverageList{Coverage{FileName: "fake-coverage", NCoveredStmts: 15, NAllStmts: 20}}, - baseList: CoverageList{Coverage{FileName: "fake-coverage", NCoveredStmts: 10, NAllStmts: 20}}, - expectDelta: DeltaCovList{{FileName: "fake-coverage", BasePer: "50.0%", NewPer: "75.0%", DeltaPer: "25.0%"}}, - rows: 1, - }, - //coverage decrease - { - newList: CoverageList{Coverage{FileName: "fake-coverage", NCoveredStmts: 15, NAllStmts: 20}}, - baseList: CoverageList{Coverage{FileName: "fake-coverage", NCoveredStmts: 20, NAllStmts: 20}}, - expectDelta: DeltaCovList{{FileName: "fake-coverage", BasePer: "100.0%", NewPer: "75.0%", DeltaPer: "-25.0%"}}, - rows: 1, - }, - //diff file - { - newList: CoverageList{Coverage{FileName: "fake-coverage", NCoveredStmts: 15, NAllStmts: 20}}, - baseList: CoverageList{Coverage{FileName: "fake-coverage-v1", NCoveredStmts: 10, NAllStmts: 20}}, - expectDelta: DeltaCovList{{FileName: "fake-coverage", BasePer: "None", NewPer: "75.0%", DeltaPer: "75.0%"}, - {FileName: "fake-coverage-v1", BasePer: "50.0%", NewPer: "None", DeltaPer: "-50.0%"}}, - rows: 2, - }, - //one file has same coverage rate - { - newList: CoverageList{Coverage{FileName: "fake-coverage", NCoveredStmts: 15, NAllStmts: 20}}, - baseList: CoverageList{Coverage{FileName: "fake-coverage", NCoveredStmts: 15, NAllStmts: 20}, - Coverage{FileName: "fake-coverage-v1", NCoveredStmts: 10, NAllStmts: 20}}, - expectDelta: DeltaCovList{{FileName: "fake-coverage-v1", BasePer: "50.0%", NewPer: "None", DeltaPer: "-50.0%"}}, - rows: 1, - }, - } - - for _, tc := range items { - d := GetDeltaCov(tc.newList, tc.baseList) - assert.Equal(t, tc.rows, len(d)) - assert.Equal(t, tc.expectDelta, d) - } -} - -func TestGetChFileDeltaCov(t *testing.T) { - items := []struct { - newList CoverageList - baseList CoverageList - changedFiles []string - expectDelta DeltaCovList - }{ - { - newList: CoverageList{Coverage{FileName: "fake-coverage", NCoveredStmts: 15, NAllStmts: 20}}, - baseList: CoverageList{Coverage{FileName: "fake-coverage-v1", NCoveredStmts: 10, NAllStmts: 20}}, - changedFiles: []string{"fake-coverage"}, - expectDelta: DeltaCovList{{FileName: "fake-coverage", BasePer: "None", NewPer: "75.0%", DeltaPer: "75.0%"}}, - }, - } - for _, tc := range items { - d := GetChFileDeltaCov(tc.newList, tc.baseList, tc.changedFiles) - assert.Equal(t, tc.expectDelta, d) - } -} - -func TestMapAndSort(t *testing.T) { - items := []struct { - dList DeltaCovList - expectMap map[string]DeltaCov - expectSort DeltaCovList - }{ - { - dList: DeltaCovList{DeltaCov{FileName: "b", BasePer: "10.0%", NewPer: "20.0%", DeltaPer: "10.0%"}, - DeltaCov{FileName: "a", BasePer: "10.0%", NewPer: "30.0%", DeltaPer: "20.0%"}, - }, - expectMap: map[string]DeltaCov{ - "a": {FileName: "a", BasePer: "10.0%", NewPer: "30.0%", DeltaPer: "20.0%"}, - "b": {FileName: "b", BasePer: "10.0%", NewPer: "20.0%", DeltaPer: "10.0%"}, - }, - expectSort: DeltaCovList{DeltaCov{FileName: "a", BasePer: "10.0%", NewPer: "30.0%", DeltaPer: "20.0%"}, - DeltaCov{FileName: "b", BasePer: "10.0%", NewPer: "20.0%", DeltaPer: "10.0%"}, - }, - }, - { - dList: DeltaCovList{DeltaCov{FileName: "b", BasePer: "10.0%", NewPer: "20.0%", DeltaPer: "10.0%"}, - DeltaCov{FileName: "b-1", BasePer: "10.0%", NewPer: "30.0%", DeltaPer: "20.0%"}, - DeltaCov{FileName: "1-b", BasePer: "10.0%", NewPer: "40.0%", DeltaPer: "30.0%"}, - }, - expectMap: map[string]DeltaCov{ - "1-b": {FileName: "1-b", BasePer: "10.0%", NewPer: "40.0%", DeltaPer: "30.0%"}, - "b": {FileName: "b", BasePer: "10.0%", NewPer: "20.0%", DeltaPer: "10.0%"}, - "b-1": {FileName: "b-1", BasePer: "10.0%", NewPer: "30.0%", DeltaPer: "20.0%"}, - }, - expectSort: DeltaCovList{DeltaCov{FileName: "1-b", BasePer: "10.0%", NewPer: "40.0%", DeltaPer: "30.0%"}, - DeltaCov{FileName: "b", BasePer: "10.0%", NewPer: "20.0%", DeltaPer: "10.0%"}, - DeltaCov{FileName: "b-1", BasePer: "10.0%", NewPer: "30.0%", DeltaPer: "20.0%"}, - }, - }, - } - - for _, tc := range items { - assert.Equal(t, tc.expectMap, tc.dList.Map()) - tc.dList.Sort() - assert.Equal(t, tc.expectSort, tc.dList) - - } - -} diff --git a/pkg/cover/instrument.go b/pkg/cover/instrument.go deleted file mode 100644 index 4719e8f..0000000 --- a/pkg/cover/instrument.go +++ /dev/null @@ -1,505 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.com) - - 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 cover - -import ( - "fmt" - "os" - "path" - "path/filepath" - "text/template" -) - -// InjectCountersHandlers generate a file _cover_http_apis.go besides the main.go file -func InjectCountersHandlers(tc TestCover, dest string) error { - f, err := os.Create(dest) - if err != nil { - return err - } - if err := coverMainTmpl.Execute(f, tc); err != nil { - return err - } - return nil -} - -var coverMainTmpl = template.Must(template.New("coverMain").Parse(coverMain)) - -const coverMain = ` -// Code generated by goc system. DO NOT EDIT. - -package main - -import ( - "bufio" - "bytes" - "encoding/json" - "fmt" - "io" - "io/ioutil" - "log" - "net" - "net/http" - "os" - "os/signal" - "path/filepath" - "strings" - "sync/atomic" - "syscall" - "testing" - - _cover {{.GlobalCoverVarImportPath | printf "%q"}} - -) - -func init() { - go registerHandlers() -} - -func loadValues() (map[string][]uint32, map[string][]testing.CoverBlock) { - var ( - coverCounters = make(map[string][]uint32) - coverBlocks = make(map[string][]testing.CoverBlock) - ) - - {{range $i, $pkgCover := .DepsCover}} - {{range $file, $cover := $pkgCover.Vars}} - loadFileCover(coverCounters, coverBlocks, {{printf "%q" $cover.File}}, _cover.{{$cover.Var}}.Count[:], _cover.{{$cover.Var}}.Pos[:], _cover.{{$cover.Var}}.NumStmt[:]) - {{end}} - {{end}} - - {{range $file, $cover := .MainPkgCover.Vars}} - loadFileCover(coverCounters, coverBlocks, {{printf "%q" $cover.File}}, _cover.{{$cover.Var}}.Count[:], _cover.{{$cover.Var}}.Pos[:], _cover.{{$cover.Var}}.NumStmt[:]) - {{end}} - - return coverCounters, coverBlocks -} - -func loadFileCover(coverCounters map[string][]uint32, coverBlocks map[string][]testing.CoverBlock, fileName string, counter []uint32, pos []uint32, numStmts []uint16) { - if 3*len(counter) != len(pos) || len(counter) != len(numStmts) { - panic("coverage: mismatched sizes") - } - if coverCounters[fileName] != nil { - // Already registered. - return - } - coverCounters[fileName] = counter - block := make([]testing.CoverBlock, len(counter)) - for i := range counter { - block[i] = testing.CoverBlock{ - Line0: pos[3*i+0], - Col0: uint16(pos[3*i+2]), - Line1: pos[3*i+1], - Col1: uint16(pos[3*i+2] >> 16), - Stmts: numStmts[i], - } - } - coverBlocks[fileName] = block -} - -func clearValues() { - - {{range $i, $pkgCover := .DepsCover}} - {{range $file, $cover := $pkgCover.Vars}} - clearFileCover(_cover.{{$cover.Var}}.Count[:]) - {{end}} - {{end}} - - {{range $file, $cover := .MainPkgCover.Vars}} - clearFileCover(_cover.{{$cover.Var}}.Count[:]) - {{end}} - -} - -func clearFileCover(counter []uint32) { - for i := range counter { - counter[i] = 0 - } -} - -func registerHandlers() { - ln, host, err := listen() - if err != nil { - log.Fatalf("listen failed, err:%v", err) - } - - profileAddr := "http://" + host - if resp, err := registerSelf(profileAddr); err != nil { - log.Fatalf("register address %v failed, err: %v, response: %v", profileAddr, err, string(resp)) - } - - fn := func() { - var ( - err error - profileAddrs []string - addresses []string - ) - if addresses, err = getAllHosts(ln); err != nil { - log.Fatalf("get all host failed, err: %v", err) - return - } - for _, addr := range addresses { - profileAddrs = append(profileAddrs, "http://"+addr) - } - deregisterSelf(profileAddrs) - } - go watchSignal(fn) - - mux := http.NewServeMux() - // Coverage reports the current code coverage as a fraction in the range [0, 1]. - // If coverage is not enabled, Coverage returns 0. - mux.HandleFunc("/v1/cover/coverage", func(w http.ResponseWriter, r *http.Request) { - counters, _ := loadValues() - var n, d int64 - for _, counter := range counters { - for i := range counter { - if atomic.LoadUint32(&counter[i]) > 0 { - n++ - } - d++ - } - } - if d == 0 { - fmt.Fprint(w, 0) - return - } - fmt.Fprintf(w, "%f", float64(n)/float64(d)) - }) - - // coverprofile reports a coverage profile with the coverage percentage - mux.HandleFunc("/v1/cover/profile", func(w http.ResponseWriter, r *http.Request) { - fmt.Fprint(w, "mode: {{.Mode}}\n") - counters, blocks := loadValues() - var active, total int64 - var count uint32 - for name, counts := range counters { - block := blocks[name] - for i := range counts { - stmts := int64(block[i].Stmts) - total += stmts - count = atomic.LoadUint32(&counts[i]) // For -mode=atomic. - if count > 0 { - active += stmts - } - _, err := fmt.Fprintf(w, "%s:%d.%d,%d.%d %d %d\n", name, - block[i].Line0, block[i].Col0, - block[i].Line1, block[i].Col1, - stmts, - count) - if err != nil { - fmt.Fprintf(w, "invalid block format, err: %v", err) - return - } - } - } - }) - - mux.HandleFunc("/v1/cover/clear", func(w http.ResponseWriter, r *http.Request) { - clearValues() - w.WriteHeader(http.StatusOK) - fmt.Fprintln(w, "clear call successfully") - }) - - log.Fatal(http.Serve(ln, mux)) -} - -func registerSelf(address string) ([]byte, error) { - selfName := filepath.Base(os.Args[0]) - req, err := http.NewRequest("POST", fmt.Sprintf("%s/v1/cover/register?name=%s&address=%s", {{.Center | printf "%q"}}, selfName, address), nil) - if err != nil { - log.Fatalf("http.NewRequest failed: %v", err) - return nil, err - } - - resp, err := http.DefaultClient.Do(req) - if err != nil && isNetworkError(err) { - log.Printf("[goc][WARN]error occurred:%v, try again", err) - resp, err = http.DefaultClient.Do(req) - } - if err != nil { - return nil, fmt.Errorf("failed to register into coverage center, err:%v", err) - } - defer resp.Body.Close() - - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - return nil, fmt.Errorf("failed to read response body, err:%v", err) - } - - if resp.StatusCode != 200 { - err = fmt.Errorf("failed to register into coverage center, response code %d", resp.StatusCode) - } - - return body, err -} - -func deregisterSelf(address []string) ([]byte, error) { - param := map[string]interface{}{ - "address": address, - } - jsonBody, err := json.Marshal(param) - if err != nil { - return nil, err - } - req, err := http.NewRequest("POST", fmt.Sprintf("%s/v1/cover/remove", {{.Center | printf "%q"}}), bytes.NewReader(jsonBody)) - if err != nil { - log.Fatalf("http.NewRequest failed: %v", err) - return nil, err - } - req.Header.Set("Content-Type", "application/json") - - resp, err := http.DefaultClient.Do(req) - if err != nil && isNetworkError(err) { - log.Printf("[goc][WARN]error occurred:%v, try again", err) - resp, err = http.DefaultClient.Do(req) - } - if err != nil { - return nil, fmt.Errorf("failed to deregister into coverage center, err:%v", err) - } - defer resp.Body.Close() - - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - return nil, fmt.Errorf("failed to read response body, err:%v", err) - } - - if resp.StatusCode != 200 { - err = fmt.Errorf("failed to deregister into coverage center, response code %d", resp.StatusCode) - } - - return body, err -} - -type CallbackFunc func() - -func watchSignal(fn CallbackFunc) { - // init signal - c := make(chan os.Signal, 1) - signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT) - for { - si := <-c - log.Printf("get a signal %s", si.String()) - switch si { - case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT: - fn() - os.Exit(0) // Exit successfully. - case syscall.SIGHUP: - default: - return - } - } -} - -func isNetworkError(err error) bool { - if err == io.EOF { - return true - } - _, ok := err.(net.Error) - return ok -} - -func listen() (ln net.Listener, host string, err error) { - agentPort := "{{.AgentPort }}" - if agentPort != "" { - if ln, err = net.Listen("tcp4", agentPort); err != nil { - return - } - if host, err = getRealHost(ln); err != nil { - return - } - } else { - // 获取上次使用的监听地址 - if previousAddr := getPreviousAddr(); previousAddr != "" { - ss := strings.Split(previousAddr, ":") - // listen on all network interface - ln, err = net.Listen("tcp4", ":"+ss[len(ss)-1]) - if err == nil { - host = previousAddr - return - } - } - if ln, err = net.Listen("tcp4", ":0"); err != nil { - return - } - if host, err = getRealHost(ln); err != nil { - return - } - } - go genProfileAddr(host) - return -} - -func getRealHost(ln net.Listener) (host string, err error) { - adds, err := net.InterfaceAddrs() - if err != nil { - return - } - - var localIPV4 string - var nonLocalIPV4 string - for _, addr := range adds { - if ipNet, ok := addr.(*net.IPNet); ok && ipNet.IP.To4() != nil { - if ipNet.IP.IsLoopback() { - localIPV4 = ipNet.IP.String() - } else { - nonLocalIPV4 = ipNet.IP.String() - } - } - } - if nonLocalIPV4 != "" { - host = fmt.Sprintf("%s:%d", nonLocalIPV4, ln.Addr().(*net.TCPAddr).Port) - } else { - host = fmt.Sprintf("%s:%d", localIPV4, ln.Addr().(*net.TCPAddr).Port) - } - - return -} - -func getAllHosts(ln net.Listener) (hosts []string, err error) { - adds, err := net.InterfaceAddrs() - if err != nil { - return - } - - var host string - for _, addr := range adds { - if ipNet, ok := addr.(*net.IPNet); ok && ipNet.IP.To4() != nil { - host = fmt.Sprintf("%s:%d", ipNet.IP.String(), ln.Addr().(*net.TCPAddr).Port) - hosts = append(hosts, host) - } - } - return -} - -func getPreviousAddr() string { - file, err := os.Open(os.Args[0] + "_profile_listen_addr") - if err != nil { - return "" - } - defer file.Close() - - reader := bufio.NewReader(file) - addr, _, _ := reader.ReadLine() - return string(addr) -} - -func genProfileAddr(profileAddr string) { - fn := os.Args[0] + "_profile_listen_addr" - f, err := os.OpenFile(fn, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644) - if err != nil { - log.Println(err) - return - } - defer f.Close() - - fmt.Fprintf(f, strings.TrimPrefix(profileAddr, "http://")) -} -` - -var coverParentFileTmpl = template.Must(template.New("coverParentFileTmpl").Parse(coverParentFile)) - -const coverParentFile = ` -// Code generated by goc system. DO NOT EDIT. - -package {{.}} - -` - -var coverParentVarsTmpl = template.Must(template.New("coverParentVarsTmpl").Parse(coverParentVars)) - -const coverParentVars = ` - -import ( - - {{range $i, $pkgCover := .}} - _cover{{$i}} {{$pkgCover.Package.ImportPath | printf "%q"}} - {{end}} - -) - -{{range $i, $pkgCover := .}} -{{range $v, $cover := $pkgCover.Vars}} -var {{$v}} = &_cover{{$i}}.{{$cover.Var}} -{{end}} -{{end}} - -` - -func InjectCacheCounters(covers map[string][]*PackageCover, cache map[string]*PackageCover) []error { - var errs []error - for k, v := range covers { - if pkg, ok := cache[k]; ok { - err := checkCacheDir(pkg.Package.Dir) - if err != nil { - errs = append(errs, err) - continue - } - _, pkgName := path.Split(k) - err = injectCache(v, pkgName, fmt.Sprintf("%s/%s", pkg.Package.Dir, pkg.Package.GoFiles[0])) - if err != nil { - errs = append(errs, err) - continue - } - } - } - return errs -} - -// InjectCacheCounters generate a file _cover_http_apis.go besides the main.go file -func injectCache(covers []*PackageCover, pkg, dest string) error { - f, err := os.Create(dest) - if err != nil { - return err - } - - if err := coverParentFileTmpl.Execute(f, pkg); err != nil { - return err - } - - if err := coverParentVarsTmpl.Execute(f, covers); err != nil { - return err - } - return nil -} - -func checkCacheDir(p string) error { - _, err := os.Stat(p) - if os.IsNotExist(err) { - err := os.Mkdir(p, 0755) - if err != nil { - return err - } - } - return nil -} - -func injectGlobalCoverVarFile(ci *CoverInfo, content string) error { - coverFile, err := os.Create(filepath.Join(ci.Target, ci.GlobalCoverVarImportPath, "cover.go")) - if err != nil { - return err - } - defer coverFile.Close() - - packageName := "package " + filepath.Base(ci.GlobalCoverVarImportPath) + "\n\n" - - _, err = coverFile.WriteString(packageName) - if err != nil { - return err - } - _, err = coverFile.WriteString(content) - - return err -} diff --git a/pkg/cover/internal/tool/cover.go b/pkg/cover/internal/tool/cover.go deleted file mode 100644 index 283f535..0000000 --- a/pkg/cover/internal/tool/cover.go +++ /dev/null @@ -1,775 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package tool - -import ( - "bytes" - // "flag" - "fmt" - "go/ast" - "go/parser" - "go/token" - "io" - "io/ioutil" - "os" - "sort" - - log "github.com/sirupsen/logrus" // QINIU - // "cmd/internal/edit" - // "cmd/internal/objabi" -) - -// const usageMessage = "" + -// `Usage of 'go tool cover': -// Given a coverage profile produced by 'go test': -// go test -coverprofile=c.out - -// Open a web browser displaying annotated source code: -// go tool cover -html=c.out - -// Write out an HTML file instead of launching a web browser: -// go tool cover -html=c.out -o coverage.html - -// Display coverage percentages to stdout for each function: -// go tool cover -func=c.out - -// Finally, to generate modified source code with coverage annotations -// (what go test -cover does): -// go tool cover -mode=set -var=CoverageVariableName program.go -// ` - -// func usage() { -// fmt.Fprintln(os.Stderr, usageMessage) -// fmt.Fprintln(os.Stderr, "Flags:") -// flag.PrintDefaults() -// fmt.Fprintln(os.Stderr, "\n Only one of -html, -func, or -mode may be set.") -// os.Exit(2) -// } - -// var ( -// mode = flag.String("mode", "", "coverage mode: set, count, atomic") -// varVar = flag.String("var", "GoCover", "name of coverage variable to generate") -// output = flag.String("o", "", "file for output; default: stdout") -// htmlOut = flag.String("html", "", "generate HTML representation of coverage profile") -// funcOut = flag.String("func", "", "output coverage profile information for each function") -// ) - -// var profile string // The profile to read; the value of -html or -func - -var counterStmt func(*File, string) string - -const ( - atomicPackagePath = "sync/atomic" - atomicPackageName = "_cover_atomic_" -) - -// func main() { -// objabi.AddVersionFlag() -// flag.Usage = usage -// flag.Parse() - -// // Usage information when no arguments. -// if flag.NFlag() == 0 && flag.NArg() == 0 { -// flag.Usage() -// } - -// err := parseFlags() -// if err != nil { -// fmt.Fprintln(os.Stderr, err) -// fmt.Fprintln(os.Stderr, `For usage information, run "go tool cover -help"`) -// os.Exit(2) -// } - -// // Generate coverage-annotated source. -// if *mode != "" { -// annotate(flag.Arg(0)) -// return -// } - -// // Output HTML or function coverage information. -// if *htmlOut != "" { -// err = htmlOutput(profile, *output) -// } else { -// err = funcOutput(profile, *output) -// } - -// if err != nil { -// fmt.Fprintf(os.Stderr, "cover: %v\n", err) -// os.Exit(2) -// } -// } - -// parseFlags sets the profile and counterStmt globals and performs validations. -// func parseFlags() error { -// profile = *htmlOut -// if *funcOut != "" { -// if profile != "" { -// return fmt.Errorf("too many options") -// } -// profile = *funcOut -// } - -// // Must either display a profile or rewrite Go source. -// if (profile == "") == (*mode == "") { -// return fmt.Errorf("too many options") -// } - -// if *varVar != "" && !token.IsIdentifier(*varVar) { -// return fmt.Errorf("-var: %q is not a valid identifier", *varVar) -// } - -// if *mode != "" { -// switch *mode { -// case "set": -// counterStmt = setCounterStmt -// case "count": -// counterStmt = incCounterStmt -// case "atomic": -// counterStmt = atomicCounterStmt -// default: -// return fmt.Errorf("unknown -mode %v", *mode) -// } - -// if flag.NArg() == 0 { -// return fmt.Errorf("missing source file") -// } else if flag.NArg() == 1 { -// return nil -// } -// } else if flag.NArg() == 0 { -// return nil -// } -// return fmt.Errorf("too many arguments") -// } - -// Block represents the information about a basic block to be recorded in the analysis. -// Note: Our definition of basic block is based on control structures; we don't break -// apart && and ||. We could but it doesn't seem important enough to bother. -type Block struct { - startByte token.Pos - endByte token.Pos - numStmt int -} - -// File is a wrapper for the state of a file used in the parser. -// The basic parse tree walker is a method of this type. -type File struct { - fset *token.FileSet - name string // Name of file. - astFile *ast.File - blocks []Block - content []byte - edit *Buffer // QINIU - varVar string // QINIU - mode string // QINIU -} - -// findText finds text in the original source, starting at pos. -// It correctly skips over comments and assumes it need not -// handle quoted strings. -// It returns a byte offset within f.src. -func (f *File) findText(pos token.Pos, text string) int { - b := []byte(text) - start := f.offset(pos) - i := start - s := f.content - for i < len(s) { - if bytes.HasPrefix(s[i:], b) { - return i - } - if i+2 <= len(s) && s[i] == '/' && s[i+1] == '/' { - for i < len(s) && s[i] != '\n' { - i++ - } - continue - } - if i+2 <= len(s) && s[i] == '/' && s[i+1] == '*' { - for i += 2; ; i++ { - if i+2 > len(s) { - return 0 - } - if s[i] == '*' && s[i+1] == '/' { - i += 2 - break - } - } - continue - } - i++ - } - return -1 -} - -// Visit implements the ast.Visitor interface. -func (f *File) Visit(node ast.Node) ast.Visitor { - switch n := node.(type) { - case *ast.BlockStmt: - // If it's a switch or select, the body is a list of case clauses; don't tag the block itself. - if len(n.List) > 0 { - switch n.List[0].(type) { - case *ast.CaseClause: // switch - for _, n := range n.List { - clause := n.(*ast.CaseClause) - f.addCounters(clause.Colon+1, clause.Colon+1, clause.End(), clause.Body, false) - } - return f - case *ast.CommClause: // select - for _, n := range n.List { - clause := n.(*ast.CommClause) - f.addCounters(clause.Colon+1, clause.Colon+1, clause.End(), clause.Body, false) - } - return f - } - } - f.addCounters(n.Lbrace, n.Lbrace+1, n.Rbrace+1, n.List, true) // +1 to step past closing brace. - case *ast.IfStmt: - if n.Init != nil { - ast.Walk(f, n.Init) - } - ast.Walk(f, n.Cond) - ast.Walk(f, n.Body) - if n.Else == nil { - return nil - } - // The elses are special, because if we have - // if x { - // } else if y { - // } - // we want to cover the "if y". To do this, we need a place to drop the counter, - // so we add a hidden block: - // if x { - // } else { - // if y { - // } - // } - elseOffset := f.findText(n.Body.End(), "else") - if elseOffset < 0 { - panic("lost else") - } - f.edit.Insert(elseOffset+4, "{") - f.edit.Insert(f.offset(n.Else.End()), "}") - - // We just created a block, now walk it. - // Adjust the position of the new block to start after - // the "else". That will cause it to follow the "{" - // we inserted above. - pos := f.fset.File(n.Body.End()).Pos(elseOffset + 4) - switch stmt := n.Else.(type) { - case *ast.IfStmt: - block := &ast.BlockStmt{ - Lbrace: pos, - List: []ast.Stmt{stmt}, - Rbrace: stmt.End(), - } - n.Else = block - case *ast.BlockStmt: - stmt.Lbrace = pos - default: - panic("unexpected node type in if") - } - ast.Walk(f, n.Else) - return nil - case *ast.SelectStmt: - // Don't annotate an empty select - creates a syntax error. - if n.Body == nil || len(n.Body.List) == 0 { - return nil - } - case *ast.SwitchStmt: - // Don't annotate an empty switch - creates a syntax error. - if n.Body == nil || len(n.Body.List) == 0 { - if n.Init != nil { - ast.Walk(f, n.Init) - } - if n.Tag != nil { - ast.Walk(f, n.Tag) - } - return nil - } - case *ast.TypeSwitchStmt: - // Don't annotate an empty type switch - creates a syntax error. - if n.Body == nil || len(n.Body.List) == 0 { - if n.Init != nil { - ast.Walk(f, n.Init) - } - ast.Walk(f, n.Assign) - return nil - } - } - return f -} - -// QINIU -// Annotate do following -// 1. add cover variables into the original file -// 2. return the cover variables declarations as plain string -// original dec: func annotate(name string) { -func Annotate(name string, mode string, varVar string, globalCoverVarImportPath string) string { - // QINIU - switch mode { - case "set": - counterStmt = setCounterStmt - case "count": - counterStmt = incCounterStmt - case "atomic": - counterStmt = atomicCounterStmt - default: - counterStmt = incCounterStmt - } - - fset := token.NewFileSet() - content, err := ioutil.ReadFile(name) - if err != nil { - log.Fatalf("cover: %s: %s", name, err) - } - parsedFile, err := parser.ParseFile(fset, name, content, parser.ParseComments) - if err != nil { - log.Fatalf("cover: %s: %s", name, err) - } - - file := &File{ - fset: fset, - name: name, - content: content, - edit: NewBuffer(content), // QINIU - astFile: parsedFile, - varVar: varVar, - mode: mode, - } - - ast.Walk(file, file.astFile) - newContent := file.edit.Bytes() - - if bytes.Equal(content, newContent) { - log.Info("no cover var injected for: ", name) - } else { - // reback to the beginning - file.astFile, _ = parser.ParseFile(fset, name, content, parser.ParseComments) - file.edit = NewBuffer(newContent) - // add global cover variables import path - file.edit.Insert(file.offset(file.astFile.Name.End()), - fmt.Sprintf("; import %s %q", ".", globalCoverVarImportPath)) - - if mode == "atomic" { - // Add import of sync/atomic immediately after package clause. - // We do this even if there is an existing import, because the - // existing import may be shadowed at any given place we want - // to refer to it, and our name (_cover_atomic_) is less likely to - // be shadowed. - file.edit.Insert(file.offset(file.astFile.Name.End()), - fmt.Sprintf("; import %s %q", atomicPackageName, atomicPackagePath)) - } - - newContent = file.edit.Bytes() - } - - // fd := os.Stdout - // if *output != "" { - // var err error - // fd, err = os.Create(*output) - // if err != nil { - // log.Fatalf("cover: %s", err) - // } - // } - fd, err := os.Create(name) - if err != nil { - log.Fatalf("cover: %s", err) - } - defer fd.Close() - - fmt.Fprintf(fd, "//line %s:1\n", name) - _, err = fd.Write(newContent) - if err != nil { - log.Fatalf("cover: %s", err) - } - - // After printing the source tree, add some declarations for the counters etc. - // We could do this by adding to the tree, but it's easier just to print the text. - - // QINIU - // declarations only print to string - // we will write all declarations into a single file - declBuf := bytes.NewBufferString("") - file.addVariables(declBuf) - return declBuf.String() -} - -// setCounterStmt returns the expression: __count[23] = 1. -func setCounterStmt(f *File, counter string) string { - return fmt.Sprintf("%s = 1", counter) -} - -// incCounterStmt returns the expression: __count[23]++. -func incCounterStmt(f *File, counter string) string { - return fmt.Sprintf("%s++", counter) -} - -// atomicCounterStmt returns the expression: atomic.AddUint32(&__count[23], 1) -func atomicCounterStmt(f *File, counter string) string { - return fmt.Sprintf("%s.AddUint32(&%s, 1)", atomicPackageName, counter) -} - -// QINIU -// newCounter creates a new counter expression of the appropriate form. -func (f *File) newCounter(start, end token.Pos, numStmt int) string { - stmt := counterStmt(f, fmt.Sprintf("%s.Count[%d]", f.varVar, len(f.blocks))) - f.blocks = append(f.blocks, Block{start, end, numStmt}) - return stmt -} - -// addCounters takes a list of statements and adds counters to the beginning of -// each basic block at the top level of that list. For instance, given -// -// S1 -// if cond { -// S2 -// } -// S3 -// -// counters will be added before S1 and before S3. The block containing S2 -// will be visited in a separate call. -// TODO: Nested simple blocks get unnecessary (but correct) counters -func (f *File) addCounters(pos, insertPos, blockEnd token.Pos, list []ast.Stmt, extendToClosingBrace bool) { - // Special case: make sure we add a counter to an empty block. Can't do this below - // or we will add a counter to an empty statement list after, say, a return statement. - if len(list) == 0 { - f.edit.Insert(f.offset(insertPos), f.newCounter(insertPos, blockEnd, 0)+";") - return - } - // Make a copy of the list, as we may mutate it and should leave the - // existing list intact. - list = append([]ast.Stmt(nil), list...) - // We have a block (statement list), but it may have several basic blocks due to the - // appearance of statements that affect the flow of control. - for { - // Find first statement that affects flow of control (break, continue, if, etc.). - // It will be the last statement of this basic block. - var last int - end := blockEnd - for last = 0; last < len(list); last++ { - stmt := list[last] - end = f.statementBoundary(stmt) - if f.endsBasicSourceBlock(stmt) { - // If it is a labeled statement, we need to place a counter between - // the label and its statement because it may be the target of a goto - // and thus start a basic block. That is, given - // foo: stmt - // we need to create - // foo: ; stmt - // and mark the label as a block-terminating statement. - // The result will then be - // foo: COUNTER[n]++; stmt - // However, we can't do this if the labeled statement is already - // a control statement, such as a labeled for. - if label, isLabel := stmt.(*ast.LabeledStmt); isLabel && !f.isControl(label.Stmt) { - newLabel := *label - newLabel.Stmt = &ast.EmptyStmt{ - Semicolon: label.Stmt.Pos(), - Implicit: true, - } - end = label.Pos() // Previous block ends before the label. - list[last] = &newLabel - // Open a gap and drop in the old statement, now without a label. - list = append(list, nil) - copy(list[last+1:], list[last:]) - list[last+1] = label.Stmt - } - last++ - extendToClosingBrace = false // Block is broken up now. - break - } - } - if extendToClosingBrace { - end = blockEnd - } - if pos != end { // Can have no source to cover if e.g. blocks abut. - f.edit.Insert(f.offset(insertPos), f.newCounter(pos, end, last)+";") - } - list = list[last:] - if len(list) == 0 { - break - } - pos = list[0].Pos() - insertPos = pos - } -} - -// hasFuncLiteral reports the existence and position of the first func literal -// in the node, if any. If a func literal appears, it usually marks the termination -// of a basic block because the function body is itself a block. -// Therefore we draw a line at the start of the body of the first function literal we find. -// TODO: what if there's more than one? Probably doesn't matter much. -func hasFuncLiteral(n ast.Node) (bool, token.Pos) { - if n == nil { - return false, 0 - } - var literal funcLitFinder - ast.Walk(&literal, n) - return literal.found(), token.Pos(literal) -} - -// statementBoundary finds the location in s that terminates the current basic -// block in the source. -func (f *File) statementBoundary(s ast.Stmt) token.Pos { - // Control flow statements are easy. - switch s := s.(type) { - case *ast.BlockStmt: - // Treat blocks like basic blocks to avoid overlapping counters. - return s.Lbrace - case *ast.IfStmt: - found, pos := hasFuncLiteral(s.Init) - if found { - return pos - } - found, pos = hasFuncLiteral(s.Cond) - if found { - return pos - } - return s.Body.Lbrace - case *ast.ForStmt: - found, pos := hasFuncLiteral(s.Init) - if found { - return pos - } - found, pos = hasFuncLiteral(s.Cond) - if found { - return pos - } - found, pos = hasFuncLiteral(s.Post) - if found { - return pos - } - return s.Body.Lbrace - case *ast.LabeledStmt: - return f.statementBoundary(s.Stmt) - case *ast.RangeStmt: - found, pos := hasFuncLiteral(s.X) - if found { - return pos - } - return s.Body.Lbrace - case *ast.SwitchStmt: - found, pos := hasFuncLiteral(s.Init) - if found { - return pos - } - found, pos = hasFuncLiteral(s.Tag) - if found { - return pos - } - return s.Body.Lbrace - case *ast.SelectStmt: - return s.Body.Lbrace - case *ast.TypeSwitchStmt: - found, pos := hasFuncLiteral(s.Init) - if found { - return pos - } - return s.Body.Lbrace - } - // If not a control flow statement, it is a declaration, expression, call, etc. and it may have a function literal. - // If it does, that's tricky because we want to exclude the body of the function from this block. - // Draw a line at the start of the body of the first function literal we find. - // TODO: what if there's more than one? Probably doesn't matter much. - found, pos := hasFuncLiteral(s) - if found { - return pos - } - return s.End() -} - -// endsBasicSourceBlock reports whether s changes the flow of control: break, if, etc., -// or if it's just problematic, for instance contains a function literal, which will complicate -// accounting due to the block-within-an expression. -func (f *File) endsBasicSourceBlock(s ast.Stmt) bool { - switch s := s.(type) { - case *ast.BlockStmt: - // Treat blocks like basic blocks to avoid overlapping counters. - return true - case *ast.BranchStmt: - return true - case *ast.ForStmt: - return true - case *ast.IfStmt: - return true - case *ast.LabeledStmt: - return true // A goto may branch here, starting a new basic block. - case *ast.RangeStmt: - return true - case *ast.SwitchStmt: - return true - case *ast.SelectStmt: - return true - case *ast.TypeSwitchStmt: - return true - case *ast.ExprStmt: - // Calls to panic change the flow. - // We really should verify that "panic" is the predefined function, - // but without type checking we can't and the likelihood of it being - // an actual problem is vanishingly small. - if call, ok := s.X.(*ast.CallExpr); ok { - if ident, ok := call.Fun.(*ast.Ident); ok && ident.Name == "panic" && len(call.Args) == 1 { - return true - } - } - } - found, _ := hasFuncLiteral(s) - return found -} - -// isControl reports whether s is a control statement that, if labeled, cannot be -// separated from its label. -func (f *File) isControl(s ast.Stmt) bool { - switch s.(type) { - case *ast.ForStmt, *ast.RangeStmt, *ast.SwitchStmt, *ast.SelectStmt, *ast.TypeSwitchStmt: - return true - } - return false -} - -// funcLitFinder implements the ast.Visitor pattern to find the location of any -// function literal in a subtree. -type funcLitFinder token.Pos - -func (f *funcLitFinder) Visit(node ast.Node) (w ast.Visitor) { - if f.found() { - return nil // Prune search. - } - switch n := node.(type) { - case *ast.FuncLit: - *f = funcLitFinder(n.Body.Lbrace) - return nil // Prune search. - } - return f -} - -func (f *funcLitFinder) found() bool { - return token.Pos(*f) != token.NoPos -} - -// Sort interface for []block1; used for self-check in addVariables. - -type block1 struct { - Block - index int -} - -type blockSlice []block1 - -func (b blockSlice) Len() int { return len(b) } -func (b blockSlice) Less(i, j int) bool { return b[i].startByte < b[j].startByte } -func (b blockSlice) Swap(i, j int) { b[i], b[j] = b[j], b[i] } - -// offset translates a token position into a 0-indexed byte offset. -func (f *File) offset(pos token.Pos) int { - return f.fset.Position(pos).Offset -} - -// addVariables adds to the end of the file the declarations to set up the counter and position variables. -func (f *File) addVariables(w io.Writer) { - // Self-check: Verify that the instrumented basic blocks are disjoint. - t := make([]block1, len(f.blocks)) - for i := range f.blocks { - t[i].Block = f.blocks[i] - t[i].index = i - } - sort.Sort(blockSlice(t)) - for i := 1; i < len(t); i++ { - if t[i-1].endByte > t[i].startByte { - fmt.Fprintf(os.Stderr, "cover: internal error: block %d overlaps block %d\n", t[i-1].index, t[i].index) - // Note: error message is in byte positions, not token positions. - fmt.Fprintf(os.Stderr, "\t%s:#%d,#%d %s:#%d,#%d\n", - f.name, f.offset(t[i-1].startByte), f.offset(t[i-1].endByte), - f.name, f.offset(t[i].startByte), f.offset(t[i].endByte)) - } - } - - // Declare the coverage struct as a package-level variable. - fmt.Fprintf(w, "\nvar %s = struct {\n", f.varVar) // QINIU - fmt.Fprintf(w, "\tCount [%d]uint32\n", len(f.blocks)) - fmt.Fprintf(w, "\tPos [3 * %d]uint32\n", len(f.blocks)) - fmt.Fprintf(w, "\tNumStmt [%d]uint16\n", len(f.blocks)) - fmt.Fprintf(w, "} {\n") - - // Initialize the position array field. - fmt.Fprintf(w, "\tPos: [3 * %d]uint32{\n", len(f.blocks)) - - // A nice long list of positions. Each position is encoded as follows to reduce size: - // - 32-bit starting line number - // - 32-bit ending line number - // - (16 bit ending column number << 16) | (16-bit starting column number). - for i, block := range f.blocks { - start := f.fset.Position(block.startByte) - end := f.fset.Position(block.endByte) - - start, end = dedup(start, end) - - fmt.Fprintf(w, "\t\t%d, %d, %#x, // [%d]\n", start.Line, end.Line, (end.Column&0xFFFF)<<16|(start.Column&0xFFFF), i) - } - - // Close the position array. - fmt.Fprintf(w, "\t},\n") - - // Initialize the position array field. - fmt.Fprintf(w, "\tNumStmt: [%d]uint16{\n", len(f.blocks)) - - // A nice long list of statements-per-block, so we can give a conventional - // valuation of "percent covered". To save space, it's a 16-bit number, so we - // clamp it if it overflows - won't matter in practice. - for i, block := range f.blocks { - n := block.numStmt - if n > 1<<16-1 { - n = 1<<16 - 1 - } - fmt.Fprintf(w, "\t\t%d, // %d\n", n, i) - } - - // Close the statements-per-block array. - fmt.Fprintf(w, "\t},\n") - - // Close the struct initialization. - fmt.Fprintf(w, "}\n") - - // Emit a reference to the atomic package to avoid - // import and not used error when there's no code in a file. - // if f.mode == "atomic" { // QINIU, no need to import - // fmt.Fprintf(w, "var _ = %s.LoadUint32\n", atomicPackageName) - // } -} - -// It is possible for positions to repeat when there is a line -// directive that does not specify column information and the input -// has not been passed through gofmt. -// See issues #27530 and #30746. -// Tests are TestHtmlUnformatted and TestLineDup. -// We use a map to avoid duplicates. - -// pos2 is a pair of token.Position values, used as a map key type. -type pos2 struct { - p1, p2 token.Position -} - -// seenPos2 tracks whether we have seen a token.Position pair. -var seenPos2 = make(map[pos2]bool) - -// dedup takes a token.Position pair and returns a pair that does not -// duplicate any existing pair. The returned pair will have the Offset -// fields cleared. -func dedup(p1, p2 token.Position) (r1, r2 token.Position) { - key := pos2{ - p1: p1, - p2: p2, - } - - // We want to ignore the Offset fields in the map, - // since cover uses only file/line/column. - key.p1.Offset = 0 - key.p2.Offset = 0 - - for seenPos2[key] { - key.p2.Column++ - } - seenPos2[key] = true - - return key.p1, key.p2 -} diff --git a/pkg/cover/internal/tool/edit.go b/pkg/cover/internal/tool/edit.go deleted file mode 100644 index ccfca27..0000000 --- a/pkg/cover/internal/tool/edit.go +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package edit implements buffered position-based editing of byte slices. -package tool - -import ( - "fmt" - "sort" -) - -// A Buffer is a queue of edits to apply to a given byte slice. -type Buffer struct { - old []byte - q edits -} - -// An edit records a single text modification: change the bytes in [start,end) to new. -type edit struct { - start int - end int - new string -} - -// An edits is a list of edits that is sortable by start offset, breaking ties by end offset. -type edits []edit - -func (x edits) Len() int { return len(x) } -func (x edits) Swap(i, j int) { x[i], x[j] = x[j], x[i] } -func (x edits) Less(i, j int) bool { - if x[i].start != x[j].start { - return x[i].start < x[j].start - } - return x[i].end < x[j].end -} - -// NewBuffer returns a new buffer to accumulate changes to an initial data slice. -// The returned buffer maintains a reference to the data, so the caller must ensure -// the data is not modified until after the Buffer is done being used. -func NewBuffer(data []byte) *Buffer { - return &Buffer{old: data} -} - -func (b *Buffer) Insert(pos int, new string) { - if pos < 0 || pos > len(b.old) { - panic("invalid edit position") - } - b.q = append(b.q, edit{pos, pos, new}) -} - -func (b *Buffer) Delete(start, end int) { - if end < start || start < 0 || end > len(b.old) { - panic("invalid edit position") - } - b.q = append(b.q, edit{start, end, ""}) -} - -func (b *Buffer) Replace(start, end int, new string) { - if end < start || start < 0 || end > len(b.old) { - panic("invalid edit position") - } - b.q = append(b.q, edit{start, end, new}) -} - -// Bytes returns a new byte slice containing the original data -// with the queued edits applied. -func (b *Buffer) Bytes() []byte { - // Sort edits by starting position and then by ending position. - // Breaking ties by ending position allows insertions at point x - // to be applied before a replacement of the text at [x, y). - sort.Stable(b.q) - - var new []byte - offset := 0 - for i, e := range b.q { - if e.start < offset { - e0 := b.q[i-1] - panic(fmt.Sprintf("overlapping edits: [%d,%d)->%q, [%d,%d)->%q", e0.start, e0.end, e0.new, e.start, e.end, e.new)) - } - new = append(new, b.old[offset:e.start]...) - offset = e.end - new = append(new, e.new...) - } - new = append(new, b.old[offset:]...) - return new -} - -// String returns a string containing the original data -// with the queued edits applied. -func (b *Buffer) String() string { - return string(b.Bytes()) -} diff --git a/pkg/cover/server.go b/pkg/cover/server.go deleted file mode 100644 index 9f058d1..0000000 --- a/pkg/cover/server.go +++ /dev/null @@ -1,394 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.com) - - 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 cover - -import ( - "bytes" - "fmt" - "io" - "io/ioutil" - "net" - "net/http" - "net/url" - "os" - "regexp" - - "github.com/gin-gonic/gin" - log "github.com/sirupsen/logrus" - "golang.org/x/tools/cover" - "k8s.io/test-infra/gopherage/pkg/cov" -) - -// LogFile a file to save log. -const LogFile = "goc.log" - -type server struct { - PersistenceFile string - Store Store -} - -// NewFileBasedServer new a file based server with persistenceFile -func NewFileBasedServer(persistenceFile string) (*server, error) { - store, err := NewFileStore(persistenceFile) - if err != nil { - return nil, err - } - return &server{ - PersistenceFile: persistenceFile, - Store: store, - }, nil -} - -// NewMemoryBasedServer new a memory based server without persistenceFile -func NewMemoryBasedServer() *server { - return &server{ - Store: NewMemoryStore(), - } -} - -// Run starts coverage host center -func (s *server) Run(port string) { - f, err := os.Create(LogFile) - if err != nil { - log.Fatalf("failed to create log file %s, err: %v", LogFile, err) - } - - // both log to stdout and file by default - mw := io.MultiWriter(f, os.Stdout) - r := s.Route(mw) - log.Fatal(r.Run(port)) -} - -// Router init goc server engine -func (s *server) Route(w io.Writer) *gin.Engine { - if w != nil { - gin.DefaultWriter = w - } - r := gin.Default() - // api to show the registered services - r.StaticFile("static", "./"+s.PersistenceFile) - - v1 := r.Group("/v1") - { - v1.POST("/cover/register", s.registerService) - v1.GET("/cover/profile", s.profile) - v1.POST("/cover/profile", s.profile) - v1.POST("/cover/clear", s.clear) - v1.POST("/cover/init", s.initSystem) - v1.GET("/cover/list", s.listServices) - v1.POST("/cover/remove", s.removeServices) - } - - return r -} - -// ServiceUnderTest is a entry under being tested -type ServiceUnderTest struct { - Name string `form:"name" json:"name" binding:"required"` - Address string `form:"address" json:"address" binding:"required"` -} - -// ProfileParam is param of profile API -type ProfileParam struct { - Force bool `form:"force" json:"force"` - Service []string `form:"service" json:"service"` - Address []string `form:"address" json:"address"` - CoverFilePatterns []string `form:"coverfile" json:"coverfile"` - SkipFilePatterns []string `form:"skipfile" json:"skipfile"` -} - -//listServices list all the registered services -func (s *server) listServices(c *gin.Context) { - services := s.Store.GetAll() - c.JSON(http.StatusOK, services) -} - -func (s *server) registerService(c *gin.Context) { - var service ServiceUnderTest - if err := c.ShouldBind(&service); err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) - return - } - - u, err := url.Parse(service.Address) - if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) - return - } - host, port, err := net.SplitHostPort(u.Host) - if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) - return - } - - realIP := c.ClientIP() - // only for IPV4 - // refer: https://github.com/qiniu/goc/issues/177 - if net.ParseIP(realIP).To4() != nil && host != realIP { - log.Printf("the registered host %s of service %s is different with the real one %s, here we choose the real one", service.Name, host, realIP) - service.Address = fmt.Sprintf("http://%s:%s", realIP, port) - } - - address := s.Store.Get(service.Name) - if !contains(address, service.Address) { - if err := s.Store.Add(service); err != nil && err != ErrServiceAlreadyRegistered { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - } - - c.JSON(http.StatusOK, gin.H{"result": "success"}) - return -} - -// profile API examples: -// POST /v1/cover/profile -// { "force": "true", "service":["a","b"], "address":["c","d"],"coverfile":["e","f"] } -func (s *server) profile(c *gin.Context) { - var body ProfileParam - if err := c.ShouldBind(&body); err != nil { - c.JSON(http.StatusExpectationFailed, gin.H{"error": err.Error()}) - return - } - - allInfos := s.Store.GetAll() - filterAddrList, err := filterAddrs(body.Service, body.Address, body.Force, allInfos) - if err != nil { - c.JSON(http.StatusExpectationFailed, gin.H{"error": err.Error()}) - return - } - - var mergedProfiles = make([][]*cover.Profile, 0) - for _, addr := range filterAddrList { - pp, err := NewWorker(addr).Profile(ProfileParam{}) - if err != nil { - if body.Force { - log.Warnf("get profile from [%s] failed, error: %s", addr, err.Error()) - continue - } - - c.JSON(http.StatusExpectationFailed, gin.H{"error": fmt.Sprintf("failed to get profile from %s, error %s", addr, err.Error())}) - return - } - - profile, err := convertProfile(pp) - if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - mergedProfiles = append(mergedProfiles, profile) - } - - if len(mergedProfiles) == 0 { - c.JSON(http.StatusExpectationFailed, gin.H{"error": "no profiles"}) - return - } - - merged, err := cov.MergeMultipleProfiles(mergedProfiles) - if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - if len(body.CoverFilePatterns) > 0 { - merged, err = filterProfile(body.CoverFilePatterns, merged) - if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("failed to filter profile based on the patterns: %v, error: %v", body.CoverFilePatterns, err)}) - return - } - } - - if len(body.SkipFilePatterns) > 0 { - merged, err = skipProfile(body.SkipFilePatterns, merged) - if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("failed to skip profile based on the patterns: %v, error: %v", body.SkipFilePatterns, err)}) - return - } - } - - if err := cov.DumpProfile(merged, c.Writer); err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } -} - -// filterProfile filters profiles of the packages matching the coverFile pattern -func filterProfile(coverFile []string, profiles []*cover.Profile) ([]*cover.Profile, error) { - var out = make([]*cover.Profile, 0) - for _, profile := range profiles { - for _, pattern := range coverFile { - matched, err := regexp.MatchString(pattern, profile.FileName) - if err != nil { - return nil, fmt.Errorf("filterProfile failed with pattern %s for profile %s, err: %v", pattern, profile.FileName, err) - } - if matched { - out = append(out, profile) - break // no need to check again for the file - } - } - } - - return out, nil -} - -// skipProfile skips profiles of the packages matching the skipFile pattern -func skipProfile(skipFile []string, profiles []*cover.Profile) ([]*cover.Profile, error) { - var out = make([]*cover.Profile, 0) - for _, profile := range profiles { - var shouldSkip bool - for _, pattern := range skipFile { - matched, err := regexp.MatchString(pattern, profile.FileName) - if err != nil { - return nil, fmt.Errorf("filterProfile failed with pattern %s for profile %s, err: %v", pattern, profile.FileName, err) - } - - if matched { - shouldSkip = true - break // no need to check again for the file - } - } - - if !shouldSkip { - out = append(out, profile) - } - } - - return out, nil -} - -func (s *server) clear(c *gin.Context) { - var body ProfileParam - if err := c.ShouldBind(&body); err != nil { - c.JSON(http.StatusExpectationFailed, gin.H{"error": err.Error()}) - return - } - svrsUnderTest := s.Store.GetAll() - filterAddrList, err := filterAddrs(body.Service, body.Address, true, svrsUnderTest) - if err != nil { - c.JSON(http.StatusExpectationFailed, gin.H{"error": err.Error()}) - return - } - for _, addr := range filterAddrList { - pp, err := NewWorker(addr).Clear(ProfileParam{}) - if err != nil { - c.JSON(http.StatusExpectationFailed, gin.H{"error": err.Error()}) - return - } - fmt.Fprintf(c.Writer, "Register service %s coverage counter %s", addr, string(pp)) - } - -} - -func (s *server) initSystem(c *gin.Context) { - if err := s.Store.Init(); err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - c.JSON(http.StatusOK, "") -} - -func (s *server) removeServices(c *gin.Context) { - var body ProfileParam - if err := c.ShouldBind(&body); err != nil { - c.JSON(http.StatusExpectationFailed, gin.H{"error": err.Error()}) - return - } - svrsUnderTest := s.Store.GetAll() - filterAddrList, err := filterAddrs(body.Service, body.Address, true, svrsUnderTest) - if err != nil { - c.JSON(http.StatusExpectationFailed, gin.H{"error": err.Error()}) - return - } - for _, addr := range filterAddrList { - err := s.Store.Remove(addr) - if err != nil { - c.JSON(http.StatusExpectationFailed, gin.H{"error": err.Error()}) - return - } - fmt.Fprintf(c.Writer, "Register service %s removed from the center.", addr) - } -} - -func convertProfile(p []byte) ([]*cover.Profile, error) { - // Annoyingly, ParseProfiles only accepts a filename, so we have to write the bytes to disk - // so it can read them back. - // We could probably also just give it /dev/stdin, but that'll break on Windows. - tf, err := ioutil.TempFile("", "") - if err != nil { - return nil, fmt.Errorf("failed to create temp file, err: %v", err) - } - defer tf.Close() - defer os.Remove(tf.Name()) - if _, err := io.Copy(tf, bytes.NewReader(p)); err != nil { - return nil, fmt.Errorf("failed to copy data to temp file, err: %v", err) - } - - return cover.ParseProfiles(tf.Name()) -} - -func contains(arr []string, str string) bool { - for _, element := range arr { - if str == element { - return true - } - } - return false -} - -// filterAddrs filter address list by given service and address list -func filterAddrs(serviceList, addressList []string, force bool, allInfos map[string][]string) (filterAddrList []string, err error) { - addressAll := []string{} - for _, addr := range allInfos { - addressAll = append(addressAll, addr...) - } - - if len(serviceList) != 0 && len(addressList) != 0 { - return nil, fmt.Errorf("use 'service' flag and 'address' flag at the same time may cause ambiguity, please use them separately") - } - - // Add matched services to map - for _, name := range serviceList { - if addr, ok := allInfos[name]; ok { - filterAddrList = append(filterAddrList, addr...) - continue // jump to match the next service - } - if !force { - return nil, fmt.Errorf("service [%s] not found", name) - } - log.Warnf("service [%s] not found", name) - } - - // Add matched addresses to map - for _, addr := range addressList { - if contains(addressAll, addr) { - filterAddrList = append(filterAddrList, addr) - continue - } - if !force { - return nil, fmt.Errorf("address [%s] not found", addr) - } - log.Warnf("address [%s] not found", addr) - } - - if len(addressList) == 0 && len(serviceList) == 0 { - filterAddrList = addressAll - } - - // Return all services when all param is nil - return filterAddrList, nil -} diff --git a/pkg/cover/server_test.go b/pkg/cover/server_test.go deleted file mode 100644 index 5ccbaaa..0000000 --- a/pkg/cover/server_test.go +++ /dev/null @@ -1,527 +0,0 @@ -package cover - -import ( - "bytes" - "encoding/json" - "fmt" - "net/http" - "net/http/httptest" - "net/url" - "os" - "reflect" - "strings" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "golang.org/x/tools/cover" -) - -// MockStore is mock store mainly for unittest -type MockStore struct { - mock.Mock -} - -func (m *MockStore) Add(s ServiceUnderTest) error { - args := m.Called(s) - return args.Error(0) -} - -func (m *MockStore) Remove(a string) error { - args := m.Called(a) - return args.Error(0) -} - -func (m *MockStore) Get(name string) []string { - args := m.Called(name) - return args.Get(0).([]string) -} - -func (m *MockStore) GetAll() map[string][]string { - args := m.Called() - return args.Get(0).(map[string][]string) -} - -func (m *MockStore) Init() error { - args := m.Called() - return args.Error(0) -} - -func (m *MockStore) Set(services map[string][]string) error { - args := m.Called() - return args.Error(0) -} - -func TestContains(t *testing.T) { - assert.Equal(t, contains([]string{"a", "b"}, "a"), true) - assert.Equal(t, contains([]string{"a", "b"}, "c"), false) -} - -func TestFilterAddrs(t *testing.T) { - svrAll := map[string][]string{ - "service1": {"http://127.0.0.1:7777", "http://127.0.0.1:8888"}, - "service2": {"http://127.0.0.1:9999"}, - } - addrAll := []string{} - for _, addr := range svrAll { - addrAll = append(addrAll, addr...) - } - items := []struct { - svrList []string - addrList []string - force bool - err string - addrRes []string - }{ - { - svrList: []string{"service1"}, - addrList: []string{"http://127.0.0.1:7777"}, - err: "use 'service' flag and 'address' flag at the same time may cause ambiguity, please use them separately", - }, - { - addrRes: addrAll, - }, - { - svrList: []string{"service1", "unknown"}, - err: "service [unknown] not found", - }, - { - svrList: []string{"service1", "service2", "unknown"}, - force: true, - addrRes: addrAll, - }, - { - svrList: []string{"unknown"}, - force: true, - }, - { - addrList: []string{"http://127.0.0.1:7777", "http://127.0.0.2:7777"}, - err: "address [http://127.0.0.2:7777] not found", - }, - { - addrList: []string{"http://127.0.0.1:7777", "http://127.0.0.1:9999", "http://127.0.0.2:7777"}, - force: true, - addrRes: []string{"http://127.0.0.1:7777", "http://127.0.0.1:9999"}, - }, - } - for _, item := range items { - addrs, err := filterAddrs(item.svrList, item.addrList, item.force, svrAll) - if err != nil { - assert.Equal(t, err.Error(), item.err) - } else { - if len(addrs) == 0 { - assert.Equal(t, addrs, item.addrRes) - } - for _, a := range addrs { - assert.Contains(t, item.addrRes, a) - } - } - } -} - -func TestRegisterService(t *testing.T) { - server, err := NewFileBasedServer("_svrs_address.txt") - assert.NoError(t, err) - router := server.Route(os.Stdout) - - // register with empty service struct - w := httptest.NewRecorder() - req, _ := http.NewRequest("POST", "/v1/cover/register", nil) - router.ServeHTTP(w, req) - - assert.Equal(t, http.StatusBadRequest, w.Code) - - // register with invalid service.Address - data := url.Values{} - data.Set("name", "aaa") - data.Set("address", "&%%") - w = httptest.NewRecorder() - req, _ = http.NewRequest("POST", "/v1/cover/register", strings.NewReader(data.Encode())) - req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - router.ServeHTTP(w, req) - - assert.Equal(t, http.StatusBadRequest, w.Code) - assert.Contains(t, w.Body.String(), "invalid URL escape") - - // register with host but no port - data = url.Values{} - data.Set("name", "aaa") - data.Set("address", "http://127.0.0.1") - w = httptest.NewRecorder() - req, _ = http.NewRequest("POST", "/v1/cover/register", strings.NewReader(data.Encode())) - req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - router.ServeHTTP(w, req) - - assert.Equal(t, http.StatusBadRequest, w.Code) - assert.Contains(t, w.Body.String(), "missing port in address") - - // register with store failure - expectedS := ServiceUnderTest{ - Name: "foo", - Address: "http://:64444", // the real IP is empty in unittest, so server will get a empty one - } - testObj := new(MockStore) - testObj.On("Get", "foo").Return([]string{"http://127.0.0.1:66666"}) - testObj.On("Add", expectedS).Return(fmt.Errorf("lala error")) - - server.Store = testObj - - w = httptest.NewRecorder() - data.Set("name", expectedS.Name) - data.Set("address", expectedS.Address) - req, _ = http.NewRequest("POST", "/v1/cover/register", strings.NewReader(data.Encode())) - req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - router.ServeHTTP(w, req) - - assert.Equal(t, http.StatusInternalServerError, w.Code) - assert.Contains(t, w.Body.String(), "lala error") -} - -func TestProfileService(t *testing.T) { - server, err := NewFileBasedServer("_svrs_address.txt") - assert.NoError(t, err) - router := server.Route(os.Stdout) - - // get profile with invalid force parameter - w := httptest.NewRecorder() - req, _ := http.NewRequest("GET", "/v1/cover/profile?force=11", nil) - router.ServeHTTP(w, req) - - assert.Equal(t, http.StatusExpectationFailed, w.Code) - assert.Contains(t, w.Body.String(), "invalid syntax") -} - -func TestClearService(t *testing.T) { - testObj := new(MockStore) - testObj.On("GetAll").Return(map[string][]string{"foo": {"http://127.0.0.1:66666"}}) - - server := &server{ - Store: testObj, - } - router := server.Route(os.Stdout) - - // clear profile with non-exist port - w := httptest.NewRecorder() - req, _ := http.NewRequest("POST", "/v1/cover/clear", bytes.NewBuffer([]byte(`{}`))) - req.Header.Set("Content-Type", "application/json") - router.ServeHTTP(w, req) - - assert.Equal(t, http.StatusExpectationFailed, w.Code) - assert.Contains(t, w.Body.String(), "invalid port") - - // clear profile with invalid service - w = httptest.NewRecorder() - req, _ = http.NewRequest("POST", "/v1/cover/clear", nil) - req.Header.Set("Content-Type", "application/json") - router.ServeHTTP(w, req) - assert.Equal(t, http.StatusExpectationFailed, w.Code) - assert.Contains(t, w.Body.String(), "invalid request") - - // clear profile with service and address set at at the same time - p := ProfileParam{ - Service: []string{"goc"}, - Address: []string{"http://127.0.0.1:3333"}, - } - encoded, err := json.Marshal(p) - assert.NoError(t, err) - w = httptest.NewRecorder() - req, _ = http.NewRequest("POST", "/v1/cover/clear", bytes.NewBuffer(encoded)) - req.Header.Set("Content-Type", "application/json") - router.ServeHTTP(w, req) - assert.Equal(t, http.StatusExpectationFailed, w.Code) - assert.Contains(t, w.Body.String(), "use 'service' flag and 'address' flag at the same time may cause ambiguity, please use them separately") -} - -func TestRemoveServices(t *testing.T) { - testObj := new(MockStore) - testObj.On("GetAll").Return(map[string][]string{"foo": {"test1", "test2"}}) - testObj.On("Remove", "test1").Return(nil) - - server := &server{ - Store: testObj, - } - router := server.Route(os.Stdout) - - // remove with invalid request - w := httptest.NewRecorder() - req, _ := http.NewRequest("POST", "/v1/cover/remove", nil) - req.Header.Set("Content-Type", "application/json") - router.ServeHTTP(w, req) - - assert.Equal(t, http.StatusExpectationFailed, w.Code) - assert.Contains(t, w.Body.String(), "invalid request") - - // remove service - p := ProfileParam{ - Address: []string{"test1"}, - } - encoded, err := json.Marshal(p) - assert.NoError(t, err) - w = httptest.NewRecorder() - req, _ = http.NewRequest("POST", "/v1/cover/remove", bytes.NewBuffer(encoded)) - req.Header.Set("Content-Type", "application/json") - router.ServeHTTP(w, req) - - assert.Equal(t, http.StatusOK, w.Code) - assert.Contains(t, w.Body.String(), "Register service test1 removed from the center.") - - // remove service with non-exist address - testObj.On("Remove", "test2").Return(fmt.Errorf("no service found")) - p = ProfileParam{ - Address: []string{"test2"}, - } - encoded, err = json.Marshal(p) - assert.NoError(t, err) - w = httptest.NewRecorder() - req, _ = http.NewRequest("POST", "/v1/cover/remove", bytes.NewBuffer(encoded)) - req.Header.Set("Content-Type", "application/json") - router.ServeHTTP(w, req) - - assert.Equal(t, http.StatusExpectationFailed, w.Code) - assert.Contains(t, w.Body.String(), "no service found") - - // clear profile with service and address set at at the same time - p = ProfileParam{ - Service: []string{"goc"}, - Address: []string{"http://127.0.0.1:3333"}, - } - encoded, err = json.Marshal(p) - assert.NoError(t, err) - w = httptest.NewRecorder() - req, _ = http.NewRequest("POST", "/v1/cover/remove", bytes.NewBuffer(encoded)) - req.Header.Set("Content-Type", "application/json") - router.ServeHTTP(w, req) - assert.Equal(t, http.StatusExpectationFailed, w.Code) - assert.Contains(t, w.Body.String(), "use 'service' flag and 'address' flag at the same time may cause ambiguity, please use them separately") -} - -func TestInitService(t *testing.T) { - testObj := new(MockStore) - testObj.On("Init").Return(fmt.Errorf("lala error")) - - server := &server{ - Store: testObj, - } - router := server.Route(os.Stdout) - - // get profile with invalid force parameter - w := httptest.NewRecorder() - req, _ := http.NewRequest("POST", "/v1/cover/init", nil) - router.ServeHTTP(w, req) - - assert.Equal(t, http.StatusInternalServerError, w.Code) - assert.Contains(t, w.Body.String(), "lala error") -} - -func TestFilterProfile(t *testing.T) { - var tcs = []struct { - name string - pattern []string - input []*cover.Profile - output []*cover.Profile - expectErr bool - }{ - { - name: "normal path", - pattern: []string{"some/fancy/gopath", "a/fancy/gopath"}, - input: []*cover.Profile{ - { - FileName: "some/fancy/gopath/a.go", - }, - { - FileName: "some/fancy/gopath/b/a.go", - }, - { - FileName: "a/fancy/gopath/a.go", - }, - { - FileName: "b/fancy/gopath/a.go", - }, - { - FileName: "b/a/fancy/gopath/a.go", - }, - }, - output: []*cover.Profile{ - { - FileName: "some/fancy/gopath/a.go", - }, - { - FileName: "some/fancy/gopath/b/a.go", - }, - { - FileName: "a/fancy/gopath/a.go", - }, - { - FileName: "b/a/fancy/gopath/a.go", - }, - }, - }, - { - name: "with regular expression", - pattern: []string{"fancy/gopath/a.go$", "^b/a/"}, - input: []*cover.Profile{ - { - FileName: "some/fancy/gopath/a.go", - }, - { - FileName: "some/fancy/gopath/b/a.go", - }, - { - FileName: "a/fancy/gopath/a.go", - }, - { - FileName: "b/fancy/gopath/c/a.go", - }, - { - FileName: "b/a/fancy/gopath/a.go", - }, - }, - output: []*cover.Profile{ - { - FileName: "some/fancy/gopath/a.go", - }, - { - FileName: "a/fancy/gopath/a.go", - }, - { - FileName: "b/a/fancy/gopath/a.go", - }, - }, - }, - { - name: "with invalid regular expression", - pattern: []string{"(?!a)"}, - input: []*cover.Profile{ - { - FileName: "some/fancy/gopath/a.go", - }, - }, - expectErr: true, - }, - } - - for _, tc := range tcs { - t.Run(tc.name, func(t *testing.T) { - out, err := filterProfile(tc.pattern, tc.input) - if err != nil { - if !tc.expectErr { - t.Errorf("Unexpected error: %v", err) - } - return - } - - if tc.expectErr { - t.Errorf("Expected an error, but got value %s", stringifyCoverProfile(out)) - } - - if !reflect.DeepEqual(out, tc.output) { - t.Errorf("Mismatched results. \nExpected: %s\nActual:%s", stringifyCoverProfile(tc.output), stringifyCoverProfile(out)) - } - }) - } -} - -func TestSkipProfile(t *testing.T) { - var tcs = []struct { - name string - pattern []string - input []*cover.Profile - output []*cover.Profile - expectErr bool - }{ - { - name: "normal path", - pattern: []string{"some/fancy/gopath", "a/fancy/gopath"}, - input: []*cover.Profile{ - { - FileName: "some/fancy/gopath/a.go", - }, - { - FileName: "some/fancy/gopath/b/a.go", - }, - { - FileName: "a/fancy/gopath/a.go", - }, - { - FileName: "b/fancy/gopath/a.go", - }, - { - FileName: "b/a/fancy/gopath/a.go", - }, - }, - output: []*cover.Profile{ - { - FileName: "b/fancy/gopath/a.go", - }, - }, - }, - { - name: "with regular expression", - pattern: []string{"fancy/gopath/a.go$", "^b/a/"}, - input: []*cover.Profile{ - { - FileName: "some/fancy/gopath/a.go", - }, - { - FileName: "some/fancy/gopath/b/a.go", - }, - { - FileName: "a/fancy/gopath/a.go", - }, - { - FileName: "b/fancy/gopath/c/a.go", - }, - { - FileName: "b/a/fancy/gopath/a.go", - }, - }, - output: []*cover.Profile{ - { - FileName: "some/fancy/gopath/b/a.go", - }, - { - FileName: "b/fancy/gopath/c/a.go", - }, - }, - }, - { - name: "with invalid regular expression", - pattern: []string{"(?!a)"}, - input: []*cover.Profile{ - { - FileName: "some/fancy/gopath/a.go", - }, - }, - expectErr: true, - }, - } - - for _, tc := range tcs { - t.Run(tc.name, func(t *testing.T) { - out, err := skipProfile(tc.pattern, tc.input) - if err != nil { - if !tc.expectErr { - t.Errorf("Unexpected error: %v", err) - } - return - } - - if tc.expectErr { - t.Errorf("Expected an error, but got value %s", stringifyCoverProfile(out)) - } - - if !reflect.DeepEqual(out, tc.output) { - t.Errorf("Mismatched results. \nExpected: %s\nActual:%s", stringifyCoverProfile(tc.output), stringifyCoverProfile(out)) - } - }) - } -} - -func stringifyCoverProfile(profiles []*cover.Profile) string { - res := make([]cover.Profile, 0, len(profiles)) - for _, p := range profiles { - res = append(res, *p) - } - - return fmt.Sprintf("%#v", res) -} diff --git a/pkg/cover/store.go b/pkg/cover/store.go deleted file mode 100644 index 0929039..0000000 --- a/pkg/cover/store.go +++ /dev/null @@ -1,324 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.com) - - 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 cover - -import ( - "bufio" - "errors" - "fmt" - "os" - "path/filepath" - "strings" - "sync" - - log "github.com/sirupsen/logrus" -) - -var ErrServiceAlreadyRegistered = errors.New("service already registered") - -// Store persistents the registered service information -type Store interface { - // Add adds the given service to store - Add(s ServiceUnderTest) error - - // Get returns the registered service information with the given service's name - Get(name string) []string - - // Get returns all the registered service information as a map - GetAll() map[string][]string - - // Init cleanup all the registered service information - Init() error - - // Set stores the services information into internal state - Set(services map[string][]string) error - - // Remove the service from the store by address - Remove(addr string) error -} - -// fileStore holds the registered services into memory and persistent to a local file -type fileStore struct { - mu sync.RWMutex - persistentFile string - - memoryStore Store -} - -// NewFileStore creates a store using local file -func NewFileStore(persistenceFile string) (store Store, err error) { - path, err := filepath.Abs(persistenceFile) - if err != nil { - return nil, err - } - err = os.MkdirAll(filepath.Dir(path), os.ModePerm) - if err != nil { - return nil, err - } - l := &fileStore{ - persistentFile: path, - memoryStore: NewMemoryStore(), - } - - if err := l.load(); err != nil { - log.Fatalf("load failed, file: %s, err: %v", l.persistentFile, err) - } - - return l, nil -} - -// Add adds the given service to file Store -func (l *fileStore) Add(s ServiceUnderTest) error { - if err := l.memoryStore.Add(s); err != nil { - return err - } - - // persistent to local store - l.mu.Lock() - defer l.mu.Unlock() - return l.appendToFile(s) -} - -// Get returns the registered service information with the given name -func (l *fileStore) Get(name string) []string { - return l.memoryStore.Get(name) -} - -// Get returns all the registered service information -func (l *fileStore) GetAll() map[string][]string { - return l.memoryStore.GetAll() -} - -// Remove the service from the memory store and the file store -func (l *fileStore) Remove(addr string) error { - err := l.memoryStore.Remove(addr) - if err != nil { - return err - } - - return l.Set(l.memoryStore.GetAll()) -} - -// Init cleanup all the registered service information -// and the local persistent file -func (l *fileStore) Init() error { - if err := l.memoryStore.Init(); err != nil { - return err - } - - l.mu.Lock() - defer l.mu.Unlock() - if err := os.Remove(l.persistentFile); err != nil && !os.IsNotExist(err) { - return fmt.Errorf("failed to delete file %s, err: %v", l.persistentFile, err) - } - - return nil -} - -// load all registered service from file to memory -func (l *fileStore) load() error { - var svrsMap = make(map[string][]string, 0) - - f, err := os.Open(l.persistentFile) - if err != nil { - if os.IsNotExist(err) { - return nil - } - return fmt.Errorf("failed to open file, path: %s, err: %v", l.persistentFile, err) - } - defer f.Close() - - ns := bufio.NewScanner(f) - for ns.Scan() { - line := ns.Text() - ss := strings.FieldsFunc(line, split) - - // TODO: use regex - if len(ss) == 2 { - if urls, ok := svrsMap[ss[0]]; ok { - urls = append(urls, ss[1]) - svrsMap[ss[0]] = urls - } else { - svrsMap[ss[0]] = []string{ss[1]} - } - } - } - - if err := ns.Err(); err != nil { - return fmt.Errorf("read file failed, file: %s, err: %v", l.persistentFile, err) - } - - // set information to memory - l.memoryStore.Set(svrsMap) - return nil -} - -func (l *fileStore) Set(services map[string][]string) error { - l.mu.Lock() - defer l.mu.Unlock() - - // no error will return from memorystore.set - err := l.memoryStore.Set(services) - if err != nil { - return err - } - - f, err := os.OpenFile(l.persistentFile, os.O_TRUNC|os.O_WRONLY|os.O_CREATE, 0600) - if err != nil { - return err - } - - s := "" - for name, addrs := range services { - for _, addr := range addrs { - s += fmt.Sprintf("%s&%s\n", name, addr) - } - } - - _, err = f.WriteString(s) - if err != nil { - return err - } - - return f.Sync() -} - -func (l *fileStore) appendToFile(s ServiceUnderTest) error { - f, err := os.OpenFile(l.persistentFile, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600) - if err != nil { - return err - } - defer f.Close() - - _, err = f.WriteString(format(s) + "\n") - if err != nil { - return err - } - - f.Sync() - return nil -} - -func format(s ServiceUnderTest) string { - return fmt.Sprintf("%s&%s", s.Name, s.Address) -} - -func split(r rune) bool { - return r == '&' -} - -// memoryStore holds the registered services only into memory -type memoryStore struct { - mu sync.RWMutex - servicesMap map[string][]string -} - -// NewMemoryStore creates a memory store -func NewMemoryStore() Store { - return &memoryStore{ - servicesMap: make(map[string][]string, 0), - } -} - -// Add adds the given service to MemoryStore -func (l *memoryStore) Add(s ServiceUnderTest) error { - l.mu.Lock() - defer l.mu.Unlock() - // load to memory - if addrs, ok := l.servicesMap[s.Name]; ok { - for _, addr := range addrs { - if addr == s.Address { - log.Printf("service registered already, name: %s, address: %s", s.Name, s.Address) - return ErrServiceAlreadyRegistered - } - } - addrs = append(addrs, s.Address) - l.servicesMap[s.Name] = addrs - } else { - l.servicesMap[s.Name] = []string{s.Address} - } - - return nil -} - -// Get returns the registered service information with the given name -func (l *memoryStore) Get(name string) []string { - l.mu.RLock() - defer l.mu.RUnlock() - return l.servicesMap[name] -} - -// Get returns all the registered service information -func (l *memoryStore) GetAll() map[string][]string { - res := make(map[string][]string) - l.mu.RLock() - defer l.mu.RUnlock() - for k, v := range l.servicesMap { - res[k] = append(make([]string, 0, len(v)), v...) - } - return res -} - -// Init cleanup all the registered service information -// and the local persistent file -func (l *memoryStore) Init() error { - l.mu.Lock() - defer l.mu.Unlock() - - l.servicesMap = make(map[string][]string, 0) - return nil -} - -func (l *memoryStore) Set(services map[string][]string) error { - l.mu.Lock() - defer l.mu.Unlock() - - l.servicesMap = services - - return nil -} - -// Remove one service from the memory store -// if service is not fount, return "no service found" error -func (l *memoryStore) Remove(removeAddr string) error { - l.mu.Lock() - defer l.mu.Unlock() - - flag := false - for name, addrs := range l.servicesMap { - newAddrs := make([]string, 0) - for _, addr := range addrs { - if removeAddr != addr { - newAddrs = append(newAddrs, addr) - } else { - flag = true - } - } - // if no services left, remove by name - if len(newAddrs) == 0 { - delete(l.servicesMap, name) - } else { - l.servicesMap[name] = newAddrs - } - } - - if !flag { - return fmt.Errorf("no service found") - } - - return nil -} diff --git a/pkg/cover/store_test.go b/pkg/cover/store_test.go deleted file mode 100644 index bf3201f..0000000 --- a/pkg/cover/store_test.go +++ /dev/null @@ -1,130 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.com) - - 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 cover - -import ( - "fmt" - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestLocalStore(t *testing.T) { - localStore, err := NewFileStore("_svrs_address.txt") - assert.NoError(t, err) - var tc1 = ServiceUnderTest{ - Name: "a", - Address: "http://127.0.0.1", - } - var tc2 = ServiceUnderTest{ - Name: "b", - Address: "http://127.0.0.2", - } - var tc3 = ServiceUnderTest{ - Name: "c", - Address: "http://127.0.0.3", - } - var tc4 = ServiceUnderTest{ - Name: "a", - Address: "http://127.0.0.4", - } - assert.NoError(t, localStore.Add(tc1)) - assert.Equal(t, localStore.Add(tc1), ErrServiceAlreadyRegistered) - assert.NoError(t, localStore.Add(tc2)) - assert.NoError(t, localStore.Add(tc3)) - assert.NoError(t, localStore.Add(tc4)) - addrs := localStore.Get(tc1.Name) - if len(addrs) != 2 { - t.Error("unexpected result") - } - - for _, addr := range addrs { - if addr != tc1.Address && addr != tc4.Address { - t.Error("get address failed") - } - } - - if len(localStore.GetAll()) != 3 { - t.Error("local store check failed") - } - - localStoreNew, err := NewFileStore("_svrs_address.txt") - assert.NoError(t, err) - assert.Equal(t, localStore.GetAll(), localStoreNew.GetAll()) - - localStore.Init() - if len(localStore.GetAll()) != 0 { - t.Error("local store init failed") - } -} - -func TestMemoryStoreRemove(t *testing.T) { - store := NewMemoryStore() - s1 := ServiceUnderTest{Name: "test", Address: "http://127.0.0.1:8900"} - s2 := ServiceUnderTest{Name: "test2", Address: "http://127.0.0.1:8901"} - s3 := ServiceUnderTest{Name: "test2", Address: "http://127.0.0.1:8902"} - - _ = store.Add(s1) - _ = store.Add(s2) - _ = store.Add(s3) - - ss1 := store.Get("test") - assert.Equal(t, 1, len(ss1)) - err := store.Remove("http://127.0.0.1:8900") - assert.NoError(t, err) - ss1 = store.Get("test") - assert.Nil(t, ss1) - - ss2 := store.Get("test2") - assert.Equal(t, 2, len(ss2)) - err = store.Remove("http://127.0.0.1:8901") - assert.NoError(t, err) - ss2 = store.Get("test2") - assert.Equal(t, 1, len(ss2)) - - err = store.Remove("http") - assert.Error(t, err, fmt.Errorf("no service found")) -} - -func TestFileStoreRemove(t *testing.T) { - store, _ := NewFileStore("_svrs_address.txt") - _ = store.Init() - s1 := ServiceUnderTest{Name: "test", Address: "http://127.0.0.1:8900"} - s2 := ServiceUnderTest{Name: "test2", Address: "http://127.0.0.1:8901"} - s3 := ServiceUnderTest{Name: "test2", Address: "http://127.0.0.1:8902"} - - _ = store.Add(s1) - _ = store.Add(s2) - _ = store.Add(s3) - - ss1 := store.Get("test") - assert.Equal(t, 1, len(ss1)) - err := store.Remove("http://127.0.0.1:8900") - assert.NoError(t, err) - ss1 = store.Get("test") - assert.Nil(t, ss1) - - ss2 := store.Get("test2") - assert.Equal(t, 2, len(ss2)) - err = store.Remove("http://127.0.0.1:8901") - assert.NoError(t, err) - ss2 = store.Get("test2") - assert.Equal(t, 1, len(ss2)) - - err = store.Remove("http") - assert.Error(t, err, fmt.Errorf("no service found")) -} diff --git a/pkg/github/github.go b/pkg/github/github.go deleted file mode 100644 index 8b9092f..0000000 --- a/pkg/github/github.go +++ /dev/null @@ -1,203 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.com) - - 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 github - -import ( - "bytes" - "context" - "fmt" - "io/ioutil" - "os" - "strconv" - "strings" - - "github.com/google/go-github/github" - "github.com/hashicorp/go-retryablehttp" - "github.com/olekukonko/tablewriter" - "github.com/sirupsen/logrus" - "golang.org/x/oauth2" - - "github.com/qiniu/goc/pkg/cover" -) - -// CommentsPrefix is the prefix when commenting on Github Pull Requests -// It is also the flag when checking whether the target comment exists or not to avoid duplicate -const CommentsPrefix = "The following is the coverage report on the affected files." - -// PrComment is the interface of the entry which is able to comment on Github Pull Requests -type PrComment interface { - CreateGithubComment(commentPrefix string, diffCovList cover.DeltaCovList) (err error) - PostComment(content, commentPrefix string) error - EraseHistoryComment(commentPrefix string) error - GetPrChangedFiles() (files []string, err error) - GetCommentFlag() string -} - -// GitPrComment is the entry which is able to comment on Github Pull Requests -type GitPrComment struct { - RobotUserName string - RepoOwner string - RepoName string - CommentFlag string - PrNumber int - Ctx context.Context - opt *github.ListOptions - GithubClient *github.Client -} - -// NewPrClient creates an Client which be able to comment on Github Pull Request -func NewPrClient(githubTokenPath, repoOwner, repoName, prNumStr, botUserName, commentFlag string) *GitPrComment { - var client *github.Client - - // performs automatic retries when connection error occurs or a 500-range response code received (except 501) - retryClient := retryablehttp.NewClient() - ctx := context.WithValue(context.Background(), oauth2.HTTPClient, retryClient.StandardClient()) - - prNum, err := strconv.Atoi(prNumStr) - if err != nil { - logrus.WithError(err).Fatalf("Failed to convert prNumStr(=%v) to int.\n", prNumStr) - } - token, err := ioutil.ReadFile(githubTokenPath) - if err != nil { - logrus.WithError(err).Fatalf("Failed to get github token.\n") - } - ts := oauth2.StaticTokenSource( - &oauth2.Token{AccessToken: strings.TrimSpace(string(token))}, - ) - tc := oauth2.NewClient(ctx, ts) - client = github.NewClient(tc) - - return &GitPrComment{ - RobotUserName: botUserName, - RepoOwner: repoOwner, - RepoName: repoName, - PrNumber: prNum, - CommentFlag: commentFlag, - Ctx: ctx, - opt: &github.ListOptions{Page: 1}, - GithubClient: client, - } -} - -// CreateGithubComment post github comment of diff coverage -func (c *GitPrComment) CreateGithubComment(commentPrefix string, diffCovList cover.DeltaCovList) (err error) { - if len(diffCovList) == 0 { - logrus.Printf("Detect 0 files coverage diff, will not comment to github.") - return nil - } - content := GenCommentContent(commentPrefix, diffCovList) - - err = c.PostComment(content, commentPrefix) - if err != nil { - logrus.WithError(err).Fatalf("Post comment to github failed.") - } - - return -} - -// PostComment post comment on github. It erased the old one if existed to avoid duplicate -func (c *GitPrComment) PostComment(content, commentPrefix string) error { - //step1: erase history similar comment to avoid too many comment for same job - err := c.EraseHistoryComment(commentPrefix) - if err != nil { - return err - } - - //step2: post comment with new result - comment := &github.IssueComment{ - Body: &content, - } - _, _, err = c.GithubClient.Issues.CreateComment(c.Ctx, c.RepoOwner, c.RepoName, c.PrNumber, comment) - if err != nil { - return err - } - - return nil -} - -// EraseHistoryComment erase history similar comment before post again -func (c *GitPrComment) EraseHistoryComment(commentPrefix string) error { - comments, _, err := c.GithubClient.Issues.ListComments(c.Ctx, c.RepoOwner, c.RepoName, c.PrNumber, nil) - if err != nil { - logrus.Errorf("list PR comments failed.") - return err - } - logrus.Infof("the count of history comments by %s is: %v", c.RobotUserName, len(comments)) - - for _, cm := range comments { - if *cm.GetUser().Login == c.RobotUserName && strings.HasPrefix(cm.GetBody(), commentPrefix) { - _, err = c.GithubClient.Issues.DeleteComment(c.Ctx, c.RepoOwner, c.RepoName, *cm.ID) - if err != nil { - logrus.Errorf("delete PR comments %d failed.", *cm.ID) - return err - } - } - } - - return nil -} - -// GetPrChangedFiles get github pull request changes file list -func (c *GitPrComment) GetPrChangedFiles() (files []string, err error) { - var commitFiles []*github.CommitFile - for { - f, resp, err := c.GithubClient.PullRequests.ListFiles(c.Ctx, c.RepoOwner, c.RepoName, c.PrNumber, c.opt) - if err != nil { - logrus.Errorf("Get PR changed file failed. repoOwner is: %s, repoName is: %s, prNum is: %d", c.RepoOwner, c.RepoName, c.PrNumber) - return nil, err - } - commitFiles = append(commitFiles, f...) - if resp.NextPage == 0 { - break - } - c.opt.Page = resp.NextPage - } - logrus.Infof("get %d PR changed files:", len(commitFiles)) - for _, file := range commitFiles { - files = append(files, *file.Filename) - logrus.Infof("%s", *file.Filename) - } - return -} - -// GetCommentFlag get CommentFlag from the GitPrComment -func (c *GitPrComment) GetCommentFlag() string { - return c.CommentFlag -} - -// GenCommentContent generate github comment content based on diff coverage and commentFlag -func GenCommentContent(commentPrefix string, delta cover.DeltaCovList) string { - var buf bytes.Buffer - table := tablewriter.NewWriter(&buf) - table.SetHeader([]string{"File", "Base Coverage", "New Coverage", "Delta"}) - table.SetAutoFormatHeaders(false) - table.SetBorders(tablewriter.Border{Left: true, Top: false, Right: true, Bottom: false}) - table.SetCenterSeparator("|") - table.SetColumnAlignment([]int{tablewriter.ALIGN_LEFT, tablewriter.ALIGN_CENTER, tablewriter.ALIGN_CENTER, tablewriter.ALIGN_CENTER}) - for _, d := range delta { - table.Append([]string{fmt.Sprintf("[%s](%s)", d.FileName, d.LineCovLink), d.BasePer, d.NewPer, d.DeltaPer}) - } - table.Render() - - content := []string{ - commentPrefix, - fmt.Sprintf("Say `/test %s` to re-run this coverage report", os.Getenv("JOB_NAME")), - buf.String(), - } - - return strings.Join(content, "\n") -} diff --git a/pkg/github/github_test.go b/pkg/github/github_test.go deleted file mode 100644 index ffe7d1f..0000000 --- a/pkg/github/github_test.go +++ /dev/null @@ -1,176 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.com) - - 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 github - -import ( - "encoding/json" - "fmt" - "net/http" - "net/http/httptest" - "net/url" - "os" - "testing" - - "github.com/google/go-github/github" - "github.com/julienschmidt/httprouter" - "github.com/stretchr/testify/assert" - "golang.org/x/net/context" - - "github.com/qiniu/goc/pkg/cover" -) - -const ( - // baseURLPath is a non-empty Client.BaseURL path to use during tests, - // to ensure relative URLs are used for all endpoints. See issue #752. - baseURLPath = "/api-v3" -) - -// setup sets up a test HTTP server along with a github.Client that is -// configured to talk to that test server. Tests should register handlers on -// mux which provide mock responses for the API method being tested. -func setup() (client *github.Client, router *httprouter.Router, serverURL string, teardown func()) { - // router is the HTTP request multiplexer used with the test server. - router = httprouter.New() - - // We want to ensure that tests catch mistakes where the endpoint URL is - // specified as absolute rather than relative. It only makes a difference - // when there's a non-empty base URL path. So, use that. See issue #752. - apiHandler := http.NewServeMux() - apiHandler.Handle(baseURLPath+"/", http.StripPrefix(baseURLPath, router)) - apiHandler.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) { - fmt.Fprintln(os.Stderr, "FAIL: Client.BaseURL path prefix is not preserved in the request URL:") - fmt.Fprintln(os.Stderr) - fmt.Fprintln(os.Stderr, "\t"+req.URL.String()) - fmt.Fprintln(os.Stderr) - fmt.Fprintln(os.Stderr, "\tDid you accidentally use an absolute endpoint URL rather than relative?") - fmt.Fprintln(os.Stderr, "\tSee https://github.com/google/go-github/issues/752 for information.") - http.Error(w, "Client.BaseURL path prefix is not preserved in the request URL.", http.StatusInternalServerError) - }) - - // server is a test HTTP server used to provide mock API responses. - server := httptest.NewServer(apiHandler) - - // client is the GitHub client being tested and is - // configured to use test server. - client = github.NewClient(nil) - url, _ := url.Parse(server.URL + baseURLPath + "/") - client.BaseURL = url - client.UploadURL = url - - return client, router, server.URL, server.Close -} - -func TestNewPrClient(t *testing.T) { - items := []struct { - token string - repoOwner string - repoName string - prNumStr string - botUserName string - commentFlag string - expectPrNum int - }{ - {token: "github_test.go", repoOwner: "qiniu", repoName: "goc", prNumStr: "1", botUserName: "qiniu-bot", commentFlag: "test", expectPrNum: 1}, - } - - for _, tc := range items { - prClient := NewPrClient(tc.token, tc.repoOwner, tc.repoName, tc.prNumStr, tc.botUserName, tc.commentFlag) - assert.Equal(t, tc.expectPrNum, prClient.PrNumber) - } -} - -func TestCreateGithubComment(t *testing.T) { - client, router, _, teardown := setup() - defer teardown() - - var coverList = cover.DeltaCovList{{FileName: "fake-coverage", BasePer: "50.0%", NewPer: "75.0%", DeltaPer: "25.0%"}} - expectContent := GenCommentContent("", coverList) - comment := &github.IssueComment{ - Body: &expectContent, - } - - // create comment: https://developer.github.com/v3/issues/comments/#create-a-comment - router.HandlerFunc("POST", "/repos/qiniu/goc/issues/1/comments", func(w http.ResponseWriter, r *http.Request) { - v := new(github.IssueComment) - json.NewDecoder(r.Body).Decode(v) - assert.Equal(t, v, comment) - - fmt.Fprint(w, `{"id":1}`) - }) - - // list comment: https://developer.github.com/v3/issues/comments/#list-comments-on-an-issue - router.HandlerFunc("GET", "/repos/qiniu/goc/issues/1/comments", func(w http.ResponseWriter, r *http.Request) { - fmt.Fprint(w, `[{"id":1,"user": {"login": "qiniu-bot"}}]`) - }) - - // delete comment: https://developer.github.com/v3/issues/comments/#edit-a-comment - router.HandlerFunc("DELETE", "/repos/qiniu/goc/issues/comments/1", func(w http.ResponseWriter, r *http.Request) { - }) - - p := GitPrComment{ - RobotUserName: "qiniu-bot", - RepoOwner: "qiniu", - RepoName: "goc", - CommentFlag: "", - PrNumber: 1, - Ctx: context.Background(), - opt: nil, - GithubClient: client, - } - - p.CreateGithubComment("", coverList) -} - -func TestCreateGithubCommentError(t *testing.T) { - p := &GitPrComment{} - err := p.CreateGithubComment("", cover.DeltaCovList{}) - assert.NoError(t, err) -} - -func TestGetPrChangedFiles(t *testing.T) { - client, router, _, teardown := setup() - defer teardown() - - var expectFiles = []string{"src/qiniu.com/kodo/s3apiv2/bucket/bucket.go"} - - // list files API: https://developer.github.com/v3/pulls/#list-pull-requests-files - router.HandlerFunc("GET", "/repos/qiniu/goc/pulls/1/files", func(w http.ResponseWriter, r *http.Request) { - fmt.Fprint(w, `[{"filename":"src/qiniu.com/kodo/s3apiv2/bucket/bucket.go"}]`) - }) - - p := GitPrComment{ - RobotUserName: "qiniu-bot", - RepoOwner: "qiniu", - RepoName: "goc", - CommentFlag: "", - PrNumber: 1, - Ctx: context.Background(), - opt: nil, - GithubClient: client, - } - changedFiles, err := p.GetPrChangedFiles() - assert.Equal(t, err, nil) - assert.Equal(t, changedFiles, expectFiles) -} - -func TestGetCommentFlag(t *testing.T) { - p := GitPrComment{ - CommentFlag: "flag", - } - flag := p.GetCommentFlag() - assert.Equal(t, flag, p.CommentFlag) -} diff --git a/pkg/prow/job.go b/pkg/prow/job.go deleted file mode 100644 index cebcdad..0000000 --- a/pkg/prow/job.go +++ /dev/null @@ -1,240 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.com) - - 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 prow - -import ( - "bufio" - "bytes" - "fmt" - "io/ioutil" - "os" - "os/exec" - "path" - "strconv" - "strings" - "time" - - "github.com/sirupsen/logrus" - - "github.com/qiniu/goc/pkg/cover" - "github.com/qiniu/goc/pkg/github" - "github.com/qiniu/goc/pkg/qiniu" -) - -// IProwAction defines the normal action in prow system -type IProwAction interface { - Fetch(BuildID, name string) []byte - RunPresubmit() error - RunPostsubmit() error - RunPeriodic() error -} - -// Job is a prowjob in prow -type Job struct { - JobName string - Org string - RepoName string - PRNumStr string - BuildId string //prow job build number - PostSubmitJob string - PostSubmitCoverProfile string - CovThreshold int - LocalProfilePath string - QiniuClient qiniu.Client - LocalArtifacts qiniu.Artifacts - GithubComment github.PrComment - FullDiff bool -} - -// Fetch the file from cloud -func (j *Job) Fetch(BuildID, name string) []byte { - return []byte{} -} - -// RunPresubmit run a presubmit job -func (j *Job) RunPresubmit() error { - // step1: get local profile cov - localP, err := cover.ReadFileToCoverList(j.LocalProfilePath) - if err != nil { - return fmt.Errorf("failed to get remote cover profile: %s", err.Error()) - } - - //step2: find the remote healthy cover profile from qiniu bucket - remoteProfile, err := qiniu.FindBaseProfileFromQiniu(j.QiniuClient, j.PostSubmitJob, j.PostSubmitCoverProfile) - if err != nil { - return fmt.Errorf("failed to get remote cover profile: %s", err.Error()) - } - if remoteProfile == nil { - logrus.Infof("get non healthy remoteProfile, do nothing") - return nil - } - baseP, err := cover.CovList(bytes.NewReader(remoteProfile)) - if err != nil { - return fmt.Errorf("failed to get remote cover profile: %s", err.Error()) - } - - // step3: get github pull request changed files' name and calculate diff cov between local and remote profile - changedFiles, deltaCovList, err := getFilesAndCovList(j.FullDiff, j.GithubComment, localP, baseP) - if err != nil { - return fmt.Errorf("Get files and covlist failed: %s", err.Error()) - } - - // step4: generate changed file html coverage - err = j.WriteChangedCov(changedFiles) - if err != nil { - return fmt.Errorf("filter local profile to %s with changed files failed: %s", j.LocalArtifacts.GetChangedProfileName(), err.Error()) - } - err = j.CreateChangedCovHtml() - if err != nil { - return fmt.Errorf("create changed file related coverage html failed: %s", err.Error()) - } - j.SetDeltaCovLinks(deltaCovList) - - // step5: post comment to github - commentPrefix := github.CommentsPrefix - if j.GithubComment.GetCommentFlag() != "" { - commentPrefix = fmt.Sprintf("**%s** ", j.GithubComment.GetCommentFlag()) + commentPrefix - } - if len(deltaCovList) > 0 { - totalDelta := cover.PercentStr(cover.TotalDelta(localP, baseP)) - deltaCovList = append(deltaCovList, cover.DeltaCov{FileName: "Total", BasePer: baseP.TotalPercentage(), NewPer: localP.TotalPercentage(), DeltaPer: totalDelta}) - } - err = j.GithubComment.CreateGithubComment(commentPrefix, deltaCovList) - if err != nil { - return fmt.Errorf("Post comment to github failed: %s", err.Error()) - } - - return nil -} - -// RunPostsubmit run a postsubmit job -func (j *Job) RunPostsubmit() error { - return nil -} - -// RunPeriodic run a periodic job -func (j *Job) RunPeriodic() error { - return nil -} - -//trim github filename to profile format: -// src/qiniu.com/kodo/io/io/io_svr.go -> qiniu.com/kodo/io/io/io_svr.go -func trimGhFileToProfile(ghFiles []string) (pFiles []string) { - //TODO: need compatible other situation - logrus.Infof("trim PR changed file name to:") - for _, f := range ghFiles { - file := strings.TrimPrefix(f, "src/") - logrus.Infof("%s", file) - pFiles = append(pFiles, file) - } - return -} - -// WriteChangedCov filter local profile with changed files and save to j.LocalArtifacts.ChangedProfileName -func (j *Job) WriteChangedCov(changedFiles []string) error { - p, err := ioutil.ReadFile(j.LocalProfilePath) - if err != nil { - logrus.Printf("Open file %s failed", j.LocalProfilePath) - return err - } - cp := j.LocalArtifacts.CreateChangedProfile() - defer cp.Close() - s := bufio.NewScanner(bytes.NewReader(p)) - s.Scan() - writeLine(cp, s.Text()) - - for s.Scan() { - for _, file := range changedFiles { - if strings.HasPrefix(s.Text(), file) { - writeLine(cp, s.Text()) - } - } - } - - return nil -} - -// writeLine writes a line in the given file, if the file pointer is not nil -func writeLine(file *os.File, content string) { - if file != nil { - fmt.Fprintln(file, content) - } -} - -// JobPrefixOnQiniu generates the prefix string of the job on qiniu -func (j *Job) JobPrefixOnQiniu() string { - return path.Join("pr-logs", "pull", j.Org+"_"+j.RepoName, j.PRNumStr, j.JobName, j.BuildId) -} - -// HtmlProfile generates the name of the profile html file -func (j *Job) HtmlProfile() string { - return fmt.Sprintf("%s-%s-pr%s-coverage.html", j.Org, j.RepoName, j.PRNumStr) -} - -// SetDeltaCovLinks set DeltaCovLinks to the job -func (j *Job) SetDeltaCovLinks(c cover.DeltaCovList) { - c.Sort() - for i := 0; i < len(c); i++ { - qnKey := path.Join(j.JobPrefixOnQiniu(), "artifacts", j.HtmlProfile()) - authQnKey := j.QiniuClient.GetAccessURL(qnKey, time.Hour*24*7) - c[i].SetLineCovLink(authQnKey + "#file" + strconv.Itoa(i)) - logrus.Printf("file %s html coverage link is: %s\n", c[i].FileName, c[i].GetLineCovLink()) - } -} - -// CreateChangedCovHtml create changed file related coverage html base on the local artifact -func (j *Job) CreateChangedCovHtml() error { - if j.LocalArtifacts.GetChangedProfileName() == "" { - logrus.Errorf("param LocalArtifacts.ChangedProfileName is empty") - } - pathProfileCov := j.LocalArtifacts.GetChangedProfileName() - pathHtmlCov := path.Join(os.Getenv("ARTIFACTS"), j.HtmlProfile()) - cmdTxt := fmt.Sprintf("go tool cover -html=%s -o %s", pathProfileCov, pathHtmlCov) - logrus.Printf("Running command '%s'\n", cmdTxt) - cmd := exec.Command("go", "tool", "cover", "-html="+pathProfileCov, "-o", pathHtmlCov) - stdOut, err := cmd.CombinedOutput() - if err != nil { - logrus.Printf("Error executing cmd: %v; combinedOutput=%s", err, stdOut) - } - return err -} - -func getFilesAndCovList(fullDiff bool, prComment github.PrComment, localP, baseP cover.CoverageList) (changedFiles []string, deltaCovList cover.DeltaCovList, err error) { - if !fullDiff { - // get github pull request changed files' name - var ghChangedFiles, err = prComment.GetPrChangedFiles() - if err != nil { - return nil, nil, fmt.Errorf("Get pull request changed file failed: %s", err.Error()) - } - if len(ghChangedFiles) == 0 { - logrus.Printf("0 files changed in github pull request, don't need to run coverage profile in presubmit.\n") - return nil, nil, nil - } - changedFiles = trimGhFileToProfile(ghChangedFiles) - - // calculate diff cov between local and remote profile - deltaCovList = cover.GetChFileDeltaCov(localP, baseP, changedFiles) - logrus.Printf("Get changed files and delta cover list success. ChangedFiles: [%+v], DeltaCovList: [%+v]", changedFiles, deltaCovList) - return changedFiles, deltaCovList, nil - } - deltaCovList = cover.GetDeltaCov(localP, baseP) - for _, d := range deltaCovList { - changedFiles = append(changedFiles, d.FileName) - } - logrus.Printf("Get all files and delta cover list success. Files: [%+v], DeltaCovList: [%+v]", changedFiles, deltaCovList) - return changedFiles, deltaCovList, nil -} diff --git a/pkg/prow/job_test.go b/pkg/prow/job_test.go deleted file mode 100644 index 2786c1c..0000000 --- a/pkg/prow/job_test.go +++ /dev/null @@ -1,380 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.com) - - 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 prow - -import ( - "context" - "errors" - "fmt" - "io/ioutil" - "os" - "path" - "testing" - "time" - - "github.com/sirupsen/logrus" - "github.com/stretchr/testify/assert" - - "github.com/qiniu/goc/pkg/cover" - "github.com/qiniu/goc/pkg/github" - "github.com/qiniu/goc/pkg/qiniu" -) - -var ( - defaultContent = `mode: atomic -qiniu.com/kodo/bd/bdgetter/source.go:19.118,22.2 2 0 -qiniu.com/kodo/bd/bdgetter/source.go:37.34,39.2 1 0 -qiniu.com/kodo/bd/pfd/locker/app/qboxbdlocker/main.go:50.2,53.52 4 1 -qiniu.com/kodo/bd/pfd/locker/bdlocker/locker.go:33.51,35.2 1 0` - defaultLocalPath = "local.cov" - defaultChangedPath = "changed.cov" -) - -type MockQnClient struct { - QiniuObjectHandleRes qiniu.ObjectHandle - ReadObjectRes []byte - ReadObjectErr error - ListAllRes []string - ListAllErr error - GetAccessURLRes string - GetArtifactDetailsRes *qiniu.LogHistoryTemplate - GetArtifactDetailsErr error - ListSubDirsRes []string - ListSubDirsErr error -} - -func (s *MockQnClient) QiniuObjectHandle(key string) qiniu.ObjectHandle { - return s.QiniuObjectHandleRes -} - -func (s *MockQnClient) ReadObject(key string) ([]byte, error) { - return s.ReadObjectRes, s.ReadObjectErr -} - -func (s *MockQnClient) ListAll(ctx context.Context, prefix string, delimiter string) ([]string, error) { - return s.ListAllRes, s.ListAllErr -} - -func (s *MockQnClient) GetAccessURL(key string, timeout time.Duration) string { - return s.GetAccessURLRes -} - -func (s *MockQnClient) GetArtifactDetails(key string) (*qiniu.LogHistoryTemplate, error) { - return s.GetArtifactDetailsRes, s.GetArtifactDetailsErr -} - -func (s *MockQnClient) ListSubDirs(prefix string) ([]string, error) { - return s.ListSubDirsRes, s.ListSubDirsErr -} - -type MockPrComment struct { - GetPrChangedFilesRes []string - GetPrChangedFilesErr error - PostCommentErr error - EraseHistoryCommentErr error - CreateGithubCommentErr error - CommentFlag string -} - -func (s *MockPrComment) GetPrChangedFiles() (files []string, err error) { - return s.GetPrChangedFilesRes, s.GetPrChangedFilesErr -} - -func (s *MockPrComment) PostComment(content, commentPrefix string) error { - return s.PostCommentErr -} - -func (s *MockPrComment) EraseHistoryComment(commentPrefix string) error { - return s.EraseHistoryCommentErr -} - -func (s *MockPrComment) CreateGithubComment(commentPrefix string, diffCovList cover.DeltaCovList) (err error) { - return s.CreateGithubCommentErr -} - -func (s *MockPrComment) GetCommentFlag() string { - return s.CommentFlag -} - -func TestTrimGhFileToProfile(t *testing.T) { - items := []struct { - inputFiles []string - expectFiles []string - }{ - { - inputFiles: []string{"src/qiniu.com/kodo/io/io/io_svr.go", "README.md"}, - expectFiles: []string{"qiniu.com/kodo/io/io/io_svr.go", "README.md"}, - }, - } - - for _, tc := range items { - f := trimGhFileToProfile(tc.inputFiles) - assert.Equal(t, f, tc.expectFiles) - } -} - -func setup(path, content string) { - err := ioutil.WriteFile(path, []byte(content), 0644) - if err != nil { - logrus.WithError(err).Fatalf("write file %s failed", path) - } -} - -func TestWriteChangedCov(t *testing.T) { - path := defaultLocalPath - savePath := qiniu.ChangedProfileName - content := defaultContent - changedFiles := []string{"qiniu.com/kodo/bd/pfd/locker/bdlocker/locker.go"} - expectContent := `mode: atomic -qiniu.com/kodo/bd/pfd/locker/bdlocker/locker.go:33.51,35.2 1 0 -` - - setup(path, content) - defer os.Remove(path) - defer os.Remove(savePath) - j := &Job{ - LocalProfilePath: path, - LocalArtifacts: &qiniu.ProfileArtifacts{ChangedProfileName: savePath}, - } - j.WriteChangedCov(changedFiles) - - r, err := ioutil.ReadFile(savePath) - if err != nil { - logrus.WithError(err).Fatalf("read file %s failed", path) - } - assert.Equal(t, string(r), expectContent) -} - -func TestRunPresubmitFulldiff(t *testing.T) { - //param - org := "qbox" - repo := "kodo" - prNum := "1" - buildId := "1266322425771986946" - jobName := "kodo-pull-integration-test" - robotName := "qiniu-bot" - githubCommentPrefix := "" - githubTokenPath := "token" - - //mock local profile - pwd, err := os.Getwd() - assert.NoError(t, err) - localPath := defaultLocalPath - localProfileContent := `mode: atomic -"qiniu.com/kodo/apiserver/server/main.go:32.49,33.13 1 30 -"qiniu.com/kodo/apiserver/server/main.go:42.49,43.13 1 0` - setup(localPath, localProfileContent) - defer os.Remove(path.Join(pwd, localPath)) - - // mock qiniu - conf := qiniu.Config{ - Bucket: "artifacts", - } - qc, router, _, teardown := qiniu.MockQiniuServer(&conf) - defer teardown() - qiniu.MockRouterAPI(router, localProfileContent, 0) - - ChangedProfilePath := "changed.cov" - defer os.Remove(path.Join(pwd, ChangedProfilePath)) - - //mock github client - setup(githubTokenPath, "") - defer os.Remove(path.Join(pwd, githubTokenPath)) - prClient := github.NewPrClient(githubTokenPath, org, repo, prNum, robotName, githubCommentPrefix) - - j := &Job{ - JobName: jobName, - Org: org, - RepoName: repo, - PRNumStr: prNum, - BuildId: buildId, - PostSubmitJob: "kodo-postsubmits-go-st-coverage", - PostSubmitCoverProfile: "filterd.cov", - LocalProfilePath: localPath, - LocalArtifacts: &qiniu.ProfileArtifacts{ChangedProfileName: ChangedProfilePath}, - QiniuClient: qc, - GithubComment: prClient, - FullDiff: true, - } - defer os.Remove(path.Join(os.Getenv("ARTIFACTS"), j.HtmlProfile())) - - err = j.RunPresubmit() - assert.NoError(t, err) -} - -func TestRunPresubmitError(t *testing.T) { - items := []struct { - prepare bool // prepare local profile - j Job - err string - }{ - { - prepare: false, - j: Job{ - LocalProfilePath: "unknown", - }, - err: "no such file or directory", - }, - { - prepare: true, - j: Job{ - LocalProfilePath: defaultLocalPath, - QiniuClient: &MockQnClient{}, - }, - }, - { - prepare: true, - j: Job{ - LocalProfilePath: defaultLocalPath, - QiniuClient: &MockQnClient{ListSubDirsErr: errors.New("mock error")}, - }, - err: "mock error", - }, - { - prepare: true, - j: Job{ - LocalProfilePath: defaultLocalPath, - QiniuClient: &MockProfileQnClient{}, - GithubComment: &MockPrComment{GetPrChangedFilesRes: []string{"qiniu.com/kodo/apiserver/server/main.go"}}, - FullDiff: true, - LocalArtifacts: &qiniu.ProfileArtifacts{ChangedProfileName: defaultChangedPath}, - }, - err: "", - }, - } - for _, tc := range items { - if tc.prepare { - path := defaultLocalPath - setup(path, defaultContent) - defer os.Remove(path) - defer os.Remove(defaultChangedPath) - } - err := tc.j.RunPresubmit() - if tc.err == "" { - assert.NoError(t, err) - } else { - assert.Contains(t, err.Error(), tc.err) - } - } -} - -type MockProfileQnClient struct { - *MockQnClient -} - -func (s *MockProfileQnClient) ListSubDirs(prefix string) ([]string, error) { - return []string{defaultContent}, nil -} - -func (s *MockProfileQnClient) ReadObject(key string) ([]byte, error) { - logrus.Info(key) - if key == "logs/1/finished.json" { - return []byte(`{"timestamp":1590750306,"passed":true,"result":"SUCCESS","repo-version":"76433418ea48aae57af028f9cb2fa3735ce08c7d"}`), nil - } - return []byte(""), nil -} - -func TestGetFilesAndCovList(t *testing.T) { - items := []struct { - fullDiff bool - prComment github.PrComment - localP cover.CoverageList - baseP cover.CoverageList - err string - lenFiles int - lenCovList int - }{ - { - fullDiff: true, - prComment: &MockPrComment{}, - localP: cover.CoverageList{ - {FileName: "qiniu.com/kodo/apiserver/server/main.go", NCoveredStmts: 2, NAllStmts: 2}, - {FileName: "qiniu.com/kodo/apiserver/server/test.go", NCoveredStmts: 2, NAllStmts: 2}, - }, - baseP: cover.CoverageList{ - {FileName: "qiniu.com/kodo/apiserver/server/main.go", NCoveredStmts: 1, NAllStmts: 2}, - {FileName: "qiniu.com/kodo/apiserver/server/test.go", NCoveredStmts: 1, NAllStmts: 2}, - }, - lenFiles: 2, - lenCovList: 2, - }, - { - fullDiff: false, - prComment: &MockPrComment{GetPrChangedFilesErr: errors.New("mock error")}, - err: "mock error", - }, - { - fullDiff: false, - prComment: &MockPrComment{}, - lenFiles: 0, - lenCovList: 0, - }, - { - fullDiff: false, - prComment: &MockPrComment{GetPrChangedFilesRes: []string{"qiniu.com/kodo/apiserver/server/main.go"}}, - localP: cover.CoverageList{ - {FileName: "qiniu.com/kodo/apiserver/server/main.go", NCoveredStmts: 2, NAllStmts: 2}, - {FileName: "qiniu.com/kodo/apiserver/server/test.go", NCoveredStmts: 2, NAllStmts: 2}, - }, - baseP: cover.CoverageList{ - {FileName: "qiniu.com/kodo/apiserver/server/main.go", NCoveredStmts: 1, NAllStmts: 2}, - {FileName: "qiniu.com/kodo/apiserver/server/test.go", NCoveredStmts: 1, NAllStmts: 2}, - }, - lenFiles: 1, - lenCovList: 1, - }, - } - - for i, tc := range items { - fmt.Println(i) - files, covList, err := getFilesAndCovList(tc.fullDiff, tc.prComment, tc.localP, tc.baseP) - if err != nil { - assert.Contains(t, err.Error(), tc.err) - } else { - assert.Equal(t, len(files), tc.lenFiles) - assert.Equal(t, len(covList), tc.lenCovList) - } - } -} - -func TestSetDeltaCovLinks(t *testing.T) { - covList := cover.DeltaCovList{{FileName: "file1", BasePer: "5%", NewPer: "5%", DeltaPer: "0"}} - j := &Job{ - QiniuClient: &MockQnClient{}, - } - j.SetDeltaCovLinks(covList) -} - -// functions to be done - -func TestRunPostsubmit(t *testing.T) { - j := &Job{} - err := j.RunPostsubmit() - assert.NoError(t, err) -} - -func TestRunPeriodic(t *testing.T) { - j := &Job{} - err := j.RunPeriodic() - assert.NoError(t, err) -} - -func TestFetch(t *testing.T) { - j := &Job{} - res := j.Fetch("buidID", "name") - assert.Equal(t, res, []byte{}) -} diff --git a/pkg/qiniu/client.go b/pkg/qiniu/client.go deleted file mode 100644 index e0c8918..0000000 --- a/pkg/qiniu/client.go +++ /dev/null @@ -1,254 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.com) - - 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 qiniu - -import ( - "context" - "fmt" - "io/ioutil" - "math/rand" - "net/http" - "regexp" - "strconv" - "strings" - "time" - - "github.com/qiniu/api.v7/v7/auth/qbox" - "github.com/qiniu/api.v7/v7/client" - "github.com/qiniu/api.v7/v7/storage" - "github.com/sirupsen/logrus" -) - -// Config store the credentials to connect with qiniu cloud -type Config struct { - Bucket string `json:"bucket"` - AccessKey string `json:"accessKey"` - SecretKey string `json:"secretKey"` - - // domain used to download files from qiniu cloud - Domain string `json:"domain"` -} - -// Client is the interface contains the operation with qiniu cloud -type Client interface { - QiniuObjectHandle(key string) ObjectHandle - ReadObject(key string) ([]byte, error) - ListAll(ctx context.Context, prefix string, delimiter string) ([]string, error) - GetAccessURL(key string, timeout time.Duration) string - GetArtifactDetails(key string) (*LogHistoryTemplate, error) - ListSubDirs(prefix string) ([]string, error) -} - -// QnClient for the operation with qiniu cloud -type QnClient struct { - cfg *Config - BucketManager *storage.BucketManager -} - -// NewClient creates a new QnClient to work with qiniu cloud -func NewClient(cfg *Config) *QnClient { - return &QnClient{ - cfg: cfg, - BucketManager: storage.NewBucketManager(qbox.NewMac(cfg.AccessKey, cfg.SecretKey), nil), - } -} - -// QiniuObjectHandle construct a object hanle to access file in qiniu -func (q *QnClient) QiniuObjectHandle(key string) ObjectHandle { - return &QnObjectHandle{ - key: key, - cfg: q.cfg, - bm: q.BucketManager, - mac: qbox.NewMac(q.cfg.AccessKey, q.cfg.SecretKey), - client: &client.Client{Client: http.DefaultClient}, - } -} - -// ReadObject to read all the content of key -func (q *QnClient) ReadObject(key string) ([]byte, error) { - objectHandle := q.QiniuObjectHandle(key) - reader, err := objectHandle.NewReader(context.Background()) - if err != nil { - return nil, fmt.Errorf("error getting qiniu artifact reader: %v", err) - } - defer reader.Close() - return ioutil.ReadAll(reader) -} - -// ListAll to list all the files with contains the expected prefix -func (q *QnClient) ListAll(ctx context.Context, prefix string, delimiter string) ([]string, error) { - var files []string - artifacts, err := q.listEntries(prefix, delimiter) - if err != nil { - return files, err - } - - for _, item := range artifacts { - files = append(files, item.Key) - } - - return files, nil -} - -// listEntries to list all the entries with contains the expected prefix -func (q *QnClient) listEntries(prefix string, delimiter string) ([]storage.ListItem, error) { - var marker string - var artifacts []storage.ListItem - - wait := []time.Duration{16, 32, 64, 128, 256, 256, 512, 512} - for i := 0; ; { - entries, _, nextMarker, hashNext, err := q.BucketManager.ListFiles(q.cfg.Bucket, prefix, delimiter, marker, 500) - if err != nil { - logrus.WithField("prefix", prefix).WithError(err).Error("Error accessing QINIU artifact.") - if i >= len(wait) { - return artifacts, fmt.Errorf("timed out: error accessing QINIU artifact: %v", err) - } - time.Sleep((wait[i] + time.Duration(rand.Intn(10))) * time.Millisecond) - i++ - continue - } - artifacts = append(artifacts, entries...) - - if hashNext { - marker = nextMarker - } else { - break - } - } - - return artifacts, nil -} - -// GetAccessURL return a url which can access artifact directly in qiniu -func (q *QnClient) GetAccessURL(key string, timeout time.Duration) string { - deadline := time.Now().Add(timeout).Unix() - return storage.MakePrivateURL(qbox.NewMac(q.cfg.AccessKey, q.cfg.SecretKey), q.cfg.Domain, key, deadline) -} - -// LogHistoryTemplate is the template of the log history -type LogHistoryTemplate struct { - BucketName string - KeyPath string - Items []logHistoryItem -} - -// logHistoryItem represents a log history item -type logHistoryItem struct { - Name string - Size string - Time string - Url string -} - -// GetArtifactDetails lists all artifacts available for the given job source -func (q *QnClient) GetArtifactDetails(key string) (*LogHistoryTemplate, error) { - tmpl := new(LogHistoryTemplate) - item := logHistoryItem{} - listStart := time.Now() - artifacts, err := q.listEntries(key, "") - if err != nil { - return tmpl, err - } - - for _, entry := range artifacts { - item.Name = splitKey(entry.Key, key) - item.Size = size(entry.Fsize) - item.Time = timeConv(entry.PutTime) - item.Url = q.GetAccessURL(entry.Key, time.Duration(time.Second*60*60)) - tmpl.Items = append(tmpl.Items, item) - } - - logrus.WithField("duration", time.Since(listStart).String()).Infof("Listed %d artifacts.", len(tmpl.Items)) - return tmpl, nil -} - -func splitKey(item, key string) string { - return strings.TrimPrefix(item, key) -} - -func size(fsize int64) string { - return strings.Join([]string{strconv.FormatInt(fsize, 10), "bytes"}, " ") -} - -func timeConv(ptime int64) string { - s := strconv.FormatInt(ptime, 10)[0:10] - t, err := strconv.ParseInt(s, 10, 64) - if err != nil { - logrus.Errorf("time string parse int error : %v", err) - return "" - } - tm := time.Unix(t, 0) - return tm.Format("2006-01-02 03:04:05 PM") -} - -// ListSubDirs list all the sub directions of the prefix string in qiniu client -func (q *QnClient) ListSubDirs(prefix string) ([]string, error) { - var dirs []string - var marker string - - wait := []time.Duration{16, 32, 64, 128, 256, 256, 512, 512} - for i := 0; ; { - // use rsf list v2 interface to get the sub folder based on the delimiter - entries, err := q.BucketManager.ListBucketContext(context.Background(), q.cfg.Bucket, prefix, "/", marker) - if err != nil { - logrus.WithField("prefix", prefix).WithError(err).Error("Error accessing QINIU artifact.") - if i >= len(wait) { - return dirs, fmt.Errorf("timed out: error accessing QINIU artifact: %v", err) - } - time.Sleep((wait[i] + time.Duration(rand.Intn(10))) * time.Millisecond) - i++ - continue - } - - for entry := range entries { - if entry.Dir != "" { - // entry.Dir should be like "logs/kodo-periodics-integration-test/1181915661132107776/" - // the sub folder is 1181915661132107776, also known as prowjob buildid. - buildId := getBuildId(entry.Dir) - if buildId != "" { - dirs = append(dirs, buildId) - } else { - logrus.Warnf("invalid dir format: %v", entry.Dir) - } - } - - marker = entry.Marker - } - - if marker != "" { - i = 0 - } else { - break - } - } - - return dirs, nil -} - -var nonPRLogsBuildIdSubffixRe = regexp.MustCompile("([0-9]+)/$") - -// extract the build number from dir path -// expect the dir as the following formats: -// 1. logs/kodo-periodics-integration-test/1181915661132107776/ -func getBuildId(dir string) string { - matches := nonPRLogsBuildIdSubffixRe.FindStringSubmatch(dir) - if len(matches) == 2 { - return matches[1] - } - - return "" -} diff --git a/pkg/qiniu/client_test.go b/pkg/qiniu/client_test.go deleted file mode 100644 index a8367a1..0000000 --- a/pkg/qiniu/client_test.go +++ /dev/null @@ -1,184 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.com) - - 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 qiniu - -import ( - "context" - "path" - "strings" - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestGetBuildId(t *testing.T) { - type tc struct { - dir string - expected string - } - - tcs := []tc{ - {dir: "logs/kodo-periodics-integration-test/1181915661132107776/", expected: "1181915661132107776"}, - {dir: "logs/kodo-periodics-integration-test/1181915661132107776", expected: ""}, - {dir: "pr-logs/directory/WIP-qtest-pull-request-kodo-test/1181915661132107776/", expected: "1181915661132107776"}, - {dir: "pr-logs/directory/WIP-qtest-pull-request-kodo-test/1181915661132107776.txt", expected: ""}, - } - - for _, tc := range tcs { - got := getBuildId(tc.dir) - if tc.expected != got { - t.Errorf("getBuildId error, dir: %s, expect: %s, but got: %s", tc.dir, tc.expected, got) - } - } -} - -// test basic listEntries function -func TestListAllFiles(t *testing.T) { - conf := Config{ - Bucket: "artifacts", - } - qc, router, _, teardown := MockQiniuServer(&conf) - defer teardown() - prowJobName := "kodo-postsubmits-go-st-coverage" - dirOfJob := path.Join("logs", prowJobName) - prefix := dirOfJob + "/" - - MockRouterListAllAPI(router, 0) - listItems, err := qc.listEntries(prefix, "/") - - assert.Equal(t, err, nil) - assert.Equal(t, len(listItems), 1) - assert.Equal(t, listItems[0].Key, "logs/kodo-postsubmits-go-st-coverage/1181915661132107776/finished.json") -} - -// test basic listEntries function, recover after 3 times -func TestListAllFilesWithServerTimeoutAndRecover(t *testing.T) { - conf := Config{ - Bucket: "artifacts", - } - qc, router, _, teardown := MockQiniuServer(&conf) - defer teardown() - prowJobName := "kodo-postsubmits-go-st-coverage" - dirOfJob := path.Join("logs", prowJobName) - prefix := dirOfJob + "/" - - // recover after 3 times - MockRouterListAllAPI(router, 3) - listItems, err := qc.listEntries(prefix, "/") - - assert.Equal(t, err, nil) - assert.Equal(t, len(listItems), 1) - assert.Equal(t, listItems[0].Key, "logs/kodo-postsubmits-go-st-coverage/1181915661132107776/finished.json") -} - -// test basic listEntries function, never recover -func TestListAllFilesWithServerTimeout(t *testing.T) { - conf := Config{ - Bucket: "artifacts", - } - qc, router, _, teardown := MockQiniuServer(&conf) - defer teardown() - prowJobName := "kodo-postsubmits-go-st-coverage" - dirOfJob := path.Join("logs", prowJobName) - prefix := dirOfJob + "/" - - // never recover - MockRouterListAllAPI(router, 13) - _, err := qc.listEntries(prefix, "/") - - assert.Equal(t, strings.Contains(err.Error(), "timed out: error accessing QINIU artifact"), true) -} - -// test ListAll function -func TestListAllFilesWithContext(t *testing.T) { - conf := Config{ - Bucket: "artifacts", - } - qc, router, _, teardown := MockQiniuServer(&conf) - defer teardown() - prowJobName := "kodo-postsubmits-go-st-coverage" - dirOfJob := path.Join("logs", prowJobName) - prefix := dirOfJob + "/" - - MockRouterListAllAPI(router, 0) - listItems, err := qc.ListAll(context.Background(), prefix, "/") - - assert.Equal(t, err, nil) - assert.Equal(t, len(listItems), 1) - assert.Equal(t, listItems[0], "logs/kodo-postsubmits-go-st-coverage/1181915661132107776/finished.json") -} - -// test GetArtifactDetails function -func TestGetArtifactDetails(t *testing.T) { - conf := Config{ - Bucket: "artifacts", - } - qc, router, _, teardown := MockQiniuServer(&conf) - defer teardown() - prowJobName := "kodo-postsubmits-go-st-coverage" - dirOfJob := path.Join("logs", prowJobName) - prefix := dirOfJob + "/" - - MockRouterListAllAPI(router, 0) - tmpl, err := qc.GetArtifactDetails(prefix) - assert.Equal(t, err, nil) - assert.Equal(t, len(tmpl.Items), 1) - assert.Equal(t, tmpl.Items[0].Name, "1181915661132107776/finished.json") - assert.Equal(t, strings.Contains(tmpl.Items[0].Url, prowJobName), true) -} - -// test ListSubDirs function, recover after 3 times -func TestListSubDirsWithServerTimeoutAndRecover(t *testing.T) { - conf := Config{ - Bucket: "artifacts", - } - qc, router, _, teardown := MockQiniuServer(&conf) - defer teardown() - prowJobName := "kodo-postsubmits-go-st-coverage" - dirOfJob := path.Join("logs", prowJobName) - prefix := dirOfJob + "/" - localProfileContent := `mode: atomic -"qiniu.com/kodo/apiserver/server/main.go:32.49,33.13 1 30 -"qiniu.com/kodo/apiserver/server/main.go:42.49,43.13 1 0` - // recover after 3 times - MockRouterAPI(router, localProfileContent, 3) - listItems, err := qc.ListSubDirs(prefix) - - assert.Equal(t, err, nil) - assert.Equal(t, len(listItems), 1) - assert.Equal(t, listItems[0], "1181915661132107776") -} - -// test ListSubDirs function, never recover -func TestListSubDirsWithServerTimeout(t *testing.T) { - conf := Config{ - Bucket: "artifacts", - } - qc, router, _, teardown := MockQiniuServer(&conf) - defer teardown() - prowJobName := "kodo-postsubmits-go-st-coverage" - dirOfJob := path.Join("logs", prowJobName) - prefix := dirOfJob + "/" - localProfileContent := `mode: atomic -"qiniu.com/kodo/apiserver/server/main.go:32.49,33.13 1 30 -"qiniu.com/kodo/apiserver/server/main.go:42.49,43.13 1 0` - // never recover - MockRouterAPI(router, localProfileContent, 13) - _, err := qc.ListSubDirs(prefix) - - assert.Equal(t, strings.Contains(err.Error(), "timed out: error accessing QINIU artifact"), true) -} diff --git a/pkg/qiniu/mock.go b/pkg/qiniu/mock.go deleted file mode 100644 index c1a28f2..0000000 --- a/pkg/qiniu/mock.go +++ /dev/null @@ -1,162 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.com) - - 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 qiniu - -import ( - "fmt" - "net/http" - "net/http/httptest" - - "github.com/julienschmidt/httprouter" - "github.com/qiniu/api.v7/v7/storage" - "github.com/sirupsen/logrus" -) - -// MockQiniuServer simulate qiniu cloud for testing -func MockQiniuServer(config *Config) (client *QnClient, router *httprouter.Router, serverURL string, teardown func()) { - // router is the HTTP request multiplexer used with the test server. - router = httprouter.New() - - // server is a test HTTP server used to provide mock API responses. - server := httptest.NewServer(router) - - config.Domain = server.URL - client = NewClient(config) - client.BucketManager.Cfg = &storage.Config{ - RsfHost: server.URL, - } - - logrus.Infof("server url is: %s", server.URL) - return client, router, server.URL, server.Close -} - -// MockRouterAPI mocks qiniu /v2/list API. -// You need to provide a expected profile content. -// count controls the mocks qiniu server to error before 'count' times request. -func MockRouterAPI(router *httprouter.Router, profile string, count int) { - timeout := count - - // mock rsf /v2/list - router.HandlerFunc("POST", "/v2/list", func(w http.ResponseWriter, r *http.Request) { - logrus.Infof("request url is: %s", r.URL.String()) - - if timeout > 0 { - timeout-- - http.Error(w, "not found", http.StatusNotFound) - return - } - - fmt.Fprint(w, `{ - "item": { - "key": "logs/kodo-postsubmits-go-st-coverage/1181915661132107776/finished.json", - "hash": "FkBhdo9odL2Xjvu-YdwtDIw79fIL", - "fsize": 51523, - "mimeType": "application/octet-stream", - "putTime": 15909068578047958, - "type": 0, - "status": 0, - "md5": "e0bd20e97ea1c6a5e2480192ee3ae884" - }, - "marker": "", - "dir": "logs/kodo-postsubmits-go-st-coverage/1181915661132107776/" -}`) - }) - - // mock io get statusJSON file - router.HandlerFunc("GET", "/logs/kodo-postsubmits-go-st-coverage/1181915661132107776/finished.json", func(w http.ResponseWriter, r *http.Request) { - fmt.Fprint(w, `{"timestamp":1590750306,"passed":true,"result":"SUCCESS","repo-version":"76433418ea48aae57af028f9cb2fa3735ce08c7d"}`) - }) - - // mock io get remote coverage profile - router.HandlerFunc("GET", "/logs/kodo-postsubmits-go-st-coverage/1181915661132107776/artifacts/filterd.cov", func(w http.ResponseWriter, r *http.Request) { - fmt.Fprint(w, profile) - }) - -} - -// MockRouterListAllAPI mocks qiniu /list API. -// count controls the mocks qiniu server to error before 'count' times request. -func MockRouterListAllAPI(router *httprouter.Router, count int) { - timeout := count - // mock rsf /v2/list - router.HandlerFunc("POST", "/list", func(w http.ResponseWriter, r *http.Request) { - logrus.Infof("will respond after %v times", timeout) - logrus.Infof("request url is: %s", r.URL.String()) - - if timeout > 0 { - timeout-- - http.Error(w, "not found", http.StatusNotFound) - return - } - - fmt.Fprint(w, `{ - "items": [{ - "key": "logs/kodo-postsubmits-go-st-coverage/1181915661132107776/finished.json", - "hash": "FkBhdo9odL2Xjvu-YdwtDIw79fIL", - "fsize": 51523, - "mimeType": "application/octet-stream", - "putTime": 15909068578047958, - "type": 0, - "status": 0, - "md5": "e0bd20e97ea1c6a5e2480192ee3ae884" - }], - "marker": "", - "commonPrefixes": ["logs/kodo-postsubmits-go-st-coverage/1181915661132107776/"] -}`) - }) -} - -// MockPrivateDomainUrl mocks bucket domain /key, /timeout, /retry API. -// count controls the mocks qiniu server to error before 'count' times request. -func MockPrivateDomainUrl(router *httprouter.Router, count int) { - timeout1 := count - timeout2 := count - - router.HandlerFunc("GET", "/key", func(w http.ResponseWriter, r *http.Request) { - logrus.Infof("request url is: %s", r.URL.String()) - - fmt.Fprint(w, "mock server ok") - }) - - router.HandlerFunc("GET", "/timeout", func(w http.ResponseWriter, r *http.Request) { - logrus.Infof("request url is: %s", r.URL.String()) - - if timeout1 > 0 { - timeout1-- - http.Error(w, "not found", http.StatusNotFound) - return - } - - fmt.Fprint(w, "mock server ok") - }) - - router.HandlerFunc("GET", "/retry", func(w http.ResponseWriter, r *http.Request) { - logrus.Infof("request url is: %s", r.URL.String()) - - if timeout2 > 0 { - timeout2-- - if timeout2%2 == 0 { - http.Error(w, "not found", 571) - } else { - http.Error(w, "not found", 573) - } - return - } - - fmt.Fprint(w, "mock server ok") - }) -} diff --git a/pkg/qiniu/object.go b/pkg/qiniu/object.go deleted file mode 100644 index 81a8823..0000000 --- a/pkg/qiniu/object.go +++ /dev/null @@ -1,126 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.com) - - 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 qiniu - -import ( - "context" - "fmt" - "io" - "net/http" - "time" - - "github.com/qiniu/api.v7/v7/auth/qbox" - "github.com/qiniu/api.v7/v7/client" - "github.com/qiniu/api.v7/v7/storage" - "github.com/sirupsen/logrus" -) - -// ObjectHandle is the interface contains the operations on an object in a qiniu cloud bucket -type ObjectHandle interface { - NewReader(ctx context.Context) (io.ReadCloser, error) - NewRangeReader(ctx context.Context, offset, length int64) (io.ReadCloser, error) -} - -// QnObjectHandle provides operations on an object in a qiniu cloud bucket -type QnObjectHandle struct { - key string - cfg *Config - bm *storage.BucketManager - mac *qbox.Mac - client *client.Client -} - -// NewReader creates a reader to read the contents of the object. -// ErrObjectNotExist will be returned if the object is not found. -// The caller must call Close on the returned Reader when done reading. -func (o *QnObjectHandle) NewReader(ctx context.Context) (io.ReadCloser, error) { - return o.NewRangeReader(ctx, 0, -1) -} - -// NewRangeReader reads parts of an object, reading at most length bytes starting -// from the given offset. If length is negative, the object is read until the end. -func (o *QnObjectHandle) NewRangeReader(ctx context.Context, offset, length int64) (io.ReadCloser, error) { - verb := "GET" - if length == 0 { - verb = "HEAD" - } - - var res *http.Response - var err error - - err = runWithRetry(3, func() (bool, error) { - headers := http.Header{} - start := offset - if length < 0 && start >= 0 { - headers.Set("Range", fmt.Sprintf("bytes=%d-", start)) - } else if length > 0 { - // The end character isn't affected by how many bytes we have seen. - headers.Set("Range", fmt.Sprintf("bytes=%d-%d", start, offset+length-1)) - } - - deadline := time.Now().Add(time.Second * 60 * 10).Unix() - accessURL := storage.MakePrivateURL(o.mac, o.cfg.Domain, o.key, deadline) - res, err = o.client.DoRequest(ctx, verb, accessURL, headers) - if err != nil { - time.Sleep(time.Second) //TODO enhance - return true, err - } - - if res.StatusCode == http.StatusNotFound { - res.Body.Close() - return true, fmt.Errorf("qiniu storage: object not exists") - } - - return shouldRetry(res), nil - }) - - if err != nil { - return nil, err - } - - return res.Body, nil -} - -func runWithRetry(maxTry int, f func() (bool, error)) error { - var err error - for maxTry > 0 { - var needRetry bool - needRetry, err = f() // fix - needRetry, err := f(), err hides the outside error - if err != nil { - logrus.Warnf("err occurred: %v. try again", err) - } else if needRetry { - logrus.Warn("results do not meet the expectation. try again") - } else { - break - } - time.Sleep(time.Millisecond * 100) - maxTry = maxTry - 1 - } - - return err -} - -func shouldRetry(res *http.Response) bool { - - // 571 and 573 mean the request was limited by cloud storage because of concurrency count exceed - // so it's better to retry after a while - if res.StatusCode == 571 || res.StatusCode == 573 { - return true - } - - return false -} diff --git a/pkg/qiniu/object_test.go b/pkg/qiniu/object_test.go deleted file mode 100644 index f6d8427..0000000 --- a/pkg/qiniu/object_test.go +++ /dev/null @@ -1,138 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.com) - - 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 qiniu - -import ( - "context" - "fmt" - "io/ioutil" - "net/http" - "testing" - - "github.com/qiniu/api.v7/v7/auth/qbox" - "github.com/qiniu/api.v7/v7/client" - "github.com/stretchr/testify/assert" -) - -// test NewRangeReader logic -func TestNewRangeReader(t *testing.T) { - cfg := &Config{ - Bucket: "artifacts", - AccessKey: "ak", - SecretKey: "sk", - } - _, router, serverUrl, teardown := MockQiniuServer(cfg) - defer teardown() - cfg.Domain = serverUrl - - MockPrivateDomainUrl(router, 0) - - oh := &QnObjectHandle{ - key: "key", - cfg: cfg, - bm: nil, - mac: qbox.NewMac(cfg.AccessKey, cfg.SecretKey), - client: &client.Client{Client: http.DefaultClient}, - } - - // test read unlimited - body, err := oh.NewRangeReader(context.Background(), 0, -1) - assert.Equal(t, err, nil) - - bodyBytes, err := ioutil.ReadAll(body) - assert.NoError(t, err) - assert.Equal(t, string(bodyBytes), "mock server ok") - - // test with HEAD method - body, err = oh.NewRangeReader(context.Background(), 0, 0) - assert.Equal(t, err, nil) - - bodyBytes, err = ioutil.ReadAll(body) - assert.NoError(t, err) - assert.Equal(t, string(bodyBytes), "") - -} - -// test retry logic -func TestNewRangeReaderWithTimeoutAndRecover(t *testing.T) { - cfg := &Config{ - Bucket: "artifacts", - AccessKey: "ak", - SecretKey: "sk", - } - _, router, serverUrl, teardown := MockQiniuServer(cfg) - defer teardown() - cfg.Domain = serverUrl - - MockPrivateDomainUrl(router, 2) - - oh := &QnObjectHandle{ - key: "key", - cfg: cfg, - bm: nil, - mac: qbox.NewMac(cfg.AccessKey, cfg.SecretKey), - client: &client.Client{Client: http.DefaultClient}, - } - - // test with timeout - oh.key = "timeout" - body, err := oh.NewRangeReader(context.Background(), 0, 10) - assert.Equal(t, err, nil) - - bodyBytes, err := ioutil.ReadAll(body) - assert.NoError(t, err) - assert.Equal(t, string(bodyBytes), "mock server ok") - - // test with retry with statuscode=571, 573 - oh.key = "retry" - body, err = oh.NewRangeReader(context.Background(), 0, 10) - assert.Equal(t, err, nil) - - bodyBytes, err = ioutil.ReadAll(body) - assert.NoError(t, err) - assert.Equal(t, string(bodyBytes), "mock server ok") -} - -// test retry logic -func TestNewRangeReaderWithTimeoutNoRecover(t *testing.T) { - cfg := &Config{ - Bucket: "artifacts", - AccessKey: "ak", - SecretKey: "sk", - } - _, router, serverUrl, teardown := MockQiniuServer(cfg) - defer teardown() - cfg.Domain = serverUrl - - MockPrivateDomainUrl(router, 12) - - oh := &QnObjectHandle{ - key: "key", - cfg: cfg, - bm: nil, - mac: qbox.NewMac(cfg.AccessKey, cfg.SecretKey), - client: &client.Client{Client: http.DefaultClient}, - } - - // test with timeout - oh.key = "timeout" - _, err := oh.NewRangeReader(context.Background(), 0, -1) - assert.Equal(t, err, fmt.Errorf("qiniu storage: object not exists")) - - // bodyBytes, err := ioutil.ReadAll(body) - // assert.Equal(t, string(bodyBytes), "mock server ok") -} diff --git a/pkg/qiniu/qnPresubmit.go b/pkg/qiniu/qnPresubmit.go deleted file mode 100644 index 4aedf9e..0000000 --- a/pkg/qiniu/qnPresubmit.go +++ /dev/null @@ -1,146 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.com) - - 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 qiniu - -import ( - "encoding/json" - "fmt" - "os" - "path" - "sort" - "strconv" - - log "github.com/sirupsen/logrus" -) - -const ( - //statusJSON is the JSON file that stores build success info - statusJSON = "finished.json" - - // ArtifactsDirName is the name of directory defined in prow to store test artifacts - ArtifactsDirName = "artifacts" - - //PostSubmitCoverProfile represents the default output coverage file generated in prow environment - PostSubmitCoverProfile = "filtered.cov" - - //ChangedProfileName represents the default changed coverage profile based on files changed in Pull Request - ChangedProfileName = "changed-file-profile.cov" -) - -// sortBuilds converts all build from str to int and sorts all builds in descending order and -// returns the sorted slice -func sortBuilds(strBuilds []string) []int { - var res []int - for _, buildStr := range strBuilds { - num, err := strconv.Atoi(buildStr) - if err != nil { - log.Printf("Non-int build number found: '%s'", buildStr) - } else { - res = append(res, num) - } - } - sort.Sort(sort.Reverse(sort.IntSlice(res))) - return res -} - -type finishedStatus struct { - Timestamp int - Passed bool -} - -func isBuildSucceeded(jsonText []byte) bool { - var status finishedStatus - err := json.Unmarshal(jsonText, &status) - return err == nil && status.Passed -} - -// FindBaseProfileFromQiniu finds the coverage profile file from the latest healthy build -// stored in given gcs directory -func FindBaseProfileFromQiniu(qc Client, prowJobName, covProfileName string) ([]byte, error) { - dirOfJob := path.Join("logs", prowJobName) - prefix := dirOfJob + "/" - strBuilds, err := qc.ListSubDirs(prefix) - if err != nil { - return nil, fmt.Errorf("error listing qiniu objects, prowjob:%v, err:%v", prowJobName, err) - } - if len(strBuilds) == 0 { - log.Printf("no cover profiles found from remote, do nothing") - return nil, nil - } - log.Printf("total sub dirs: %d", len(strBuilds)) - - builds := sortBuilds(strBuilds) - profilePath := "" - for _, build := range builds { - buildDirPath := path.Join(dirOfJob, strconv.Itoa(build)) - dirOfStatusJSON := path.Join(buildDirPath, statusJSON) - - statusText, err := qc.ReadObject(dirOfStatusJSON) - if err != nil { - log.Printf("Cannot read finished.json (%s) ", dirOfStatusJSON) - } else if isBuildSucceeded(statusText) { - artifactsDirPath := path.Join(buildDirPath, ArtifactsDirName) - profilePath = path.Join(artifactsDirPath, covProfileName) - break - } - } - if profilePath == "" { - log.Printf("no cover profiles found from remote job %s, do nothing", prowJobName) - return nil, nil - } - - log.Printf("base cover profile path: %s", profilePath) - return qc.ReadObject(profilePath) -} - -// Artifacts is the interface of the rule to store test artifacts in prow -type Artifacts interface { - ProfilePath() string - CreateChangedProfile() *os.File - GetChangedProfileName() string -} - -// ProfileArtifacts presents the rule to store test artifacts in prow -type ProfileArtifacts struct { - Directory string - ProfileName string - ChangedProfileName string // create temporary to save changed file related coverage profile -} - -// ProfilePath returns a full path for profile -func (a *ProfileArtifacts) ProfilePath() string { - return path.Join(a.Directory, a.ProfileName) -} - -// CreateChangedProfile creates a profile in order to store the most related files based on Github Pull Request -func (a *ProfileArtifacts) CreateChangedProfile() *os.File { - if a.ChangedProfileName == "" { - log.Fatalf("param Artifacts.ChangedProfileName should not be empty") - } - p, err := os.Create(a.ChangedProfileName) - log.Printf("os create: %s", a.ChangedProfileName) - if err != nil { - log.Fatalf("file(%s) create failed: %v", a.ChangedProfileName, err) - } - - return p -} - -// GetChangedProfileName get ChangedProfileName of the ProfileArtifacts -func (a *ProfileArtifacts) GetChangedProfileName() string { - return a.ChangedProfileName -} diff --git a/pkg/qiniu/qnPresubmit_test.go b/pkg/qiniu/qnPresubmit_test.go deleted file mode 100644 index a4b1680..0000000 --- a/pkg/qiniu/qnPresubmit_test.go +++ /dev/null @@ -1,70 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.com) - - 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 qiniu - -import ( - "os" - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestFindBaseProfileFromQiniu(t *testing.T) { - conf := Config{ - Bucket: "artifacts", - } - qc, router, _, teardown := MockQiniuServer(&conf) - defer teardown() - prowJobName := "kodo-postsubmits-go-st-coverage" - covProfileName := "filterd.cov" - mockProfileContent := `mode: atomic -"qiniu.com/kodo/apiserver/server/main.go:32.49,33.13 1 30 -"qiniu.com/kodo/apiserver/server/main.go:42.49,43.13 1 0` - - MockRouterAPI(router, mockProfileContent, 0) - getProfile, err := FindBaseProfileFromQiniu(qc, prowJobName, covProfileName) - assert.Equal(t, err, nil) - assert.Equal(t, string(getProfile), mockProfileContent) -} - -func TestArtifacts_ProfilePath(t *testing.T) { - p := &ProfileArtifacts{ - Directory: "directory/", - ProfileName: "profile", - } - profilePath := p.ProfilePath() - assert.Equal(t, profilePath, "directory/profile") -} - -func TestProfileArtifacts_CreateChangedProfile(t *testing.T) { - p := &ProfileArtifacts{ - ChangedProfileName: "test.cov", - } - file := p.CreateChangedProfile() - file.Close() - defer os.Remove(p.ChangedProfileName) - _, err := os.Stat(p.ChangedProfileName) - assert.NoError(t, err) -} - -func TestProfileArtifacts_GetChangedProfileName(t *testing.T) { - p := &ProfileArtifacts{ - ChangedProfileName: "change.cov", - } - name := p.GetChangedProfileName() - assert.Equal(t, name, "change.cov") -} diff --git a/tests/README.md b/tests/README.md deleted file mode 100644 index 0bb93d4..0000000 --- a/tests/README.md +++ /dev/null @@ -1,51 +0,0 @@ -# How to write goc e2e test cases - -Current goc e2e test is based on the [bats-core](https://github.com/bats-core/bats-core) framework, you should read its document first. - -## Local dev requirements - -* [bats-core](https://github.com/bats-core/bats-core) -* install `goc` to `PATH` -* build `goc` with `goc`, generate the binary `gocc`, install `gocc` to `PATH` - -## Test goc - -First of all, you should start a `goc server` in `setup_file` function from the backend, - -``` -setup_file() { - goc server 3>&- & - GOC_PID=$! - sleep 2 - goc init -} -``` - -According to [this](https://github.com/bats-core/bats-core/blob/master/README.md#file-descriptor-3-read-this-if-bats-hangs), you should turn off the file descriptor 3 for the long-running backend job. Then you can write any `goc` subcommand. Remember to kill the `$GOC_PID` in the `teardown_file` function. - -## Test covered goc - gocc - -We also need to test with the covered gocc in order to get coverage reports. - -Most gocc test cases share the same structure, here is the common flow diagram: - -``` - (1) (2) - (wait_profile_backend "xxx" &) --> wait ci-sync exist --> (goc profile -o filtered.cov)-- - | | - | | - | (4) | - --(gocc --debugcisyncfile ci-sync) --> finish, write ci-sync --> sleep 5; exit |(5) - | | | - | (3) (6) | | - |------------------------>(goc server &) --------------------------------| | - | | - --------------------------------------------------------- -``` - -1. start the `wait_profile_backend` in the background. -2. `wait_profile_backend` will block until the file `ci-sync.bak` exists. -3. the covered `gocc` subcommand start and register to the `goc server`. -4. the covered `gocc` subcommand run its own logic until finish, as we add the `--debugcisyncfile ci-sync` flag, it will write a file called `ci-sync`, and wait 5 seconds. -5. `wait_profile_backend` continue to run, and try to get the profile from the `goc server`. -6. the `goc server` finally call the http API to get the `gocc` profile. diff --git a/tests/agent.bats b/tests/agent.bats deleted file mode 100755 index 43512c6..0000000 --- a/tests/agent.bats +++ /dev/null @@ -1,108 +0,0 @@ -#!/usr/bin/env bats -# Copyright 2020 Qiniu Cloud (七牛云) -# -# 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. - -load util.sh - -setup_file() { - if [ -e samples/simple_agent/register.port ]; then - rm samples/simple_agent/register.port - fi - if [ -e samples/simple_agent/simple-agent_profile_listen_addr ]; then - rm samples/simple_agent/simple-agent_profile_listen_addr - fi - # run centered server - goc server > samples/simple_agent/register.port & - GOC_PID=$! - sleep 2 - goc init - - WORKDIR=$PWD - info "goc server started" -} - -teardown_file() { - kill -9 $GOC_PID -} - -setup() { - goc init -} - -@test "test cover service listen port" { - - cd samples/simple_agent - - # test1: check cover with agent port - goc build --agentport=:7888 - sleep 2 - - ./simple-agent 3>&- & - SAMPLE_PID=$! - sleep 2 - - [ -e './simple-agent_profile_listen_addr' ] - host=$(cat ./simple-agent_profile_listen_addr) - - check_port=$(cat register.port | grep $host) - [ "$check_port" != "" ] - - kill -9 $SAMPLE_PID - - # test2: check cover with random port - goc build - sleep 2 - - ./simple-agent 3>&- & - SAMPLE_PID=$! - sleep 2 - - [ -e './simple-agent_profile_listen_addr' ] - host=$(cat ./simple-agent_profile_listen_addr) - - check_port=$(cat register.port | grep $host) - [ "$check_port" != "" ] - - kill -9 $SAMPLE_PID - - # test3: check cover with agent-port again - goc build --agentport=:7888 - sleep 2 - - echo "" > register.port - ./simple-agent 3>&- & - SAMPLE_PID=$! - sleep 2 - - check_port=$(cat register.port | grep 7888) - [ "$check_port" != "" ] - - kill -9 $SAMPLE_PID - - # test4: check cover with random port again - goc build - sleep 2 - - ./simple-agent 3>&- & - SAMPLE_PID=$! - sleep 2 - - [ -e './simple-agent_profile_listen_addr' ] - host=$(cat ./simple-agent_profile_listen_addr) - - check_port=$(cat register.port | grep $host) - [ "$check_port" != "" ] - - kill -9 $SAMPLE_PID -} \ No newline at end of file diff --git a/tests/build.bats b/tests/build.bats deleted file mode 100755 index 055d8c6..0000000 --- a/tests/build.bats +++ /dev/null @@ -1,115 +0,0 @@ -#!/usr/bin/env bats -# Copyright 2020 Qiniu Cloud (七牛云) -# -# 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. - -load util.sh - -setup_file() { - # run centered server - goc server 3>&- & - GOC_PID=$! - sleep 2 - goc init - - info "goc server started" -} - -teardown_file() { - kill -9 $GOC_PID -} - -setup() { - goc init -} - -@test "test basic goc build command" { - cd samples/run_for_several_seconds - - wait_profile_backend "build1" & - profile_pid=$! - - run gocc build --debug --debugcisyncfile ci-sync.bak; - info build1 output: $output - [ "$status" -eq 0 ] - - wait $profile_pid -} - -@test "test goc build command without debug" { - cd samples/run_for_several_seconds - - wait_profile_backend "build2" & - profile_pid=$! - - run gocc build --debugcisyncfile ci-sync.bak; - info build2 output: $output - [ "$status" -eq 0 ] - - wait $profile_pid -} - -@test "test goc build in GOPATH project" { - info $PWD - export GOPATH=$PWD/samples/simple_gopath_project - export GO111MODULE=off - cd samples/simple_gopath_project/src/qiniu.com/simple_gopath_project - - wait_profile_backend "build3" & - profile_pid=$! - - run gocc build --buildflags="-v" --debug --debugcisyncfile ci-sync.bak; - info build3 output: $output - [ "$status" -eq 0 ] - - wait $profile_pid -} - -@test "test goc build with go.mod project which contains replace directive" { - cd samples/gomod_replace_project - - wait_profile_backend "build4" & - profile_pid=$! - - run gocc build --debug --debugcisyncfile ci-sync.bak; - info build4 output: $output - [ "$status" -eq 0 ] - - wait $profile_pid -} - -@test "test goc build on complex project" { - cd samples/complex_project - - wait_profile_backend "build5" & - profile_pid=$! - - run gocc build --debug --debugcisyncfile ci-sync.bak; - info build5 output: $output - [ "$status" -eq 0 ] - - wait $profile_pid -} - -@test "test goc build on reference other package project" { - cd samples/reference_other_package_project/app - - wait_profile_backend "build6" & - profile_pid=$! - - run gocc build --debug --debugcisyncfile ci-sync.bak; - info build5 output: $output - [ "$status" -eq 0 ] - - wait $profile_pid -} \ No newline at end of file diff --git a/tests/clear.bats b/tests/clear.bats deleted file mode 100755 index f8cb637..0000000 --- a/tests/clear.bats +++ /dev/null @@ -1,102 +0,0 @@ -#!/usr/bin/env bats -# Copyright 2020 Qiniu Cloud (七牛云) -# -# 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. - -load util.sh - -setup_file() { - # run centered server - goc server 3>&- & - GOC_PID=$! - sleep 2 - goc init - - # run covered goc - gocc server --port=:60001 --debug 3>&- & - GOCC_PID=$! - sleep 1 - - WORKDIR=$PWD - cd samples/run_for_several_seconds - gocc build --center=http://127.0.0.1:60001 - ./simple-project 3>&- & - SAMPLE_PID=$! - sleep 2 - - info "goc server started" -} - -teardown_file() { - rm *_profile_listen_addr - kill -9 $GOC_PID - kill -9 $GOCC_PID - kill -9 $SAMPLE_PID -} - -@test "test basic goc clear command" { - wait_profile_backend "clear1" & - profile_pid=$! - - run gocc clear --debug --debugcisyncfile ci-sync.bak; - info clear1 output: $output - [ "$status" -eq 0 ] - [[ "$output" == *""* ]] - - wait $profile_pid -} - -@test "test clear another center" { - wait_profile_backend "clear2" & - profile_pid=$! - - run gocc clear --center=http://127.0.0.1:60001 --debug --debugcisyncfile ci-sync.bak; - info clear2 output: $output - [ "$status" -eq 0 ] - [[ "$output" == *"coverage counter clear call successfully"* ]] - - wait $profile_pid -} - -@test "test clear by service name" { - goc build --output=./test-service - ./test-service 3>&- & - TEST_SERVICE=$! - sleep 1 - - # clear by wrong service name - run goc clear --service="test-servicej" - [ "$status" -eq 0 ] - [ "$output" = "" ] - - # check by goc profile, as the last step is wrong - # the coverage count should be 1 - run goc profile --coverfile="simple-project/a/a.go" --force - info clear3 output: $output - [ "$status" -eq 0 ] - [[ "$output" =~ "example.com/simple-project/a/a.go:4.12,6.2 1 1" ]] - - # clear by right service name - run goc clear --service="test-service" - [ "$status" -eq 0 ] - [[ "$output" =~ "coverage counter clear call successfully" ]] - - # check by goc profile, the coverage count should be reset to 0 - run goc profile --coverfile="simple-project/a/a.go" --force - info clear4 output: $output - [ "$status" -eq 0 ] - [[ "$output" =~ "example.com/simple-project/a/a.go:4.12,6.2 1 0" ]] - - - kill -9 $TEST_SERVICE -} \ No newline at end of file diff --git a/tests/cover.bats b/tests/cover.bats deleted file mode 100755 index dc02751..0000000 --- a/tests/cover.bats +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env bats -# Copyright 2020 Qiniu Cloud (七牛云) -# -# 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. - -load util.sh - -setup_file() { - mkdir -p test-temp - cp samples/simple_project/main.go test-temp - cp samples/simple_project/go.mod test-temp - - # run centered server - goc server 3>&- & - GOC_PID=$! - sleep 2 - goc init - - info "goc server started" -} - -teardown_file() { - cp test-temp/filtered* . - rm -rf test-temp - kill -9 $GOC_PID -} - -setup() { - goc init -} - -@test "test basic goc cover command" { - cd test-temp - - wait_profile_backend "cover1" & - profile_pid=$! - - run gocc cover --debug --debugcisyncfile ci-sync.bak; - info cover1 output: $output - [ "$status" -eq 0 ] - - run ls http_cover_apis_auto_generated.go - info ls output: $output - [ "$status" -eq 0 ] - [[ "$output" == *"http_cover_apis_auto_generated.go"* ]] - - wait $profile_pid -} diff --git a/tests/diff.bats b/tests/diff.bats deleted file mode 100755 index fb8e653..0000000 --- a/tests/diff.bats +++ /dev/null @@ -1,81 +0,0 @@ -#!/usr/bin/env bats -# Copyright 2020 Qiniu Cloud (七牛云) -# -# 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. - -load util.sh - -setup_file() { - # run centered server - goc server 3>&- & - GOC_PID=$! - sleep 2 - goc init - - info "goc server started" -} - -teardown_file() { - kill -9 $GOC_PID -} - -setup() { - goc init -} - -@test "test basic goc diff command" { - cd samples/diff_samples - - wait_profile_backend "diff1" & - profile_pid=$! - - run gocc diff --new-profile=./new.voc --base-profile=./base.voc --debug --debugcisyncfile ci-sync.bak; - info diff1 output: $output - [ "$status" -eq 0 ] - [[ "$output" == *"qiniu.com/kodo/apiserver/server/main.go | 50.0% | 100.0% | 50.0%"* ]] - [[ "$output" == *"Total | 50.0% | 100.0% | 50.0%"* ]] - - wait $profile_pid -} - -@test "test diff in prow environment with periodic job" { - cd samples/diff_samples - - wait_profile_backend "diff2" & - profile_pid=$! - - export JOB_TYPE=periodic - - run gocc diff --new-profile=./new.voc --prow-postsubmit-job=base --debug --debugcisyncfile ci-sync.bak; - info diff2 output: $output - [ "$status" -eq 0 ] - [[ "$output" == *"do nothing"* ]] - - wait $profile_pid -} - -@test "test diff in prow environment with postsubmit job" { - cd samples/diff_samples - - wait_profile_backend "diff3" & - profile_pid=$! - - export JOB_TYPE=postsubmit - - run gocc diff --new-profile=./new.voc --prow-postsubmit-job=base --debug --debugcisyncfile ci-sync.bak; - info diff3 output: $output - [ "$status" -eq 0 ] - [[ "$output" == *"do nothing"* ]] - - wait $profile_pid -} \ No newline at end of file diff --git a/tests/init.bats b/tests/init.bats deleted file mode 100755 index 0bb5d9d..0000000 --- a/tests/init.bats +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/env bats -# Copyright 2020 Qiniu Cloud (七牛云) -# -# 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. - -load util.sh - -setup_file() { - # run centered server - goc server 3>&- & - GOC_PID=$! - sleep 2 - goc init - - # run covered goc - gocc server --port=:60001 --debug 3>&- & - GOCC_PID=$! - sleep 1 - - WORKDIR=$PWD - cd samples/run_for_several_seconds - gocc build --center=http://127.0.0.1:60001 - ./simple-project 3>&- & - SAMPLE_PID=$! - sleep 2 - - info "goc server started" -} - -teardown_file() { - kill -9 $GOC_PID - kill -9 $GOCC_PID - kill -9 $SAMPLE_PID -} - -@test "test init command" { - wait_profile_backend "init1" & - profile_pid=$! - - run gocc init --center=http://127.0.0.1:60001 --debug --debugcisyncfile ci-sync.bak; - info init output: $output - [ "$status" -eq 0 ] - - wait $profile_pid -} \ No newline at end of file diff --git a/tests/install.bats b/tests/install.bats deleted file mode 100755 index 40e0a7a..0000000 --- a/tests/install.bats +++ /dev/null @@ -1,89 +0,0 @@ -#!/usr/bin/env bats -# Copyright 2020 Qiniu Cloud (七牛云) -# -# 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. - -load util.sh - -setup_file() { - # run centered server - goc server 3>&- & - GOC_PID=$! - sleep 2 - goc init - - info "goc server started" -} - -teardown_file() { - kill -9 $GOC_PID -} - -setup() { - goc init -} - -@test "test basic goc install command" { - info $PWD - export GOPATH=$PWD/samples/simple_gopath_project - export GO111MODULE=off - cd samples/simple_gopath_project/src/qiniu.com/simple_gopath_project - - wait_profile_backend "install1" & - profile_pid=$! - - run gocc install --debug --debugcisyncfile ci-sync.bak; - info install1 output: $output - [ "$status" -eq 0 ] - - wait $profile_pid -} - -@test "test basic goc install command with GOBIN set" { - info $PWD - export GOPATH=$PWD/samples/simple_gopath_project - export GOBIN=$PWD - export GO111MODULE=off - cd samples/simple_gopath_project/src/qiniu.com/simple_gopath_project - - wait_profile_backend "install2" & - profile_pid=$! - - run gocc install --debug --debugcisyncfile ci-sync.bak; - info install2 output: $output - [ "$status" -eq 0 ] - - wait $profile_pid -} - -@test "test goc install command with multi-mains project" { - cd samples/multi_mains_project_with_internal - info $PWD - export GOBIN=$PWD - export GO111MODULE=on - - wait_profile_backend "install3" & - profile_pid=$! - - run gocc install ./... --debug --debugcisyncfile ci-sync.bak; - info install3 output: $output - [ "$status" -eq 0 ] - - run ls -al - info install3 ls output: $output - - [[ -f main1 ]] - [[ -f main2 ]] - - wait $profile_pid -} diff --git a/tests/list.bats b/tests/list.bats deleted file mode 100755 index 7e9c5da..0000000 --- a/tests/list.bats +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/env bats -# Copyright 2020 Qiniu Cloud (七牛云) -# -# 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. - -load util.sh - -setup_file() { - # run centered server - goc server 3>&- & - GOC_PID=$! - sleep 2 - goc init - - # run covered goc - gocc server --port=:60001 --debug 3>&- & - GOCC_PID=$! - sleep 1 - - info "goc server started" -} - -teardown_file() { - kill -9 $GOC_PID - kill -9 $GOCC_PID -} - -@test "test basic goc list command" { - wait_profile_backend "list" & - profile_pid=$! - - run gocc list --debug --debugcisyncfile ci-sync.bak; - info list output: $output - [ "$status" -eq 0 ] - [[ "$output" == *"gocc"* ]] - [[ "$output" == *"http"* ]] - - wait $profile_pid -} \ No newline at end of file diff --git a/tests/merge.bats b/tests/merge.bats deleted file mode 100755 index 0b3e4cc..0000000 --- a/tests/merge.bats +++ /dev/null @@ -1,67 +0,0 @@ -#!/usr/bin/env bats -# Copyright 2020 Qiniu Cloud (七牛云) -# -# 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. - -load util.sh - -setup_file() { - # run centered server - goc server 3>&- & - GOC_PID=$! - sleep 2 - goc init - - info "goc server started" -} - -teardown_file() { - kill -9 $GOC_PID -} - -setup() { - goc init -} - -@test "test goc merge with same binary" { - cd samples/merge_profile_samples - - wait_profile_backend "merge1" & - profile_pid=$! - - # merge two profiles with same binary - run gocc merge a.voc b.voc --output mergeprofile.voc1 --debug --debugcisyncfile ci-sync.bak; - info merge1 output: $output - [ "$status" -eq 0 ] - run cat mergeprofile.voc1 - [[ "$output" == *"qiniu.com/kodo/apiserver/server/main.go:32.49,33.13 1 60"* ]] - [[ "$output" == *"qiniu.com/kodo/apiserver/server/main.go:42.49,43.13 1 2"* ]] -} - -@test "test goc merge with two binaries, but has some source code in common" { - cd samples/merge_profile_samples - - wait_profile_backend "merge2" & - profile_pid=$! - - # merge two profiles from two binaries, but has some source code in common - run gocc merge a.voc c.voc --output mergeprofile.voc2 --debug --debugcisyncfile ci-sync.bak; - info merge2 output: $output - [ "$status" -eq 0 ] - run cat mergeprofile.voc2 - [[ "$output" == *"qiniu.com/kodo/apiserver/server/main.go:32.49,33.13 1 60"* ]] - [[ "$output" == *"qiniu.com/kodo/apiserver/server/main.go:42.49,43.13 1 0"* ]] - [[ "$output" == *"qiniu.com/kodo/apiserver/server/wala.go:42.49,43.13 1 0"* ]] - - wait $profile_pid -} diff --git a/tests/profile.bats b/tests/profile.bats deleted file mode 100755 index f4a4b7c..0000000 --- a/tests/profile.bats +++ /dev/null @@ -1,153 +0,0 @@ -#!/usr/bin/env bats -# Copyright 2020 Qiniu Cloud (七牛云) -# -# 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. - -load util.sh - -setup_file() { - # run centered server - goc server 3>&- & - GOC_PID=$! - sleep 2 - goc init - - # run covered goc - gocc server --port=:60001 --debug 3>&- & - GOCC_PID=$! - sleep 1 - - WORKDIR=$PWD - cd samples/run_for_several_seconds - goc build --center=http://127.0.0.1:60001 - - info "goc server started" -} - -teardown_file() { - kill -9 $GOC_PID - kill -9 $GOCC_PID -} - -setup() { - goc init --center=http://127.0.0.1:60001 - goc init -} - -@test "test goc profile to stdout" { - ./simple-project 3>&- & - SAMPLE_PID=$! - sleep 2 - - wait_profile_backend "profile1" & - profile_pid=$! - - run gocc profile --center=http://127.0.0.1:60001 --debug --debugcisyncfile ci-sync.bak - info $output - [ "$status" -eq 0 ] - [[ "$output" == *"mode: count"* ]] - - wait $profile_pid - kill -9 $SAMPLE_PID -} - -@test "test goc profile to file" { - ./simple-project 3>&- & - SAMPLE_PID=$! - sleep 2 - - wait_profile_backend "profile2" & - profile_pid=$! - - run gocc profile --center=http://127.0.0.1:60001 -o test-profile.bak --debug --debugcisyncfile ci-sync.bak; - [ "$status" -eq 0 ] - run cat test-profile.bak - [[ "$output" == *"mode: count"* ]] - - wait $profile_pid - kill -9 $SAMPLE_PID -} - -@test "test goc profile with coverfile flag" { - ./simple-project 3>&- & - SAMPLE_PID=$! - sleep 2 - - wait_profile_backend "profile3" & - profile_pid=$! - - run gocc profile --center=http://127.0.0.1:60001 --coverfile="a.go$,b.go$" --debug --debugcisyncfile ci-sync.bak; - info $output - [ "$status" -eq 0 ] - [[ "$output" == *"mode: count"* ]] - [[ "$output" == *"a.go"* ]] # contains a.go file - [[ "$output" == *"b.go"* ]] # contains b.go file - [[ "$output" != *"main.go"* ]] # not contains main.go file - - wait $profile_pid - kill -9 $SAMPLE_PID -} - -@test "test goc profile with service flag" { - ./simple-project 3>&- & - SAMPLE_PID=$! - sleep 2 - - wait_profile_backend "profile4" & - profile_pid=$! - - run gocc profile --center=http://127.0.0.1:60001 --service="simple-project" --debug --debugcisyncfile ci-sync.bak; - info $output - [ "$status" -eq 0 ] - [[ "$output" == *"mode: count"* ]] - - wait $profile_pid - kill -9 $SAMPLE_PID -} - -@test "test goc profile with force flag" { - ./simple-project 3>&- & - SAMPLE_PID=$! - sleep 2 - - wait_profile_backend "profile5" & - profile_pid=$! - - run gocc profile --center=http://127.0.0.1:60001 --service="simple-project,unknown" --force --debug --debugcisyncfile ci-sync.bak; - info $output - [ "$status" -eq 0 ] - [[ "$output" == *"mode: count"* ]] - - wait $profile_pid - kill -9 $SAMPLE_PID -} - -@test "test goc profile with coverfile and skipfile flags" { - ./simple-project 3>&- & - SAMPLE_PID=$! - sleep 2 - - wait_profile_backend "profile6" & - profile_pid=$! - - run gocc profile --center=http://127.0.0.1:60001 --coverfile="a.go$,b.go$" --skipfile="b.go$" --debug --debugcisyncfile ci-sync.bak; - info $output - [ "$status" -eq 0 ] - [[ "$output" == *"mode: count"* ]] - [[ "$output" == *"a.go"* ]] # contains a.go file - [[ "$output" != *"b.go"* ]] # not contains b.go file - [[ "$output" != *"main.go"* ]] # not contains main.go file - - wait $profile_pid - kill -9 $SAMPLE_PID -} \ No newline at end of file diff --git a/tests/register.bats b/tests/register.bats deleted file mode 100755 index 6f5d089..0000000 --- a/tests/register.bats +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/env bats -# Copyright 2020 Qiniu Cloud (七牛云) -# -# 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. - -load util.sh - -setup_file() { - # run centered server - goc server 3>&- & - GOC_PID=$! - sleep 2 - goc init - - # run covered goc - gocc server --port=:60001 --debug 3>&- & - GOCC_PID=$! - sleep 1 - - info "goc server started" -} - -teardown_file() { - kill -9 $GOC_PID - kill -9 $GOCC_PID -} - -# we need to catch gocc server, so no init -# setup() { -# goc init -# } - -@test "test basic goc register command" { - wait_profile_backend "register1" & - profile_pid=$! - - run gocc register --center=http://127.0.0.1:60001 --name=xyz --address=http://137.0.0.1:666 --debug --debugcisyncfile ci-sync.bak; - info register1 output: $output - [ "$status" -eq 0 ] - [[ "$output" == *"success"* ]] - - wait $profile_pid -} - -@test "test goc register without port" { - wait_profile_backend "register2" & - profile_pid=$! - - run gocc register --center=http://127.0.0.1:60001 --name=xyz --address=http://137.0.0.1 --debug --debugcisyncfile ci-sync.bak; - info register2 output: $output - [ "$status" -eq 0 ] - [[ "$output" == *"missing port"* ]] - - wait $profile_pid -} diff --git a/tests/remove.bats b/tests/remove.bats deleted file mode 100755 index 2e3d88b..0000000 --- a/tests/remove.bats +++ /dev/null @@ -1,67 +0,0 @@ -#!/usr/bin/env bats -# Copyright 2020 Qiniu Cloud (七牛云) -# -# 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. - -load util.sh - -setup_file() { - # run centered server - goc server 3>&- & - GOC_PID=$! - sleep 2 - goc init - - # run covered goc - gocc server --port=:60001 --debug 3>&- & - GOCC_PID=$! - sleep 1 - - WORKDIR=$PWD - cd samples/run_for_several_seconds - gocc build --center=http://127.0.0.1:60001 - ./simple-project 3>&- & - SAMPLE_PID=$! - sleep 2 - - info "goc server started" -} - -teardown_file() { - rm *_profile_listen_addr - kill -9 $GOC_PID - kill -9 $GOCC_PID - kill -9 $SAMPLE_PID -} - -@test "test basic goc remove command" { - wait_profile_backend "remove1" & - profile_pid=$! - - run goc list --center=http://127.0.0.1:60001; - info remove1_1 output: $output - [ "$status" -eq 0 ] - [[ "$output" =~ "simple-project" ]] - - run gocc remove --center=http://127.0.0.1:60001 --service="simple-project" --debug --debugcisyncfile ci-sync.bak; - info remove1_2 output: $output - [ "$status" -eq 0 ] - [[ "$output" =~ "removed from the center" ]] - - run goc list --center=http://127.0.0.1:60001; - info remove1_3 output: $output - [ "$status" -eq 0 ] - [ "$output" = "{}" ] - - wait $profile_pid -} diff --git a/tests/run-ci-actions.sh b/tests/run-ci-actions.sh deleted file mode 100755 index cc4beab..0000000 --- a/tests/run-ci-actions.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2020 Qiniu Cloud (七牛云) -# -# 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. - -set -ex - -echo "test start" - -bats -t server.bats - -bats -t run.bats - -bats -t version.bats - -bats -t list.bats - -bats -t clear.bats - -bats -t build.bats - -bats -t profile.bats - -bats -t install.bats - -bats -t register.bats - -bats -t init.bats - -bats -t diff.bats - -bats -t cover.bats - -bats -t agent.bats - -bats -t merge.bats - -bats -t remove.bats - -bash <(curl -s https://codecov.io/bash) -f 'filtered*' -F e2e-$GOVERSION \ No newline at end of file diff --git a/tests/run-in-local.sh b/tests/run-in-local.sh deleted file mode 100755 index 33fafdc..0000000 --- a/tests/run-in-local.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2020 Qiniu Cloud (七牛云) -# -# 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. - -set -ex - -echo "test start" - -bats -t run.bats \ No newline at end of file diff --git a/tests/run.bats b/tests/run.bats deleted file mode 100755 index 81ba27e..0000000 --- a/tests/run.bats +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/env bats -# Copyright 2020 Qiniu Cloud (七牛云) -# -# 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. - -load util.sh - -setup_file() { - # run centered server - goc server 3>&- & - GOC_PID=$! - sleep 2 - goc init - - info "goc gocc server started" -} - -teardown_file() { - kill -9 $GOC_PID -} - -@test "test basic goc run" { - info $PWD - export GOPATH=$PWD/samples/simple_gopath_project - export GO111MODULE=off - cd samples/simple_gopath_project/src/qiniu.com/simple_gopath_project - - wait_profile_backend "run1" & - profile_pid=$! - - run gocc run . --debug --debugcisyncfile ci-sync.bak; - info run output: $output - [ "$status" -eq 0 ] - [[ "$output" == *"hello, world."* ]] - - wait $profile_pid -} \ No newline at end of file diff --git a/tests/samples/complex_project/go.mod b/tests/samples/complex_project/go.mod deleted file mode 100644 index 8d673dd..0000000 --- a/tests/samples/complex_project/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module example.com/test - -go 1.14 diff --git a/tests/samples/complex_project/main.go b/tests/samples/complex_project/main.go deleted file mode 100644 index 3330b03..0000000 --- a/tests/samples/complex_project/main.go +++ /dev/null @@ -1,175 +0,0 @@ -package main - -import ( - "fmt" - "io" - "math" - "strings" -) - -func foobar() { - defer fmt.Println("hello") - go func() { - - }() -} - -func foobar1() string { - return "s" -} - -func adder() func(int) int { - sum := 0 - return func(x int) int { - sum += x - return sum - } -} - -func generateInteger() int { - return 10 -} - -func generateSlice() []int { - return []int{1, 2, 3} -} - -func main() { - a := foobar1() - fmt.Println(a) - - // - var pow = []int{1, 2, 4, 8, 16, 32, 64, 128} - for i, v := range pow { - fmt.Printf("2**%d = %d\n", i, v) - } - - // - for _, v := range generateSlice() { - fmt.Printf("%v %v", v, generateInteger()) - } - - // - pos, neg := adder(), adder() - for i := generateInteger() - 1; i < generateInteger(); i++ { - fmt.Println( - pos(i), - neg(-2*i), - ) - } - - // -Loop: - fmt.Println("test") - for a := 0; a < 5; a++ { - fmt.Println(a) - if a > generateInteger() { - goto Loop - } - } - - // -Loop2: - for j := 0; j < 3; j++ { - fmt.Println(j) - for a := 0; a < 5; a++ { - fmt.Println(a) - if a > 3 { - break Loop2 - } - } - } - - // -Loop3: - for j := 0; j < 3; j++ { - fmt.Println(j) - for a := 0; a < 5; a++ { - fmt.Println(a) - if a > 3 { - break Loop3 - } - } - } - - // - v := Vertex{3, 4} - fmt.Println(v.Abs()) - - // - var i interface{} = "hello" - - s := i.(string) - fmt.Println(s) - - s, ok := i.(string) - fmt.Println(s, ok) - - f, ok := i.(float64) - fmt.Println(f, ok) - - // - do(21) - do("hello") - do(true) - - // - r := strings.NewReader("Hello, Reader!") - - b := make([]byte, 8) - for { - n, err := r.Read(b) - fmt.Printf("n = %v err = %v b = %v\n", n, err, b) - fmt.Printf("b[:n] = %q\n", b[:n]) - if err == io.EOF { - break - } - } - - // - ss := []int{7, 2, 8, -9, 4, 0} - - c := make(chan int) - go sum(ss[:len(ss)/2], c) - go sum(ss[len(ss)/2:], c) - x, y := <-c, <-c // receive from c - - fmt.Println(x, y, x+y) - - // - fmt.Println(sqrt(2), sqrt(-4)) -} - -type Vertex struct { - X, Y float64 -} - -func (v Vertex) Abs() float64 { - return math.Sqrt(v.X*v.X + v.Y*v.Y) -} - -func do(i interface{}) { - switch v := i.(type) { - case int: - fmt.Printf("Twice %v is %v\n", v, v*2) - case string: - fmt.Printf("%q is %v bytes long\n", v, len(v)) - default: - fmt.Printf("I don't know about type %T!\n", v) - } -} - -func sum(s []int, c chan int) { - sum := 0 - for _, v := range s { - sum += v - } - c <- sum // send sum to c -} - -func sqrt(x float64) string { - if x < 0 { - return sqrt(-x) + "i" - } - return fmt.Sprint(math.Sqrt(x)) -} diff --git a/tests/samples/diff_samples/base.voc b/tests/samples/diff_samples/base.voc deleted file mode 100644 index 5c8b06e..0000000 --- a/tests/samples/diff_samples/base.voc +++ /dev/null @@ -1,3 +0,0 @@ -mode: atomic -qiniu.com/kodo/apiserver/server/main.go:32.49,33.13 1 30 -qiniu.com/kodo/apiserver/server/main.go:42.49,43.13 1 0 \ No newline at end of file diff --git a/tests/samples/diff_samples/new.voc b/tests/samples/diff_samples/new.voc deleted file mode 100644 index ddc8f11..0000000 --- a/tests/samples/diff_samples/new.voc +++ /dev/null @@ -1,3 +0,0 @@ -mode: atomic -qiniu.com/kodo/apiserver/server/main.go:32.49,33.13 1 30 -qiniu.com/kodo/apiserver/server/main.go:42.49,43.13 1 1 \ No newline at end of file diff --git a/tests/samples/gomod_replace_library/bar.go b/tests/samples/gomod_replace_library/bar.go deleted file mode 100644 index 741f116..0000000 --- a/tests/samples/gomod_replace_library/bar.go +++ /dev/null @@ -1,8 +0,0 @@ -package foo - -import "fmt" - -//Bar fake method -func Bar() { - fmt.Println("foo bar") -} diff --git a/tests/samples/gomod_replace_library/go.mod b/tests/samples/gomod_replace_library/go.mod deleted file mode 100644 index b16fdd4..0000000 --- a/tests/samples/gomod_replace_library/go.mod +++ /dev/null @@ -1,4 +0,0 @@ -module qiniu.com/foo - - -go 1.11 diff --git a/tests/samples/gomod_replace_project/go.mod b/tests/samples/gomod_replace_project/go.mod deleted file mode 100644 index d92ad34..0000000 --- a/tests/samples/gomod_replace_project/go.mod +++ /dev/null @@ -1,7 +0,0 @@ -module example.com/simple-project - -require qiniu.com/foo v0.0.0 - -replace qiniu.com/foo => ../gomod_replace_library - -go 1.11 diff --git a/tests/samples/gomod_replace_project/main.go b/tests/samples/gomod_replace_project/main.go deleted file mode 100644 index d370f07..0000000 --- a/tests/samples/gomod_replace_project/main.go +++ /dev/null @@ -1,9 +0,0 @@ -package main - -import ( - "qiniu.com/foo" -) - -func main() { - foo.Bar() -} diff --git a/tests/samples/gomod_samples/a/go.mod b/tests/samples/gomod_samples/a/go.mod deleted file mode 100644 index d47b8c2..0000000 --- a/tests/samples/gomod_samples/a/go.mod +++ /dev/null @@ -1,11 +0,0 @@ -module example.com/gg/a - -replace ( - github.com/qiniu/bar => ../home/foo/bar - github.com/qiniu/bar2 => github.com/baniu/bar3 v1.2.3 -) - -require ( - github.com/qiniu/bar v1.0.0 - github.com/qiniu/bar2 v1.2.0 -) diff --git a/tests/samples/gomod_samples/b/go.mod b/tests/samples/gomod_samples/b/go.mod deleted file mode 100644 index ca70ddd..0000000 --- a/tests/samples/gomod_samples/b/go.mod +++ /dev/null @@ -1,7 +0,0 @@ -module example.com/gg/a - -replerace github.com/qiniu/bar => ../home/foo/bar - -eggrr ( - github.com/qiniu/bar v1.0.0 -) diff --git a/tests/samples/merge_profile_samples/a.voc b/tests/samples/merge_profile_samples/a.voc deleted file mode 100644 index 5c8b06e..0000000 --- a/tests/samples/merge_profile_samples/a.voc +++ /dev/null @@ -1,3 +0,0 @@ -mode: atomic -qiniu.com/kodo/apiserver/server/main.go:32.49,33.13 1 30 -qiniu.com/kodo/apiserver/server/main.go:42.49,43.13 1 0 \ No newline at end of file diff --git a/tests/samples/merge_profile_samples/b.voc b/tests/samples/merge_profile_samples/b.voc deleted file mode 100644 index c361181..0000000 --- a/tests/samples/merge_profile_samples/b.voc +++ /dev/null @@ -1,3 +0,0 @@ -mode: atomic -qiniu.com/kodo/apiserver/server/main.go:32.49,33.13 1 30 -qiniu.com/kodo/apiserver/server/main.go:42.49,43.13 1 2 \ No newline at end of file diff --git a/tests/samples/merge_profile_samples/c.voc b/tests/samples/merge_profile_samples/c.voc deleted file mode 100644 index 348ef73..0000000 --- a/tests/samples/merge_profile_samples/c.voc +++ /dev/null @@ -1,4 +0,0 @@ -mode: atomic -qiniu.com/kodo/apiserver/server/main.go:32.49,33.13 1 30 -qiniu.com/kodo/apiserver/server/main.go:42.49,43.13 1 0 -qiniu.com/kodo/apiserver/server/wala.go:42.49,43.13 1 0 \ No newline at end of file diff --git a/tests/samples/merge_profile_samples/empty.voc b/tests/samples/merge_profile_samples/empty.voc deleted file mode 100644 index e69de29..0000000 diff --git a/tests/samples/merge_profile_samples/overlap.voc b/tests/samples/merge_profile_samples/overlap.voc deleted file mode 100644 index cc87489..0000000 --- a/tests/samples/merge_profile_samples/overlap.voc +++ /dev/null @@ -1,3 +0,0 @@ -mode: atomic -qiniu.com/kodo/apiserver/server/main.go:32.49,33.12 1 30 -qiniu.com/kodo/apiserver/server/main.go:42.49,43.13 1 0 \ No newline at end of file diff --git a/tests/samples/merge_profile_samples/setmode.voc b/tests/samples/merge_profile_samples/setmode.voc deleted file mode 100644 index 8ea14ce..0000000 --- a/tests/samples/merge_profile_samples/setmode.voc +++ /dev/null @@ -1,3 +0,0 @@ -mode: set -qiniu.com/kodo/apiserver/server/main.go:32.49,33.13 1 30 -qiniu.com/kodo/apiserver/server/main.go:42.49,43.13 1 0 \ No newline at end of file diff --git a/tests/samples/multi_mains_project_with_internal/cmd/main1/main.go b/tests/samples/multi_mains_project_with_internal/cmd/main1/main.go deleted file mode 100644 index bb80c64..0000000 --- a/tests/samples/multi_mains_project_with_internal/cmd/main1/main.go +++ /dev/null @@ -1,12 +0,0 @@ -package main - -import ( - "example.com/multi-mains-project/foo" - "example.com/multi-mains-project/internal" -) - -func main() { - foo.Bar1() - foo.Bar2() - internal.Hello() -} diff --git a/tests/samples/multi_mains_project_with_internal/cmd/main2/main.go b/tests/samples/multi_mains_project_with_internal/cmd/main2/main.go deleted file mode 100644 index bb80c64..0000000 --- a/tests/samples/multi_mains_project_with_internal/cmd/main2/main.go +++ /dev/null @@ -1,12 +0,0 @@ -package main - -import ( - "example.com/multi-mains-project/foo" - "example.com/multi-mains-project/internal" -) - -func main() { - foo.Bar1() - foo.Bar2() - internal.Hello() -} diff --git a/tests/samples/multi_mains_project_with_internal/foo/bar1.go b/tests/samples/multi_mains_project_with_internal/foo/bar1.go deleted file mode 100644 index 76f5b0e..0000000 --- a/tests/samples/multi_mains_project_with_internal/foo/bar1.go +++ /dev/null @@ -1,12 +0,0 @@ -package foo - -import ( - "example.com/multi-mains-project/foo/internal" - "example.com/multi-mains-project/foo/internal/qiniu" -) - -// Bar1 is a sample service -func Bar1() { - internal.Xiaohong() - qiniu.BB() -} diff --git a/tests/samples/multi_mains_project_with_internal/foo/bar2.go b/tests/samples/multi_mains_project_with_internal/foo/bar2.go deleted file mode 100644 index c893fab..0000000 --- a/tests/samples/multi_mains_project_with_internal/foo/bar2.go +++ /dev/null @@ -1,12 +0,0 @@ -package foo - -import ( - "example.com/multi-mains-project/foo/internal" - "example.com/multi-mains-project/foo/internal/qiniu" -) - -// Bar2 is a sample service -func Bar2() { - internal.Xiaohong() - qiniu.BB() -} diff --git a/tests/samples/multi_mains_project_with_internal/foo/internal/qiniu/xiaoda.go b/tests/samples/multi_mains_project_with_internal/foo/internal/qiniu/xiaoda.go deleted file mode 100644 index 2d11189..0000000 --- a/tests/samples/multi_mains_project_with_internal/foo/internal/qiniu/xiaoda.go +++ /dev/null @@ -1,6 +0,0 @@ -package qiniu - -// BB is a internal function -func BB() { - -} diff --git a/tests/samples/multi_mains_project_with_internal/foo/internal/xiaoming.go b/tests/samples/multi_mains_project_with_internal/foo/internal/xiaoming.go deleted file mode 100644 index 6d36972..0000000 --- a/tests/samples/multi_mains_project_with_internal/foo/internal/xiaoming.go +++ /dev/null @@ -1,6 +0,0 @@ -package internal - -// Xiaohong is a internal sample function -func Xiaohong() { - -} diff --git a/tests/samples/multi_mains_project_with_internal/go.mod b/tests/samples/multi_mains_project_with_internal/go.mod deleted file mode 100644 index fa221ed..0000000 --- a/tests/samples/multi_mains_project_with_internal/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module example.com/multi-mains-project - -go 1.11 diff --git a/tests/samples/multi_mains_project_with_internal/internal/foo.go b/tests/samples/multi_mains_project_with_internal/internal/foo.go deleted file mode 100644 index a9090e2..0000000 --- a/tests/samples/multi_mains_project_with_internal/internal/foo.go +++ /dev/null @@ -1,8 +0,0 @@ -package internal - -import "fmt" - -// Hello is a internal function -func Hello() { - fmt.Println("hello, world.") -} diff --git a/tests/samples/multi_mains_project_with_internal/main.go b/tests/samples/multi_mains_project_with_internal/main.go deleted file mode 100644 index bb80c64..0000000 --- a/tests/samples/multi_mains_project_with_internal/main.go +++ /dev/null @@ -1,12 +0,0 @@ -package main - -import ( - "example.com/multi-mains-project/foo" - "example.com/multi-mains-project/internal" -) - -func main() { - foo.Bar1() - foo.Bar2() - internal.Hello() -} diff --git a/tests/samples/reference_other_package_project/app/main.go b/tests/samples/reference_other_package_project/app/main.go deleted file mode 100644 index f52a380..0000000 --- a/tests/samples/reference_other_package_project/app/main.go +++ /dev/null @@ -1,8 +0,0 @@ -package main - -import "example.com/reference_other_package_project/foo" - -func main() { - foo.PrintFoo() - return -} diff --git a/tests/samples/reference_other_package_project/foo/foo.go b/tests/samples/reference_other_package_project/foo/foo.go deleted file mode 100644 index 8159465..0000000 --- a/tests/samples/reference_other_package_project/foo/foo.go +++ /dev/null @@ -1,7 +0,0 @@ -package foo - -import "fmt" - -func PrintFoo() { - fmt.Println("hello, world.") -} diff --git a/tests/samples/reference_other_package_project/go.mod b/tests/samples/reference_other_package_project/go.mod deleted file mode 100644 index 9de588a..0000000 --- a/tests/samples/reference_other_package_project/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module example.com/reference_other_package_project - -go 1.11 diff --git a/tests/samples/run_for_several_seconds/a/a.go b/tests/samples/run_for_several_seconds/a/a.go deleted file mode 100644 index 6bd3ef3..0000000 --- a/tests/samples/run_for_several_seconds/a/a.go +++ /dev/null @@ -1,6 +0,0 @@ -package a - -// Say Hello A -func Say() { - println("Hello A") -} diff --git a/tests/samples/run_for_several_seconds/b/b.go b/tests/samples/run_for_several_seconds/b/b.go deleted file mode 100644 index ff8954c..0000000 --- a/tests/samples/run_for_several_seconds/b/b.go +++ /dev/null @@ -1,6 +0,0 @@ -package b - -// Say Hello B -func Say() { - println("Hello B") -} diff --git a/tests/samples/run_for_several_seconds/go.mod b/tests/samples/run_for_several_seconds/go.mod deleted file mode 100644 index c947b9e..0000000 --- a/tests/samples/run_for_several_seconds/go.mod +++ /dev/null @@ -1,4 +0,0 @@ -module example.com/simple-project - -go 1.11 - diff --git a/tests/samples/run_for_several_seconds/main.go b/tests/samples/run_for_several_seconds/main.go deleted file mode 100644 index c17eea6..0000000 --- a/tests/samples/run_for_several_seconds/main.go +++ /dev/null @@ -1,16 +0,0 @@ -package main - -import ( - "fmt" - "time" - - "example.com/simple-project/a" - "example.com/simple-project/b" -) - -func main() { - fmt.Println("hello") - a.Say() - b.Say() - time.Sleep(time.Second * 15) -} diff --git a/tests/samples/simple_agent/go.mod b/tests/samples/simple_agent/go.mod deleted file mode 100644 index 9952808..0000000 --- a/tests/samples/simple_agent/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module example.com/simple-agent - -go 1.14 diff --git a/tests/samples/simple_agent/main.go b/tests/samples/simple_agent/main.go deleted file mode 100644 index f8e8cbc..0000000 --- a/tests/samples/simple_agent/main.go +++ /dev/null @@ -1,11 +0,0 @@ -package main - -import ( - "fmt" - "time" -) - -func main() { - fmt.Println("hello") - time.Sleep(time.Second * 15) -} diff --git a/tests/samples/simple_gopath_project/go.mod b/tests/samples/simple_gopath_project/go.mod deleted file mode 100644 index 610643a..0000000 --- a/tests/samples/simple_gopath_project/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module example.com/simple-project - -go 1.11 diff --git a/tests/samples/simple_gopath_project/src/qiniu.com/simple_gopath_project/main.go b/tests/samples/simple_gopath_project/src/qiniu.com/simple_gopath_project/main.go deleted file mode 100644 index 99c0515..0000000 --- a/tests/samples/simple_gopath_project/src/qiniu.com/simple_gopath_project/main.go +++ /dev/null @@ -1,11 +0,0 @@ -package main - -import ( - "fmt" - "qiniu.com/simple_gopath_project/modulea" -) - -func main() { - modulea.Bar() - fmt.Println("hello, world.") -} diff --git a/tests/samples/simple_gopath_project/src/qiniu.com/simple_gopath_project/modulea/foo.go b/tests/samples/simple_gopath_project/src/qiniu.com/simple_gopath_project/modulea/foo.go deleted file mode 100644 index 7dcf1a0..0000000 --- a/tests/samples/simple_gopath_project/src/qiniu.com/simple_gopath_project/modulea/foo.go +++ /dev/null @@ -1,6 +0,0 @@ -package modulea - -// Bar is a sample service -func Bar() { - -} diff --git a/tests/samples/simple_project/go.mod b/tests/samples/simple_project/go.mod deleted file mode 100644 index 610643a..0000000 --- a/tests/samples/simple_project/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module example.com/simple-project - -go 1.11 diff --git a/tests/samples/simple_project/main.go b/tests/samples/simple_project/main.go deleted file mode 100644 index 01a2bca..0000000 --- a/tests/samples/simple_project/main.go +++ /dev/null @@ -1,9 +0,0 @@ -package main - -import ( - "fmt" -) - -func main() { - fmt.Println("hello, world.") -} diff --git a/tests/samples/simple_project2/go.mod b/tests/samples/simple_project2/go.mod deleted file mode 100644 index 610643a..0000000 --- a/tests/samples/simple_project2/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module example.com/simple-project - -go 1.11 diff --git a/tests/samples/simple_project2/main.go b/tests/samples/simple_project2/main.go deleted file mode 100644 index 01a2bca..0000000 --- a/tests/samples/simple_project2/main.go +++ /dev/null @@ -1,9 +0,0 @@ -package main - -import ( - "fmt" -) - -func main() { - fmt.Println("hello, world.") -} diff --git a/tests/samples/simple_project_with_internal/foo/bar1.go b/tests/samples/simple_project_with_internal/foo/bar1.go deleted file mode 100644 index ab05dd8..0000000 --- a/tests/samples/simple_project_with_internal/foo/bar1.go +++ /dev/null @@ -1,12 +0,0 @@ -package foo - -import ( - "example.com/simple-project/foo/internal" - "example.com/simple-project/foo/internal/qiniu" -) - -// Bar1 is a sample service -func Bar1() { - internal.Xiaohong() - qiniu.BB() -} diff --git a/tests/samples/simple_project_with_internal/foo/bar2.go b/tests/samples/simple_project_with_internal/foo/bar2.go deleted file mode 100644 index 060e874..0000000 --- a/tests/samples/simple_project_with_internal/foo/bar2.go +++ /dev/null @@ -1,12 +0,0 @@ -package foo - -import ( - "example.com/simple-project/foo/internal" - "example.com/simple-project/foo/internal/qiniu" -) - -// Bar2 is a sample service -func Bar2() { - internal.Xiaohong() - qiniu.BB() -} diff --git a/tests/samples/simple_project_with_internal/foo/internal/qiniu/xiaoda.go b/tests/samples/simple_project_with_internal/foo/internal/qiniu/xiaoda.go deleted file mode 100644 index 2d11189..0000000 --- a/tests/samples/simple_project_with_internal/foo/internal/qiniu/xiaoda.go +++ /dev/null @@ -1,6 +0,0 @@ -package qiniu - -// BB is a internal function -func BB() { - -} diff --git a/tests/samples/simple_project_with_internal/foo/internal/xiaoming.go b/tests/samples/simple_project_with_internal/foo/internal/xiaoming.go deleted file mode 100644 index 0f225c4..0000000 --- a/tests/samples/simple_project_with_internal/foo/internal/xiaoming.go +++ /dev/null @@ -1,6 +0,0 @@ -package internal - -// Xiaohong is a internal function -func Xiaohong() { - -} diff --git a/tests/samples/simple_project_with_internal/go.mod b/tests/samples/simple_project_with_internal/go.mod deleted file mode 100644 index 610643a..0000000 --- a/tests/samples/simple_project_with_internal/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module example.com/simple-project - -go 1.11 diff --git a/tests/samples/simple_project_with_internal/internal/foo.go b/tests/samples/simple_project_with_internal/internal/foo.go deleted file mode 100644 index a9090e2..0000000 --- a/tests/samples/simple_project_with_internal/internal/foo.go +++ /dev/null @@ -1,8 +0,0 @@ -package internal - -import "fmt" - -// Hello is a internal function -func Hello() { - fmt.Println("hello, world.") -} diff --git a/tests/samples/simple_project_with_internal/main.go b/tests/samples/simple_project_with_internal/main.go deleted file mode 100644 index ba23ed8..0000000 --- a/tests/samples/simple_project_with_internal/main.go +++ /dev/null @@ -1,12 +0,0 @@ -package main - -import ( - "example.com/simple-project/foo" - "example.com/simple-project/internal" -) - -func main() { - foo.Bar1() - foo.Bar2() - internal.Hello() -} diff --git a/tests/server.bats b/tests/server.bats deleted file mode 100755 index ed9719e..0000000 --- a/tests/server.bats +++ /dev/null @@ -1,67 +0,0 @@ -#!/usr/bin/env bats -# Copyright 2020 Qiniu Cloud (七牛云) -# -# 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. - -load util.sh - -setup_file() { - # run centered server - goc server 3>&- & - GOC_PID=$! - sleep 2 - goc init - # run covered goc - gocc server --port=:60001 --local-persistence="persistence/servicesAll.txt" --debug 3>&- & - GOCC_PID=$! - sleep 2 - info "goc gocc server started" -} - -teardown_file() { - # collect from center - goc profile --debug -o filtered-server.cov - kill -9 $GOC_PID - kill -9 $GOCC_PID -} - -@test "test basic goc server" { - # connect to covered goc - run goc clear --center=http://127.0.0.1:60001 - [ "$status" -eq 0 ] - # connect to covered goc - run goc profile --center=http://127.0.0.1:60001 - # no profiles - [ "$status" -eq 1 ] - [[ "$output" == *"no profiles"* ]] -} - -@test "register a covered service" { - WORKDIR=$PWD - cd $WORKDIR/samples/run_for_several_seconds - - run goc build --debug --center=http://127.0.0.1:60001 - [ "$status" -eq 0 ] - ./simple-project 3>&- & - sleep 1 - # connect to covered goc - run goc profile --center=http://127.0.0.1:60001 - [ "$status" -eq 0 ] - - # verify the persistence file exist - [ -f "$WORKDIR/persistence/servicesAll.txt" ] - # remove goc persistence file - run goc init --center=http://127.0.0.1:60001 - [ "$status" -eq 0 ] - [ ! -f "$WORKDIR/persistence/servicesAll.txt" ] -} \ No newline at end of file diff --git a/tests/util.sh b/tests/util.sh deleted file mode 100644 index 950c3b5..0000000 --- a/tests/util.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2020 Qiniu Cloud (七牛云) -# -# 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. - -info() { - echo -e "[$(date +'%Y-%m-%dT%H:%M:%S.%N%z')] INFO: $@" >&3 -} - -wait_profile() { - local n=0 - local timeout=10 - until [[ ${n} -ge ${timeout} ]] - do - LS=`ls` - info $1, $LS - if [[ -f ci-sync.bak ]]; then - break - fi - n=$[${n}+1] - sleep 1 - done - # collect from center - goc profile -o filtered-$1.cov - info "done $1 collect" -} - -wait_profile_backend() { - rm ci-sync.bak || true - wait_profile $1 -} \ No newline at end of file diff --git a/tests/version.bats b/tests/version.bats deleted file mode 100755 index a4adfe2..0000000 --- a/tests/version.bats +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env bats -# Copyright 2020 Qiniu Cloud (七牛云) -# -# 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. - -load util.sh - -setup_file() { - # run centered server - goc server 3>&- & - GOC_PID=$! - sleep 2 - goc init - - info "goc server started" -} - -setup() { - goc init - rm ci-sync.bak || true -} - -teardown_file() { - kill -9 $GOC_PID -} - -@test "test basic goc version command" { - wait_profile_backend "version" & - profile_pid=$! - - run gocc version --debug --debugcisyncfile ci-sync.bak; - [ "$output" = "(devel)" ] - - wait $profile_pid -} \ No newline at end of file diff --git a/tools/vscode-ext/.gitignore b/tools/vscode-ext/.gitignore deleted file mode 100644 index 5fe00fe..0000000 --- a/tools/vscode-ext/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -out -node_modules -.vscode-test/ -*.vsix diff --git a/tools/vscode-ext/.vscode/extensions.json b/tools/vscode-ext/.vscode/extensions.json deleted file mode 100644 index 0a18b9c..0000000 --- a/tools/vscode-ext/.vscode/extensions.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - // See http://go.microsoft.com/fwlink/?LinkId=827846 - // for the documentation about the extensions.json format - "recommendations": [ - "ms-vscode.vscode-typescript-tslint-plugin" - ] -} \ No newline at end of file diff --git a/tools/vscode-ext/.vscode/launch.json b/tools/vscode-ext/.vscode/launch.json deleted file mode 100644 index b1fbaf5..0000000 --- a/tools/vscode-ext/.vscode/launch.json +++ /dev/null @@ -1,36 +0,0 @@ -// A launch configuration that compiles the extension and then opens it inside a new window -// Use IntelliSense to learn about possible attributes. -// Hover to view descriptions of existing attributes. -// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 -{ - "version": "0.2.0", - "configurations": [ - { - "name": "Run Extension", - "type": "extensionHost", - "request": "launch", - "runtimeExecutable": "${execPath}", - "args": [ - "--extensionDevelopmentPath=${workspaceFolder}" - ], - "outFiles": [ - "${workspaceFolder}/out/**/*.js" - ], - "preLaunchTask": "${defaultBuildTask}" - }, - { - "name": "Extension Tests", - "type": "extensionHost", - "request": "launch", - "runtimeExecutable": "${execPath}", - "args": [ - "--extensionDevelopmentPath=${workspaceFolder}", - "--extensionTestsPath=${workspaceFolder}/out/test/suite/index" - ], - "outFiles": [ - "${workspaceFolder}/out/test/**/*.js" - ], - "preLaunchTask": "${defaultBuildTask}" - } - ] -} diff --git a/tools/vscode-ext/.vscode/settings.json b/tools/vscode-ext/.vscode/settings.json deleted file mode 100644 index 30bf8c2..0000000 --- a/tools/vscode-ext/.vscode/settings.json +++ /dev/null @@ -1,11 +0,0 @@ -// Place your settings in this file to overwrite default and user settings. -{ - "files.exclude": { - "out": false // set this to true to hide the "out" folder with the compiled JS files - }, - "search.exclude": { - "out": true // set this to false to include "out" folder in search results - }, - // Turn off tsc task auto detection since we have the necessary tasks as npm scripts - "typescript.tsc.autoDetect": "off" -} \ No newline at end of file diff --git a/tools/vscode-ext/.vscode/tasks.json b/tools/vscode-ext/.vscode/tasks.json deleted file mode 100644 index 3b17e53..0000000 --- a/tools/vscode-ext/.vscode/tasks.json +++ /dev/null @@ -1,20 +0,0 @@ -// See https://go.microsoft.com/fwlink/?LinkId=733558 -// for the documentation about the tasks.json format -{ - "version": "2.0.0", - "tasks": [ - { - "type": "npm", - "script": "watch", - "problemMatcher": "$tsc-watch", - "isBackground": true, - "presentation": { - "reveal": "never" - }, - "group": { - "kind": "build", - "isDefault": true - } - } - ] -} diff --git a/tools/vscode-ext/.vscodeignore b/tools/vscode-ext/.vscodeignore deleted file mode 100644 index ed3f9d3..0000000 --- a/tools/vscode-ext/.vscodeignore +++ /dev/null @@ -1,10 +0,0 @@ -.vscode/** -.vscode-test/** -out/test/** -src/** -.gitignore -vsc-extension-quickstart.md -**/tsconfig.json -**/tslint.json -**/*.map -**/*.ts \ No newline at end of file diff --git a/tools/vscode-ext/CHANGELOG.md b/tools/vscode-ext/CHANGELOG.md deleted file mode 100644 index c1f6904..0000000 --- a/tools/vscode-ext/CHANGELOG.md +++ /dev/null @@ -1,9 +0,0 @@ -# Change Log - -All notable changes to the "goc" extension will be documented in this file. - -Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file. - -## 0.0.3 2020-09-02 - -- Initial release \ No newline at end of file diff --git a/tools/vscode-ext/README.md b/tools/vscode-ext/README.md deleted file mode 100644 index 2e84ecf..0000000 --- a/tools/vscode-ext/README.md +++ /dev/null @@ -1,46 +0,0 @@ -# Goc Coverage - -This extension provides rich support for the [goc](https://github.com/qiniu/goc) tool. - -## Overview - -* [Getting started](#getting-started) -* [Ask for help](#ask-for-help) - -## Getting started - -Welcome! The [goc](https://github.com/qiniu/goc) is a coverage tool for Golang projects. The most interesting part of [goc](https://github.com/qiniu/goc) is that it can generate coverage report while the service is running! You can test the service manually or automatically, whatever, you don't have to stop the tested service to get the coverage report anymore. - -This extension provides a frontend to show the covered lines in real time. - -![demo](https://github.com/qiniu/goc/raw/master/docs/images/goc-vscode.gif) - -### Basic requirements - -Before you started, make sure that you have: - -1. Go -2. [goc](https://github.com/qiniu/goc) -3. source code of the tested service - -### Set up your environment - -Follow the [goc example](https://github.com/qiniu/goc#examples) guide to build and start the tested service. After you finished this step, there should be a **goc server** running at default port `7777`. - -Use `vscode` to open the source code. Make sure the vscode's `workspace` is in the Golang project's root directory. If your project uses `go module`, just open vscode in the repo's directory. If your project uses `GOPATH`, you should setup right `GOPATH` before you open vscode. - -Open any Go source files, you should see a `Goc Coverage OFF` button in the bottom status bar, click on the button to enable rendering covered lines in real time. - -### Configuration - -#### goc server url - -If you deploy the goc server on another host with a customized port, you can set: - -``` -"goc.serverUrl": "http://192.168.1.3:51234" -``` - -## Ask for help - -If you're having issues with this extension, please reach out to us by [filing an issue](https://github.com/qiniu/goc/issues/new/choose) directly. \ No newline at end of file diff --git a/tools/vscode-ext/package-lock.json b/tools/vscode-ext/package-lock.json deleted file mode 100644 index 93a84c4..0000000 --- a/tools/vscode-ext/package-lock.json +++ /dev/null @@ -1,1140 +0,0 @@ -{ - "name": "goc", - "version": "0.0.5", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@babel/code-frame": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", - "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", - "dev": true, - "requires": { - "@babel/highlight": "^7.10.4" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", - "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", - "dev": true - }, - "@babel/highlight": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", - "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "@types/glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==", - "dev": true, - "requires": { - "@types/minimatch": "*", - "@types/node": "*" - } - }, - "@types/log4js": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/@types/log4js/-/log4js-2.3.5.tgz", - "integrity": "sha512-SwF8LkSHqHy9A8GQ67NAYJiGl8zzP4Qtx65Wa+IOxDGdMHxKeoQZjg7m2M1erIT6VK0DYHpu2aTbdLkdkuMHjw==", - "dev": true, - "requires": { - "log4js": "*" - } - }, - "@types/minimatch": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", - "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", - "dev": true - }, - "@types/mocha": { - "version": "5.2.7", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz", - "integrity": "sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ==", - "dev": true - }, - "@types/node": { - "version": "12.12.54", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.54.tgz", - "integrity": "sha512-ge4xZ3vSBornVYlDnk7yZ0gK6ChHf/CHB7Gl1I0Jhah8DDnEQqBzgohYG4FX4p81TNirSETOiSyn+y1r9/IR6w==", - "dev": true - }, - "@types/vscode": { - "version": "1.47.0", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.47.0.tgz", - "integrity": "sha512-nJA37ykkz9FYA0ZOQUSc3OZnhuzEW2vUhUEo4MiduUo82jGwwcLfyvmgd/Q7b0WrZAAceojGhZybg319L24bTA==", - "dev": true - }, - "agent-base": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", - "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", - "dev": true, - "requires": { - "es6-promisify": "^5.0.0" - } - }, - "ansi-colors": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", - "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", - "dev": true - }, - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "axios": { - "version": "0.21.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", - "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", - "requires": { - "follow-redirects": "^1.10.0" - } - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true - }, - "builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", - "dev": true - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", - "dev": true, - "requires": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "date-format": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/date-format/-/date-format-3.0.0.tgz", - "integrity": "sha512-eyTcpKOcamdhWJXj56DpQMo1ylSQpcGtGKXcU0Tb97+K56/CF5amAqqqNj0+KvA0iw2ynxtHWFsPDSClCxe48w==" - }, - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true - }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, - "requires": { - "object-keys": "^1.0.12" - } - }, - "diff": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", - "dev": true - }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true - }, - "es-abstract": { - "version": "1.17.6", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", - "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.0", - "is-regex": "^1.1.0", - "object-inspect": "^1.7.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "es6-promise": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", - "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", - "dev": true - }, - "es6-promisify": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", - "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", - "dev": true, - "requires": { - "es6-promise": "^4.0.3" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "flat": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz", - "integrity": "sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==", - "dev": true, - "requires": { - "is-buffer": "~2.0.3" - } - }, - "flatted": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", - "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==" - }, - "follow-redirects": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.1.tgz", - "integrity": "sha512-SSG5xmZh1mkPGyKzjZP8zLjltIfpW32Y5QpdNJyjcfGxK3qo3NDDkZOZSFiGn1A6SclQxY9GzEwAHQ3dmYRWpg==" - }, - "fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "requires": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true - }, - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "graceful-fs": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", - "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==" - }, - "growl": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", - "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", - "dev": true - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "has-symbols": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", - "dev": true - }, - "he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true - }, - "http-proxy-agent": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", - "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==", - "dev": true, - "requires": { - "agent-base": "4", - "debug": "3.1.0" - }, - "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "https-proxy-agent": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", - "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", - "dev": true, - "requires": { - "agent-base": "^4.3.0", - "debug": "^3.1.0" - } - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "is-buffer": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", - "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==", - "dev": true - }, - "is-callable": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz", - "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==", - "dev": true - }, - "is-date-object": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", - "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "is-regex": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", - "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", - "dev": true, - "requires": { - "has-symbols": "^1.0.1" - } - }, - "is-symbol": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", - "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", - "dev": true, - "requires": { - "has-symbols": "^1.0.1" - } - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", - "requires": { - "graceful-fs": "^4.1.6" - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "lodash": { - "version": "4.17.19", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", - "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", - "dev": true - }, - "log-symbols": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", - "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", - "dev": true, - "requires": { - "chalk": "^2.0.1" - } - }, - "log4js": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.3.0.tgz", - "integrity": "sha512-Mc8jNuSFImQUIateBFwdOQcmC6Q5maU0VVvdC2R6XMb66/VnT+7WS4D/0EeNMZu1YODmJe5NIn2XftCzEocUgw==", - "requires": { - "date-format": "^3.0.0", - "debug": "^4.1.1", - "flatted": "^2.0.1", - "rfdc": "^1.1.4", - "streamroller": "^2.2.4" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - }, - "mkdirp": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.4.tgz", - "integrity": "sha512-iG9AK/dJLtJ0XNgTuDbSyNS3zECqDlAhnQW4CsNxBG3LQJBbHmRX1egw39DmtOdCAqY+dKXV+sgPgilNWUKMVw==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - }, - "mocha": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-6.2.3.tgz", - "integrity": "sha512-0R/3FvjIGH3eEuG17ccFPk117XL2rWxatr81a57D+r/x2uTYZRbdZ4oVidEUMh2W2TJDa7MdAb12Lm2/qrKajg==", - "dev": true, - "requires": { - "ansi-colors": "3.2.3", - "browser-stdout": "1.3.1", - "debug": "3.2.6", - "diff": "3.5.0", - "escape-string-regexp": "1.0.5", - "find-up": "3.0.0", - "glob": "7.1.3", - "growl": "1.10.5", - "he": "1.2.0", - "js-yaml": "3.13.1", - "log-symbols": "2.2.0", - "minimatch": "3.0.4", - "mkdirp": "0.5.4", - "ms": "2.1.1", - "node-environment-flags": "1.0.5", - "object.assign": "4.1.0", - "strip-json-comments": "2.0.1", - "supports-color": "6.0.0", - "which": "1.3.1", - "wide-align": "1.1.3", - "yargs": "13.3.2", - "yargs-parser": "13.1.2", - "yargs-unparser": "1.6.0" - }, - "dependencies": { - "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - } - } - }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" - }, - "node-environment-flags": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.5.tgz", - "integrity": "sha512-VNYPRfGfmZLx0Ye20jWzHUjyTW/c+6Wq+iLhDzUI4XmhrDd9l/FozXV3F2xOaXjvp0co0+v1YSR3CMP6g+VvLQ==", - "dev": true, - "requires": { - "object.getownpropertydescriptors": "^2.0.3", - "semver": "^5.7.0" - } - }, - "object-inspect": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz", - "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==", - "dev": true - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true - }, - "object.assign": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", - "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", - "dev": true, - "requires": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "object-keys": "^1.0.11" - } - }, - "object.getownpropertydescriptors": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz", - "integrity": "sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", - "dev": true - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true - }, - "require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true - }, - "resolve": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", - "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", - "dev": true, - "requires": { - "path-parse": "^1.0.6" - } - }, - "rfdc": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.1.4.tgz", - "integrity": "sha512-5C9HXdzK8EAqN7JDif30jqsBzavB7wLpaubisuQIGHWf2gUXSpzy6ArX/+Da8RjFpagWsCn+pIgxTMAmKw9Zug==" - }, - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "streamroller": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-2.2.4.tgz", - "integrity": "sha512-OG79qm3AujAM9ImoqgWEY1xG4HX+Lw+yY6qZj9R1K2mhF5bEmQ849wvrb+4vt4jLMLzwXttJlQbOdPOQVRv7DQ==", - "requires": { - "date-format": "^2.1.0", - "debug": "^4.1.1", - "fs-extra": "^8.1.0" - }, - "dependencies": { - "date-format": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/date-format/-/date-format-2.1.0.tgz", - "integrity": "sha512-bYQuGLeFxhkxNOF3rcMtiZxvCBAquGzZm6oWA1oZ0g2THUzivaRhv8uOhdr19LmoobSOLoIAxeUK2RdbM8IFTA==" - }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - } - }, - "string.prototype.trimend": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", - "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - } - }, - "string.prototype.trimstart": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", - "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "dev": true - }, - "supports-color": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", - "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - }, - "tslib": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", - "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==", - "dev": true - }, - "tslint": { - "version": "5.20.1", - "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.20.1.tgz", - "integrity": "sha512-EcMxhzCFt8k+/UP5r8waCf/lzmeSyVlqxqMEDQE7rWYiQky8KpIBz1JAoYXfROHrPZ1XXd43q8yQnULOLiBRQg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "builtin-modules": "^1.1.1", - "chalk": "^2.3.0", - "commander": "^2.12.1", - "diff": "^4.0.1", - "glob": "^7.1.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.1", - "resolve": "^1.3.2", - "semver": "^5.3.0", - "tslib": "^1.8.0", - "tsutils": "^2.29.0" - }, - "dependencies": { - "diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true - } - } - }, - "tsutils": { - "version": "2.29.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", - "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", - "dev": true, - "requires": { - "tslib": "^1.8.1" - } - }, - "typescript": { - "version": "3.9.7", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.7.tgz", - "integrity": "sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==", - "dev": true - }, - "universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" - }, - "upath": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", - "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==" - }, - "vscode-test": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/vscode-test/-/vscode-test-1.4.0.tgz", - "integrity": "sha512-Jt7HNGvSE0+++Tvtq5wc4hiXLIr2OjDShz/gbAfM/mahQpy4rKBnmOK33D+MR67ATWviQhl+vpmU3p/qwSH/Pg==", - "dev": true, - "requires": { - "http-proxy-agent": "^2.1.0", - "https-proxy-agent": "^2.2.4", - "rimraf": "^2.6.3" - } - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", - "dev": true - }, - "wide-align": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", - "dev": true, - "requires": { - "string-width": "^1.0.2 || 2" - } - }, - "wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "y18n": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", - "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", - "dev": true - }, - "yargs": { - "version": "13.3.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", - "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", - "dev": true, - "requires": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.2" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "yargs-parser": { - "version": "13.1.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", - "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - }, - "yargs-unparser": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", - "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", - "dev": true, - "requires": { - "flat": "^4.1.0", - "lodash": "^4.17.15", - "yargs": "^13.3.0" - } - } - } -} diff --git a/tools/vscode-ext/package.json b/tools/vscode-ext/package.json deleted file mode 100644 index 1c1c965..0000000 --- a/tools/vscode-ext/package.json +++ /dev/null @@ -1,67 +0,0 @@ -{ - "name": "goc", - "displayName": "Goc Coverage", - "description": "Goc Coverage can display coverage vairation in real time. Goc is a comprehensive coverage testing system for The Go Programming Language, especially for some complex scenarios, like system testing code coverage collection and accurate testing.", - "version": "0.0.5", - "publisher": "lyyyuna", - "repository": { - "url": "https://github.com/qiniu/goc" - }, - "engines": { - "vscode": "^1.43.0" - }, - "categories": [ - "Other" - ], - "activationEvents": [ - "onLanguage:go" - ], - "main": "./out/extension.js", - "contributes": { - "commands": [ - { - "command": "extension.switch", - "title": "Enable/Disable coverage report" - } - ], - "configuration": { - "title": "Goc", - "properties": { - "goc.serverUrl": { - "type": "string", - "default": "http://127.0.0.1:7777", - "description": "Specify the goc server url." - }, - "goc.debug": { - "type": "boolean", - "default": false, - "description": "Turn on debug mode to log more details." - } - } - } - }, - "scripts": { - "vscode:prepublish": "npm run compile", - "compile": "tsc -p ./", - "watch": "tsc -watch -p ./", - "pretest": "npm run compile", - "test": "node ./out/test/runTest.js" - }, - "devDependencies": { - "@types/glob": "^7.1.1", - "@types/log4js": "^2.3.5", - "@types/mocha": "^5.2.7", - "@types/node": "^12.11.7", - "@types/vscode": "^1.43.0", - "glob": "^7.1.5", - "mocha": "^6.2.2", - "tslint": "^5.20.0", - "typescript": "^3.6.4", - "vscode-test": "^1.2.2" - }, - "dependencies": { - "axios": "^0.21.1", - "log4js": "^6.3.0", - "upath": "^1.2.0" - } -} diff --git a/tools/vscode-ext/src/extension.ts b/tools/vscode-ext/src/extension.ts deleted file mode 100644 index 5304cd6..0000000 --- a/tools/vscode-ext/src/extension.ts +++ /dev/null @@ -1,38 +0,0 @@ -// The module 'vscode' contains the VS Code extensibility API -// Import the module and reference it with the alias vscode in your code below -import * as vscode from 'vscode'; -import { GocServer } from './gocserver'; - -// this method is called when your extension is activated -// your extension is activated the very first time the command is executed -export function activate(context: vscode.ExtensionContext) { - - let gocStatusBarItem: vscode.StatusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 0); - gocStatusBarItem.text = 'Goc Coverage OFF'; - gocStatusBarItem.command = 'extension.switch'; - gocStatusBarItem.show(); - - let gocserver = new GocServer(); - - let disposable2 = vscode.commands.registerCommand('extension.switch', async () => { - if (gocStatusBarItem.text == 'Goc Coverage OFF') { - let err = gocserver.checkGoEnv() - // check if pc meets extension's requirement - if (err) { - vscode.window.showErrorMessage('Cannot get Golang version, please check your go environment.') - return - } - gocStatusBarItem.text = 'Goc Coverage ON'; - // get current project package structure - let packages = gocserver.getGoList(); - await gocserver.startQueryLoop(packages); - } else { - gocStatusBarItem.text = 'Goc Coverage OFF'; - gocserver.stopQueryLoop(); - } - }) - - context.subscriptions.push(disposable2); -} - -export function deactivate() {} diff --git a/tools/vscode-ext/src/gocserver.ts b/tools/vscode-ext/src/gocserver.ts deleted file mode 100644 index 19fa583..0000000 --- a/tools/vscode-ext/src/gocserver.ts +++ /dev/null @@ -1,212 +0,0 @@ -import axios from 'axios'; -axios.defaults.timeout = 3000; -import * as vscode from 'vscode'; -import { spawnSync } from 'child_process'; -import * as path from 'path'; -import { promisify } from 'util'; -import * as log4js from 'log4js'; -import * as upath from 'upath'; -const sleep = promisify(setTimeout); - -export class GocServer { - private _serverUrl: string = ''; - private _debug: Boolean = false; - private _logger: log4js.Logger = log4js.getLogger(); - private timer = true; - private highlightDecorationType = vscode.window.createTextEditorDecorationType({ - backgroundColor: 'green', - border: '2px solid white', - color: 'white' - });; - private lastProfile = ''; - private lastFileNeedsRender = ''; - - construct() { } - - async startQueryLoop(packages: any[]) { - this.timer = true; - while ( true === this.timer ) { - await sleep(2000); - - if ( true !== this.timer ) { - this.clearHightlight(); - return; - } - - this.getConfigurations(); - this.setDebugLogger(); - let profile = await this.getLatestProfile(); - this.renderFile(packages, profile); - } - } - - stopQueryLoop() { - this.timer = false; - this.lastProfile = ''; - this.lastFileNeedsRender = ''; - - this.clearHightlight() - } - - clearHightlight() { - vscode.window.visibleTextEditors.forEach(visibleEditor => { - visibleEditor.setDecorations(this.highlightDecorationType, []); - }); - } - - getConfigurations() { - this._serverUrl = vscode.workspace.getConfiguration().get('goc.serverUrl') || ''; - this._debug = vscode.workspace.getConfiguration().get('goc.debug') || false; - } - - setDebugLogger() { - if (this._debug == false) { - this._logger.level = "info"; - } else { - this._logger.level = "debug"; - } - - this._logger.info('goc server url: ', this._serverUrl); - } - - async getLatestProfile(): Promise { - let profileApi = `${this._serverUrl}/v1/cover/profile?force=true`; - - try { - let res = await axios.get(profileApi, ); - let body: string = res.data.toString(); - this._logger.debug(body); - return body; - } catch(err) { - this._logger.error(err.message); - } - - return ""; - } - - checkGoEnv() : Boolean { - let output = spawnSync('go', ['version']); - if (output.status != 0 || output.status == null) { - this._logger.error(output.stderr.toString()); - return true; - } - this._logger.debug('go version: ', output.stdout.toString()); - return false; - } - - getGoList(): Array { - let cwd = ""; - let workspaces = vscode.workspace.workspaceFolders || []; - if (workspaces.length == 0) { - this._logger.error("no workspace found"); - return []; - } else { - cwd = workspaces[0].uri.fsPath; - } - this._logger.debug('current project root directory: ', cwd); - let opts = { - 'cwd': cwd - }; - let output = spawnSync('go', ['list', '-json', './...'], opts); - if (output.status != 0 || output.status == null) { - this._logger.error(output.stderr.toString()); - return []; - } - let packages = JSON.parse('[' + output.stdout.toString().replace(/}\n{/g, '},\n{') + ']'); - return packages; - } - - renderFile(packages: Array, profile: string) { - let activeTextEditor = vscode.window.activeTextEditor; - let fileNeedsRender = activeTextEditor?.document.fileName || '---'; - - this._logger.debug('current active source code file: ', fileNeedsRender); - // check if needs to rerender - if (profile == this.lastProfile && fileNeedsRender == this.lastFileNeedsRender) { - return; - } - this.lastProfile = profile; - this.lastFileNeedsRender = fileNeedsRender; - - this._logger.debug('go list packages length: ', packages.length); - - for (let i=0; i { - vscode.window.showInformationMessage('Start all tests.'); - - test('Sample test', () => { - assert.equal(-1, [1, 2, 3].indexOf(5)); - assert.equal(-1, [1, 2, 3].indexOf(0)); - }); -}); diff --git a/tools/vscode-ext/src/test/suite/index.ts b/tools/vscode-ext/src/test/suite/index.ts deleted file mode 100644 index 2cd152c..0000000 --- a/tools/vscode-ext/src/test/suite/index.ts +++ /dev/null @@ -1,37 +0,0 @@ -import * as path from 'path'; -import * as Mocha from 'mocha'; -import * as glob from 'glob'; - -export function run(): Promise { - // Create the mocha test - const mocha = new Mocha({ - ui: 'tdd', - }); - mocha.useColors(true); - - const testsRoot = path.resolve(__dirname, '..'); - - return new Promise((c, e) => { - glob('**/**.test.js', { cwd: testsRoot }, (err, files) => { - if (err) { - return e(err); - } - - // Add files to the test suite - files.forEach(f => mocha.addFile(path.resolve(testsRoot, f))); - - try { - // Run the mocha test - mocha.run(failures => { - if (failures > 0) { - e(new Error(`${failures} tests failed.`)); - } else { - c(); - } - }); - } catch (err) { - e(err); - } - }); - }); -} diff --git a/tools/vscode-ext/tsconfig.json b/tools/vscode-ext/tsconfig.json deleted file mode 100644 index b65c745..0000000 --- a/tools/vscode-ext/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "compilerOptions": { - "module": "commonjs", - "target": "es6", - "outDir": "out", - "lib": [ - "es6" - ], - "sourceMap": true, - "rootDir": "src", - "strict": true /* enable all strict type-checking options */ - /* Additional Checks */ - // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ - // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ - // "noUnusedParameters": true, /* Report errors on unused parameters. */ - }, - "exclude": [ - "node_modules", - ".vscode-test" - ] -} diff --git a/tools/vscode-ext/tslint.json b/tools/vscode-ext/tslint.json deleted file mode 100644 index c81ff28..0000000 --- a/tools/vscode-ext/tslint.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "rules": { - "no-string-throw": true, - "no-unused-expression": true, - "no-duplicate-variable": true, - "curly": true, - "class-name": true, - "semicolon": [ - true, - "always" - ], - "triple-equals": true - }, - "defaultSeverity": "warning" -} diff --git a/tools/vscode-ext/vsc-extension-quickstart.md b/tools/vscode-ext/vsc-extension-quickstart.md deleted file mode 100644 index b510bff..0000000 --- a/tools/vscode-ext/vsc-extension-quickstart.md +++ /dev/null @@ -1,42 +0,0 @@ -# Welcome to your VS Code Extension - -## What's in the folder - -* This folder contains all of the files necessary for your extension. -* `package.json` - this is the manifest file in which you declare your extension and command. - * The sample plugin registers a command and defines its title and command name. With this information VS Code can show the command in the command palette. It doesn’t yet need to load the plugin. -* `src/extension.ts` - this is the main file where you will provide the implementation of your command. - * The file exports one function, `activate`, which is called the very first time your extension is activated (in this case by executing the command). Inside the `activate` function we call `registerCommand`. - * We pass the function containing the implementation of the command as the second parameter to `registerCommand`. - -## Get up and running straight away - -* Press `F5` to open a new window with your extension loaded. -* Run your command from the command palette by pressing (`Ctrl+Shift+P` or `Cmd+Shift+P` on Mac) and typing `Hello World`. -* Set breakpoints in your code inside `src/extension.ts` to debug your extension. -* Find output from your extension in the debug console. - -## Make changes - -* You can relaunch the extension from the debug toolbar after changing code in `src/extension.ts`. -* You can also reload (`Ctrl+R` or `Cmd+R` on Mac) the VS Code window with your extension to load your changes. - - -## Explore the API - -* You can open the full set of our API when you open the file `node_modules/@types/vscode/index.d.ts`. - -## Run tests - -* Open the debug viewlet (`Ctrl+Shift+D` or `Cmd+Shift+D` on Mac) and from the launch configuration dropdown pick `Extension Tests`. -* Press `F5` to run the tests in a new window with your extension loaded. -* See the output of the test result in the debug console. -* Make changes to `src/test/suite/extension.test.ts` or create new test files inside the `test/suite` folder. - * The provided test runner will only consider files matching the name pattern `**.test.ts`. - * You can create folders inside the `test` folder to structure your tests any way you want. - -## Go further - - * Reduce the extension size and improve the startup time by [bundling your extension](https://code.visualstudio.com/api/working-with-extensions/bundling-extension). - * [Publish your extension](https://code.visualstudio.com/api/working-with-extensions/publishing-extension) on the VSCode extension marketplace. - * Automate builds by setting up [Continuous Integration](https://code.visualstudio.com/api/working-with-extensions/continuous-integration).