diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..1fd59f1 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,2 @@ +# These owners will be the default owners for everything in the repo. +* @go-vela/admins \ No newline at end of file diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..1571ff9 --- /dev/null +++ b/.github/CODE_OF_CONDUCT.md @@ -0,0 +1,74 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to make participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +nationality, personal appearance, race, religion, or sexual identity and +orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +- Using welcoming and inclusive language +- Being respectful of differing viewpoints and experiences +- Gracefully accepting constructive criticism +- Focusing on what is best for the community +- Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +- The use of sexualized language or imagery and unwelcome sexual attention or + advances +- Trolling, insulting/derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or electronic + address, without explicit permission +- Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at +[opensource@target.com](mailto:opensource@target.com). All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 0000000..081389f --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,90 @@ +# Contributing + +## Getting Started + +We'd love to accept your contributions to this project! If you are a first time contributor, please review our [Contributing Guidelines](https://go-vela.github.io/docs/community/contributing_guidelines/) before proceeding. + +### Prerequisites + +* [Review the commit guide we follow](https://chris.beams.io/posts/git-commit/#seven-rules) - ensure your commits follow our standards +* Review our [style guide](https://go-vela.github.io/docs/community/contributing_guidelines/#style-guide) to ensure your code is clean and consistent. +* [Docker](https://docs.docker.com/install/) - building block for local development +* [Docker Compose](https://docs.docker.com/compose/install/) - start up local development +* [Make](https://www.gnu.org/software/make/) - start up local development + +### Setup + +- [Fork](/fork) this repository + +- Clone this repository to your workstation: + +```bash +# Clone the project +git clone git@github.com:go-vela/vela-email.git $HOME/go-vela/vela-github-release +``` + +- Navigate to the repository code: + +```bash +# Change into the project directory +cd $HOME/go-vela/vela-github-release +``` + +- Point the original code at your fork: + +```bash +# Add a remote branch pointing to your fork +git remote add fork https://github.com/your_fork/vela-github-release +``` + +### Development + +**Please review the [local development documentation](../DOCS.md) for more information.** + +- Navigate to the repository code: + +```bash +# change into the cloned project directory +cd $HOME/go-vela/vela-github-release +``` + +- Write your code and tests to implement the changes you desire. + +- Build the repository code: + +```bash +# execute the `build` target with `make` +make build +``` + +- Run the repository code (ensures your changes perform as you desire): + +```bash +# execute the `run` target with `make` +make run +``` + +- Test the repository code (ensures your changes don't break existing functionality): + +```bash +# execute the `test` target with `make` +make test +``` + +- Clean the repository code (ensures your code meets the project standards): + +```bash +# execute the `clean` target with `make` +make clean +``` + +- Push to your fork: + +```bash +# push your code up to your fork +git push fork main +``` + +* Make sure to follow our [PR process](https://go-vela.github.io/docs/community/contributing_guidelines/#development-workflow) when opening a pull request + +Thank you for your contribution! \ No newline at end of file diff --git a/.github/README.md b/.github/README.md new file mode 100644 index 0000000..d8f131f --- /dev/null +++ b/.github/README.md @@ -0,0 +1,34 @@ +# vela-github-release + +[![license](https://img.shields.io/crates/l/gl.svg)](../LICENSE) +[![GoDoc](https://godoc.org/github.com/go-vela/vela-github-release?status.svg)](https://godoc.org/github.com/go-vela/vela-github-release) +[![Go Report Card](https://goreportcard.com/badge/go-vela/vela-github-release)](https://goreportcard.com/report/go-vela/vela-github-release) +[![codecov](https://codecov.io/gh/go-vela/vela-github-release/branch/main/graph/badge.svg)](https://codecov.io/gh/go-vela/vela-github-release) + +Vela plugin designed to manage GitHub releases [GitHub CLI](https://cli.github.com/manual/) in a Vela pipeline. + +Internally, the plugin is a wrapper around the [Github Release CLI](https://cli.github.com/manual/gh_release). + +## Documentation + +For installation and usage, please [visit our docs](https://go-vela.github.io/docs). + +## Contributing + +We are always welcome to new pull requests! + +Please see our [contributing](CONTRIBUTING.md) docs for further instructions. + +## Support + +We are always here to help! + +Please see our [support](SUPPORT.md) documentation for further instructions. + +## Copyright and License + +``` +Copyright (c) 2022 Target Brands, Inc. +``` + +[Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) diff --git a/.github/SUPPORT.md b/.github/SUPPORT.md new file mode 100644 index 0000000..75826d5 --- /dev/null +++ b/.github/SUPPORT.md @@ -0,0 +1,15 @@ +# Support + +Welcome to Vela! To get help with a specific aspect of Vela, we've provided the below information. + +## Bugs or Feature Requests + +We use GitHub for tracking bugs and feature requests. + +Please see our [contributing](CONTRIBUTING.md) documentation for further instructions. + +## Questions + +We use Slack for supporting questions not already covered in the above documents. + +Please join the [#vela](https://gophers.slack.com/app_redirect?channel=CNRRKE8KY) channel. diff --git a/.github/renovate.json b/.github/renovate.json new file mode 100644 index 0000000..df3d2ef --- /dev/null +++ b/.github/renovate.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": ["local>go-vela/renovate-config"] +} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..bfceca3 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,21 @@ +# name of the action +name: build + +# trigger on pull_request or push events +on: + pull_request: + push: + +# pipeline to execute +jobs: + build: + runs-on: ubuntu-latest + container: + image: golang:1.17 + steps: + - name: clone + uses: actions/checkout@v2 + + - name: build + run: | + make build diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 0000000..e7f488d --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,67 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL" + +on: + push: + branches: [ main ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ main ] + schedule: + - cron: '32 7 * * 6' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + language: [ 'go' ] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] + # Learn more: + # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v1 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + # queries: ./path/to/local/query, your-org/your-repo/queries@main + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v1 + + # ℹī¸ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl + + # ✏ī¸ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language + + #- run: | + # make bootstrap + # make release + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 diff --git a/.github/workflows/prerelease.yml b/.github/workflows/prerelease.yml new file mode 100644 index 0000000..0b56773 --- /dev/null +++ b/.github/workflows/prerelease.yml @@ -0,0 +1,42 @@ +# name of the action +name: prerelease + +# trigger on push events with `v*` in tag +on: + push: + tags: + - "v*" + +# pipeline to execute +jobs: + prerelease: + runs-on: ubuntu-latest + container: + image: golang:1.17 + steps: + - name: clone + uses: actions/checkout@v2 + with: + # ensures we fetch tag history for the repository + fetch-depth: 0 + + - name: setup + run: | + # setup git tag in Actions environment + echo "GITHUB_TAG=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV + + - name: build + env: + GOOS: linux + CGO_ENABLED: "0" + run: | + make build-static-ci + + - name: publish + uses: elgohr/Publish-Docker-Github-Action@master + with: + name: target/vela-github-release + cache: true + tag_names: true + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..e298275 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,35 @@ +# name of the action +name: publish + +# trigger on push events with branch main +on: + push: + branches: [ main ] + +# pipeline to execute +jobs: + publish: + runs-on: ubuntu-latest + container: + image: golang:1.17 + steps: + - name: clone + uses: actions/checkout@v2 + with: + # ensures we fetch tag history for the repository + fetch-depth: 0 + + - name: build + env: + GOOS: linux + CGO_ENABLED: '0' + run: | + make build-static-ci + + - name: publish + uses: elgohr/Publish-Docker-Github-Action@master + with: + name: target/vela-github-release + cache: true + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} diff --git a/.github/workflows/reviewdog.yml b/.github/workflows/reviewdog.yml new file mode 100644 index 0000000..94d21fc --- /dev/null +++ b/.github/workflows/reviewdog.yml @@ -0,0 +1,41 @@ +# name of the action +name: reviewdog + +# trigger on pull_request events +on: + pull_request: + +# pipeline to execute +jobs: + diff-review: + runs-on: ubuntu-latest + container: + image: golang:1.17 + steps: + - name: clone + uses: actions/checkout@v2 + + - name: golangci-lint + uses: reviewdog/action-golangci-lint@v2 + with: + github_token: ${{ secrets.github_token }} + golangci_lint_flags: "--config=.golangci.yml" + fail_on_error: true + filter_mode: diff_context + reporter: github-pr-review + + full-review: + runs-on: ubuntu-latest + container: + image: golang:1.17 + steps: + - name: clone + uses: actions/checkout@v2 + + - name: golangci-lint + uses: reviewdog/action-golangci-lint@v2 + with: + github_token: ${{ secrets.github_token }} + golangci_lint_flags: "--config=.golangci.yml" + fail_on_error: false + filter_mode: nofilter diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..b2f98b5 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,27 @@ +# name of the action +name: test + +# trigger on pull_request or push events +on: + pull_request: + push: + +# pipeline to execute +jobs: + test: + runs-on: ubuntu-latest + container: + image: golang:1.17 + steps: + - name: clone + uses: actions/checkout@v2 + + - name: test + run: | + go test -race -covermode=atomic -coverprofile=coverage.out ./... + + - name: coverage + uses: codecov/codecov-action@v2 + with: + token: ${{ secrets.CODECOV_TOKEN }} + file: coverage.out diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml new file mode 100644 index 0000000..7ace2e2 --- /dev/null +++ b/.github/workflows/validate.yml @@ -0,0 +1,28 @@ +# name of the action +name: validate + +# trigger on pull_request or push events +on: + pull_request: + push: + +# pipeline to execute +jobs: + validate: + runs-on: ubuntu-latest + container: + image: golang:1.17 + steps: + - name: clone + uses: actions/checkout@v2 + + - name: validate + run: | + # Check that go mod tidy produces a zero diff; clean up any changes afterwards. + go mod tidy && git diff --exit-code; code=$?; git checkout -- .; (exit $code) + # Check that go vet ./... produces a zero diff; clean up any changes afterwards. + go vet ./... && git diff --exit-code; code=$?; git checkout -- .; (exit $code) + # Check that go fmt ./... produces a zero diff; clean up any changes afterwards. + go fmt ./... && git diff --exit-code; code=$?; git checkout -- .; (exit $code) + # Check that go fix ./... produces a zero diff; clean up any changes afterwards. + go fix ./... && git diff --exit-code; code=$?; git checkout -- .; (exit $code) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..03aa701 --- /dev/null +++ b/.gitignore @@ -0,0 +1,18 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ + +# Binary release folder +release/ diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..8dfcde3 --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,159 @@ +# This is a manually created golangci.com yaml configuration with +# some defaults explicitly provided. There is a large number of +# linters we've enabled that are usually disabled by default. +# +# https://golangci-lint.run/usage/configuration/#config-file + +# This section provides the configuration for how golangci +# outputs it results from the linters it executes. +output: + # colored-line-number|line-number|json|tab|checkstyle|code-climate, default is "colored-line-number" + format: colored-line-number + + # print lines of code with issue, default is true + print-issued-lines: true + + # print linter name in the end of issue text, default is true + print-linter-name: true + + # make issues output unique by line, default is true + uniq-by-line: true + +# This section provides the configuration for each linter +# we've instructed golangci to execute. +linters-settings: + # https://github.com/mibk/dupl + dupl: + threshold: 100 + + # https://github.com/ultraware/funlen + funlen: + # accounting for comments + lines: 160 + statements: 70 + + # https://github.com/denis-tingaikin/go-header + goheader: + template: |- + Copyright (c) {{ YEAR }} Target Brands, Inc. All rights reserved. + + Use of this source code is governed by the LICENSE file in this repository. + + # https://github.com/client9/misspell + misspell: + locale: US + + # https://github.com/golangci/golangci-lint/blob/master/pkg/golinters/nolintlint + nolintlint: + allow-leading-space: true # allow non-"machine-readable" format (ie. with leading space) + allow-unused: false # allow nolint directives that don't address a linting issue + require-explanation: true # require an explanation for nolint directives + require-specific: true # require nolint directives to be specific about which linter is being skipped + +# This section provides the configuration for which linters +# golangci will execute. Several of them were disabled by +# default but we've opted to enable them. +linters: + # disable all linters as new linters might be added to golangci + disable-all: true + + # enable a specific set of linters to run + enable: + - bidichk # checks for dangerous unicode character sequences + - bodyclose # checks whether HTTP response body is closed successfully + - contextcheck # check the function whether use a non-inherited context + - deadcode # finds unused code + - dupl # code clone detection + - errcheck # checks for unchecked errors + - errorlint # find misuses of errors + - exportloopref # check for exported loop vars + - funlen # detects long functions + - goconst # finds repeated strings that could be replaced by a constant + - gocyclo # computes and checks the cyclomatic complexity of functions + - godot # checks if comments end in a period + - gofmt # checks whether code was gofmt-ed + - goheader # checks is file header matches to pattern + - goimports # fixes imports and formats code in same style as gofmt + - gomoddirectives # manage the use of 'replace', 'retract', and 'excludes' directives in go.mod + - goprintffuncname # checks that printf-like functions are named with f at the end + - gosec # inspects code for security problems + - gosimple # linter that specializes in simplifying a code + - govet # reports suspicious constructs, ex. Printf calls whose arguments don't align with the format string + - ineffassign # detects when assignments to existing variables aren't used + - makezero # finds slice declarations with non-zero initial length + - misspell # finds commonly misspelled English words in comments + - nakedret # finds naked returns in functions greater than a specified function length + - nilerr # finds the code that returns nil even if it checks that the error is not nil + - noctx # noctx finds sending http request without context.Context + - nolintlint # reports ill-formed or insufficient nolint directives + - revive # linter for go + - staticcheck # applies static analysis checks, go vet on steroids + - structcheck # finds unused struct fields + - stylecheck # replacement for golint + - tenv # analyzer that detects using os.Setenv instead of t.Setenv since Go1.17 + - typecheck # parses and type-checks go code, like the front-end of a go compiler + - unconvert # remove unnecessary type conversions + - unparam # reports unused function parameters + - unused # checks for unused constants, variables, functions and types + - varcheck # finds unused global variables and constants + - whitespace # detects leading and trailing whitespace + - wsl # forces code to use empty lines + + # static list of linters we know golangci can run but we've + # chosen to leave disabled for now + # - asciicheck - non-critical + # - cyclop - unused complexity metric + # - depguard - unused + # - dogsled - blanks allowed + # - durationcheck - unused + # - errname - unused + # - exhaustive - unused + # - exhaustivestruct - style preference + # - forbidigo - unused + # - forcetypeassert - unused + # - gci - use goimports + # - gochecknoinits - unused + # - gochecknoglobals - global variables allowed + # - gocognit - unused complexity metric + # - gocritic - style preference + # - godox - to be used in the future + # - goerr113 - to be used in the future + # - golint - archived, replaced with revive + # - gofumpt - use gofmt + # - gomnd - get too many false-positives + # - gomodguard - unused + # - ifshort - use both styles + # - ireturn - allow interfaces to be returned + # - importas - want flexibility with naming + # - lll - not too concerned about line length + # - interfacer - archived + # - nestif - non-critical + # - nilnil - style preference + # - nlreturn - style preference + # - maligned - archived, replaced with govet 'fieldalignment' + # - paralleltest - false-positives + # - prealloc - don't use + # - predeclared - unused + # - promlinter - style preference + # - rowserrcheck - unused + # - scopelint - deprecated - replaced with exportloopref + # - sqlclosecheck - unused + # - tagliatelle - use a mix of variable naming + # - testpackage - don't use this style of testing + # - thelper - false-positives + # - varnamelen - unused + # - wastedassign - duplicate functionality + # - wrapcheck - style preference + +# This section provides the configuration for how golangci +# will report the issues it finds. +issues: + # Excluding configuration per-path, per-linter, per-text and per-source + exclude-rules: + # prevent linters from running on *_test.go files + - path: _test\.go + linters: + - dupl + - funlen + - goconst + - gocyclo diff --git a/DOCS.md b/DOCS.md new file mode 100644 index 0000000..d1deddd --- /dev/null +++ b/DOCS.md @@ -0,0 +1,237 @@ +## Description + +This plugin enables the ability to manage GitHub releases [GitHub CLI](https://cli.github.com/manual/) in a Vela pipeline. + +Source Code: https://github.com/go-vela/vela-github-release + +Registry: https://hub.docker.com/r/target/vela-github-release + +## Usage + +> **NOTE:** +> +> Users should refrain from using **latest** as the tag for the Docker image. +> +> It is recommended to use a semantically versioned tag instead. + +Sample of creating a GitHub release: + +```yaml +steps: + - name: gh + image: target/vela-github-release:v0.1.0 + pull: always + parameters: + action: create + files: [ gh/common, gh/dev/deploy.yml ] + tag: v0.1.0 +``` + +Sample of deleting release files: + +```yaml +steps: + - name: gh + image: target/vela-github-release:v0.1.0 + pull: always + parameters: + action: delete + tag: v0.1.0 +``` + +Sample of downloading assets from a release in a project: + +```yaml +steps: + - name: gh + image: target/vela-github-release:v0.1.0 + pull: always + parameters: + action: download + tag: v0.1.0 +``` + +Sample of listing releases in a repository: + +```yaml +steps: + - name: gh + image: target/vela-github-release:v0.1.0 + pull: always + parameters: + action: list +``` + +Sample of uploading assets to a gh release: + +```yaml +steps: + - name: gh + image: target/vela-github-release:v0.1.0 + pull: always + parameters: + action: upload + files: [ changelog.md ] + tag: v0.1.0 +``` + +Sample of viewing information about a gh release: + +```yaml +steps: + - name: gh + image: target/vela-github-release:v0.1.0 + pull: always + parameters: + action: view + tag: v0.1.0 +``` + +## Secrets + +> **NOTE:** Users should refrain from configuring sensitive information in your pipeline in plain text. + +### Internal + +The plugin accepts the following `parameters` for authentication: + +| Parameter | Environment Variable Configuration | +| ----------| -------------------------------------------------------------- | +| `token` | `PARAMETER_TOKEN`, `CONFIG_TOKEN`, `GH_TOKEN`, `GITHUB_TOKEN` | + +Users can use [Vela internal secrets](https://go-vela.github.io/docs/concepts/pipeline/secrets/) to substitute these sensitive values at runtime: + +```diff +steps: + - name: gh + image: target/vela-github-release:latest + pull: always ++ secrets: [github_token] + parameters: + action: create + files: [ gh/common, gh/dev/deploy.yml ] +``` + +> This example will add the secrets to the `gh` step as environment variables: +> +> * `GITHUB_TOKEN=` + +### External + +The plugin accepts the following files for authentication: + +| Parameter | Volume Configuration | +| ---------- | ------------------------------------------------------------------------------------------- | +| `token` | `/vela/parameters/github-release/config/token`, `/vela/secrets/github-release/config/token` | + +Users can use [Vela external secrets](https://go-vela.github.io/docs/concepts/pipeline/secrets/origin/) to substitute these sensitive values at runtime: + +```diff +steps: + - name: gh + image: target/vela-github-release:v0.1.0 + pull: always ++ secrets: [github_token] + parameters: + config: +- github_token: somepersonalaccesstoken +``` + +> This example will read the secret value in the volume stored at `/vela/secrets/` + +## Parameters + +> **NOTE:** +> +> The plugin supports reading all parameters via environment variables or files. +> +> VELA environments can be found at [VELA Environments](https://go-vela.github.io/docs/reference/environment/) +> +> Any values set from a file take precedence over values set from the environment. + +The following parameters are used to configure the image: + +| Name | Description | Required | Default | Environment Variables | +| ----------- | ------------------------------------------------ | -------- | ------------ | ----------------------------------------------------------------------- | +| `action` | action to perform against gh | `true` | `N/A` | `PARAMETER_ACTION`
`CONFIG_ACTION` | +| `hostname` | hostname to set for GitHub instance | `true` | `github.com` | `PARAMETER_HOSTNAME`
`GH_HOST`
`GITHUB_HOST` | +| `token` | token to set to authenticate to GitHub instance | `true` | `N/A` | `PARAMETER_TOKEN`
`CONFIG_TOKEN`
`GH_TOKEN`
`GITHUB_TOKEN` | +| `log_level` | set the log level for the plugin | `true` | `info` | `PARAMETER_LOG_LEVEL`
`VELA_LOG_LEVEL`
`GITHUB_RELEASE_LOG_LEVEL` | +| `version` | version of the `gh` CLI to install | `false` | `v1.4.0` | `PARAMETER_VERSION`
`VELA_GH_VERSION`
`GH_VERSION` | + +#### Create + +The following parameters are used to configure the `create` action: + +| Name | Description | Required | Default | Environment Variables | +| ------------ | ---------------------------------------------------- | -------- | ------- | ---------------------------------------------- | +| `draft` | save the release as a draft instead of publishing it | `false` | `false` | `PARAMETER_DRAFT`
`CREATE_DRAFT` | +| `notes` | create release notes | `false` | `N/A` | `PARAMETER_NOTES`
`CREATE_NOTES` | +| `notes_file` | read release notes from file | `false` | `N/A` | `PARAMETER_NOTES_FILE`
`CREATE_NOTES_FILE` | +| `files` | file(s) name used to create | `false` | `N/A` | `PARAMETER_FILES`
`GITHUB_RELEASE_FILES` | +| `prerelease` | mark the release as a prerelease | `false` | `false` | `PARAMETER_PRERELEASE`
`CREATE_PRERELEASE` | +| `tag` | github tag name to create | `true` | `N/A` | `PARAMETER_TAG`
`GITHUB_RELEASE_TAG` | +| `target` | target branch or commit SHA | `true` | `main` | `PARAMETER_TARGET`
`CREATE_TARGET` | +| `title` | Release title | `false` | `N/A` | `PARAMETER_TITLE`
`CREATE_TITLE` | + +#### Delete + +The following parameters are used to configure the `delete` action: + +| Name | Description | Required | Default | Environment Variables | +| --------- | -------------------------------------- | -------- | ------- | ----------------------------------------- | +| `yes` | skip the delete confirmation prompt | `false` | `false` | `PARAMETER_YES`
`DELETE_YES` | +| `tag` | github tag name to delete | `true` | `N/A` | `PARAMETER_TAG`
`GITHUB_RELEASE_TAG` | + +#### Download + +The following parameters are used to configure the `download` action: + +| Name | Description | Required | Default | Environment Variables | +| ----------- | --------------------------------------------- | -------- | ------- | --------------------------------------------- | +| `directory` | the directory to download files | `true` | `"."` | `PARAMETER_DIR`
`DOWNLOAD_DIR` | +| `patterns` | download only assets that match glob patterns | `false` | `N/A` | `PARAMETER_PATTERNS`
`DOWNLOAD_PATTERNS` | +| `tag` | github tag name to download | `true` | `N/A` | `PARAMETER_TAG`
`GITHUB_RELEASE_TAG` | + +#### List + +The following parameters are used to configure the `list` action: + +| Name | Description | Required | Default | Environment Variables | +| ---------- | ------------------------------------------------ | -------- | ------- | --------------------------------------------- | +| `limit` | maximum number of items to fetch for list action | `true` | `30` | `PARAMETER_LIMIT`
`LIST_LIMIT` | + +#### Upload + +The following parameters are used to configure the `upload` action: + +| Name | Description | Required | Default | Environment Variables | +| --------- | ------------------------------------------- | -------- | ------- | --------------------------------------------- | +| `clobber` | overwrite existing assets of the same name | `false` | `false` | `PARAMETER_CLOBBER`
`UPLOAD_CLOBBER` | +| `files` | file(s) name used to upload | `true` | `N/A` | `PARAMETER_FILES`
`GITHUB_RELEASE_FILES` | +| `tag` | github tag name to upload | `true` | `N/A` | `PARAMETER_TAG`
`GITHUB_RELEASE_TAG` | + +#### View + +The following parameters are used to configure the `view` action: + +| Name | Description | Required | Default | Environment Variables | +| ------- | --------------------------------- | -------- | ------- | ---------------------------------------- | +| `tag` | github tag name to view | `true` | `N/A` | `PARAMETER_TAG`
`GITHUB_RELEASE_TAG` | +| `web` | open the release in the browser | `true` | `false` | `PARAMETER_WEB`
`VIEW_WEB` | + + +## Troubleshooting + +You can start troubleshooting this plugin by tuning the level of logs being displayed: + +```diff +steps: + - name: github-release + image: target/vela-github-release:v0.1.0 + pull: always + parameters: + action: create + files: [ gh/common, gh/dev/deploy.yml ] ++ log_level: trace +``` diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..e99b45d --- /dev/null +++ b/Dockerfile @@ -0,0 +1,42 @@ +# Copyright (c) 2022 Target Brands, Inc. All rights reserved. +# +# Use of this source code is governed by the LICENSE file in this repository. + +# set a global Docker argument for the default CLI version +# +# https://github.com/moby/moby/issues/37345 +ARG GH_VERSION=1.4.0 + +################################################################################### +## docker build --no-cache --target binary -t vela-github-release:binary . ## +################################################################################### + +FROM alpine:3.15 as binary + +ARG GH_VERSION + +ADD https://github.com/cli/cli/releases/download/v${GH_VERSION}/gh_${GH_VERSION}_linux_amd64.tar.gz /tmp/gh.tar.gz + +RUN tar -xzf /tmp/gh.tar.gz -C /bin + +RUN cp /bin/gh_${GH_VERSION}_linux_amd64/bin/gh /bin/gh + +RUN chmod 0700 /bin/gh + +################################################################## +## docker build --no-cache -t vela-github-release:local . ## +################################################################## + +FROM alpine:3.15 + +ARG GH_VERSION + +ENV PLUGIN_GH_VERSION=${GH_VERSION} + +RUN apk add --update --no-cache git ca-certificates + +COPY --from=binary /bin/gh /bin/gh + +COPY release/vela-github-release /bin/vela-github-release + +ENTRYPOINT [ "/bin/vela-github-release" ] diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..2954d18 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright (c) 2022 Target Brands, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..4be89df --- /dev/null +++ b/Makefile @@ -0,0 +1,268 @@ + +# Copyright (c) 2022 Target Brands, Inc. All rights reserved. +# +# Use of this source code is governed by the LICENSE file in this repository. + +# capture the current date we build the application from +BUILD_DATE = $(shell date +%Y-%m-%dT%H:%M:%SZ) + +# check if a git commit sha is already set +ifndef GITHUB_SHA + # capture the current git commit sha we build the application from + GITHUB_SHA = $(shell git rev-parse HEAD) +endif + +# check if a git tag is already set +ifndef GITHUB_TAG + # capture the current git tag we build the application from + GITHUB_TAG = $(shell git describe --tag --abbrev=0) +endif + +# check if a go version is already set +ifndef GOLANG_VERSION + # capture the current go version we build the application from + GOLANG_VERSION = $(shell go version | awk '{ print $$3 }') +endif + +# create a list of linker flags for building the golang application +LD_FLAGS = -X github.com/go-vela/vela-github-release/version.Commit=${GITHUB_SHA} -X github.com/go-vela/vela-github-release/version.Date=${BUILD_DATE} -X github.com/go-vela/vela-github-release/version.Go=${GOLANG_VERSION} -X github.com/go-vela/vela-github-release/version.Tag=${GITHUB_TAG} + +# The `clean` target is intended to clean the workspace +# and prepare the local changes for submission. +# +# Usage: `make clean` +.PHONY: clean +clean: tidy vet fmt fix + +# The `run` target is intended to build and +# execute the Docker image for the plugin. +# +# Usage: `make run` +.PHONY: run +run: build docker-build docker-run + +# The `tidy` target is intended to clean up +# the Go module files (go.mod & go.sum). +# +# Usage: `make tidy` +.PHONY: tidy +tidy: + @echo + @echo "### Tidying Go module" + @go mod tidy + +# The `vet` target is intended to inspect the +# Go source code for potential issues. +# +# Usage: `make vet` +.PHONY: vet +vet: + @echo + @echo "### Vetting Go code" + @go vet ./... + +# The `fmt` target is intended to format the +# Go source code to meet the language standards. +# +# Usage: `make fmt` +.PHONY: fmt +fmt: + @echo + @echo "### Formatting Go Code" + @go fmt ./... + +# The `fix` target is intended to rewrite the +# Go source code using old APIs. +# +# Usage: `make fix` +.PHONY: fix +fix: + @echo + @echo "### Fixing Go Code" + @go fix ./... + +# The `test` target is intended to run +# the tests for the Go source code. +# +# Usage: `make test` +.PHONY: test +test: + @echo + @echo "### Testing Go Code" + @go test -race ./... + +# The `test-cover` target is intended to run +# the tests for the Go source code and then +# open the test coverage report. +# +# Usage: `make test-cover` +.PHONY: test-cover +test-cover: + @echo + @echo "### Creating test coverage report" + @go test -race -covermode=atomic -coverprofile=coverage.out ./... + @echo + @echo "### Opening test coverage report" + @go tool cover -html=coverage.out + +# The `build` target is intended to compile +# the Go source code into a binary. +# +# Usage: `make build` +.PHONY: build +build: + @echo + @echo "### Building release/vela-github-release binary" + GOOS=linux CGO_ENABLED=0 \ + go build -a \ + -ldflags '${LD_FLAGS}' \ + -o release/vela-github-release \ + github.com/go-vela/vela-github-release/cmd/vela-github-release + +# The `build-static` target is intended to compile +# the Go source code into a statically linked binary. +# +# Usage: `make build-static` +.PHONY: build-static +build-static: + @echo + @echo "### Building static release/vela-github-release binary" + GOOS=linux CGO_ENABLED=0 \ + go build -a \ + -ldflags '-s -w -extldflags "-static" ${LD_FLAGS}' \ + -o release/vela-github-release \ + github.com/go-vela/vela-github-release/cmd/vela-github-release + +# The `build-static-ci` target is intended to compile +# the Go source code into a statically linked binary +# when used within a CI environment. +# +# Usage: `make build-static-ci` +.PHONY: build-static-ci +build-static-ci: + @echo + @echo "### Building CI static release/vela-github-release binary" + @go build -a \ + -ldflags '-s -w -extldflags "-static" ${LD_FLAGS}' \ + -o release/vela-github-release \ + github.com/go-vela/vela-github-release/cmd/vela-github-release + +# The `check` target is intended to output all +# dependencies from the Go module that need updates. +# +# Usage: `make check` +.PHONY: check +check: check-install + @echo + @echo "### Checking dependencies for updates" + @go list -u -m -json all | go-mod-outdated -update + +# The `check-direct` target is intended to output direct +# dependencies from the Go module that need updates. +# +# Usage: `make check-direct` +.PHONY: check-direct +check-direct: check-install + @echo + @echo "### Checking direct dependencies for updates" + @go list -u -m -json all | go-mod-outdated -direct + +# The `check-full` target is intended to output +# all dependencies from the Go module. +# +# Usage: `make check-full` +.PHONY: check-full +check-full: check-install + @echo + @echo "### Checking all dependencies for updates" + @go list -u -m -json all | go-mod-outdated + +# The `check-install` target is intended to download +# the tool used to check dependencies from the Go module. +# +# Usage: `make check-install` +.PHONY: check-install +check-install: + @echo + @echo "### Installing psampaz/go-mod-outdated" + @go get -u github.com/psampaz/go-mod-outdated + +# The `bump-deps` target is intended to upgrade +# non-test dependencies for the Go module. +# +# Usage: `make bump-deps` +.PHONY: bump-deps +bump-deps: check + @echo + @echo "### Upgrading dependencies" + @go get -u ./... + +# The `bump-deps-full` target is intended to upgrade +# all dependencies for the Go module. +# +# Usage: `make bump-deps-full` +.PHONY: bump-deps-full +bump-deps-full: check + @echo + @echo "### Upgrading all dependencies" + @go get -t -u ./... + +# The `docker-build` target is intended to build +# the Docker image for the plugin. +# +# Usage: `make docker-build` +.PHONY: docker-build +docker-build: + @echo + @echo "### Building vela-github-release:local image" + @docker build --no-cache -t vela-github-release:local . + +# The `docker-test` target is intended to execute +# the Docker image for the plugin with test variables. +# +# Usage: `make docker-test` +.PHONY: docker-test +docker-test: + @echo + @echo "### Testing vela-github-release:local image" + @docker run --rm \ + -e PARAMETER_ACTION=list \ + -e GITHUB_TOKEN \ + -e GITHUB_HOST=github.com \ + -e PARAMETER_LIMIT=30 \ + -e PARAMETER_LOG_LEVEL=trace \ + -v $(shell pwd):/vela/src \ + -w /vela/src/github-release \ + vela-github-release:local + +# The `docker-run` target is intended to execute +# the Docker image for the plugin. +# +# Usage: `make docker-run` +.PHONY: docker-run +docker-run: + @echo + @echo "### Executing vela-github-release:local image" + @docker run --rm \ + -e PARAMETER_ACTION \ + -e PARAMETER_CLOBBER \ + -e PARAMETER_DIR \ + -e PARAMETER_DRAFT \ + -e PARAMETER_FILES \ + -e GITHUB_HOST \ + -e GITHUB_TOKEN \ + -e PARAMETER_LIMIT \ + -e PARAMETER_LOG_LEVEL \ + -e PARAMETER_NOTES \ + -e PARAMETER_NOTES_FILE \ + -e PARAMETER_PRERELEASE \ + -e PARAMETER_PATTERNS \ + -e PARAMETER_TAG \ + -e PARAMETER_TARGET \ + -e PARAMETER_TITLE \ + -e PARAMETER_VERSION \ + -e PARAMETER_WEB \ + -v $(shell pwd):/vela/src/ \ + -w /vela/src/github-release \ + -e PARAMETER_YES \ + vela-github-release:local \ No newline at end of file diff --git a/README.md b/README.md deleted file mode 100644 index d6b9167..0000000 --- a/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# vela-github-release -GitHub Release Plugin for Vela (Target's official Pipeline Automation Framework) diff --git a/cmd/vela-github-release/command.go b/cmd/vela-github-release/command.go new file mode 100644 index 0000000..a3512c7 --- /dev/null +++ b/cmd/vela-github-release/command.go @@ -0,0 +1,50 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package main + +import ( + "fmt" + "os" + "os/exec" + "strings" + + "github.com/sirupsen/logrus" +) + +// execCmd is a helper function to +// run the provided command. +func execCmd(e *exec.Cmd, f *os.File) error { + logrus.Tracef("executing cmd %s", strings.Join(e.Args, " ")) + + // set command stout to OS stdout + e.Stdout = os.Stdout + // set command stderr to OS stderr + e.Stderr = os.Stderr + + // check if file provided is empty + if f != nil { + // set command stdin to file + e.Stdin = f + } + + // output "trace" string for command + fmt.Println("$", strings.Join(e.Args, " ")) + + return e.Run() +} + +// versionCmd is a helper function to output +// the gh version information. +func versionCmd() *exec.Cmd { + logrus.Trace("creating gh version command") + + // variable to store flags for command + var flags []string + + // add flag for version gh command + flags = append(flags, "version") + + return exec.Command(_gh, flags...) +} diff --git a/cmd/vela-github-release/command_test.go b/cmd/vela-github-release/command_test.go new file mode 100644 index 0000000..1da97b3 --- /dev/null +++ b/cmd/vela-github-release/command_test.go @@ -0,0 +1,35 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package main + +import ( + "os" + "os/exec" + "reflect" + "testing" +) + +func TestGithubRelease_execCmd(t *testing.T) { + // setup types + e := exec.Command("echo", "hello") + + err := execCmd(e, os.Stdin) + if err != nil { + t.Errorf("execCmd returned err: %v", err) + } +} + +func TestGithubRelease_versionCmd(t *testing.T) { + want := exec.Command( + _gh, + "version", + ) + + got := versionCmd() + + if !reflect.DeepEqual(got, want) { + t.Errorf("versionCmd is %v, want %v", got, want) + } +} diff --git a/cmd/vela-github-release/config.go b/cmd/vela-github-release/config.go new file mode 100644 index 0000000..5c888c8 --- /dev/null +++ b/cmd/vela-github-release/config.go @@ -0,0 +1,143 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package main + +import ( + "errors" + "fmt" + "os" + "os/exec" + "os/user" + "path/filepath" + + "github.com/spf13/afero" + + "github.com/sirupsen/logrus" +) + +var ( + appFS = afero.NewOsFs() + + // ErrorNoConfigAction is return when an action isn't provided. + ErrorNoConfigAction = errors.New("no config action provided") + + // ErrorNoConfigGitToken is returned when the github token isn't provided. + ErrorNoConfigGitToken = errors.New("no config github token provided") +) + +const tokenFile = "/root/token" + +// Config represents the plugin configuration for github information. +type Config struct { + // action to perform against gh + Action string + // hostname to set for gh + Hostname string + // path to tokenFile for gh auth login + Path string + // token to provide to authenticate to github hostname + Token string +} + +// Command formats and outputs the Config command from +// the provided configuration to config resources. +func (c *Config) Command() *exec.Cmd { + logrus.Trace("creating gh config command from plugin configuration") + + // variable to store flags for command + var flags []string + + // add flag for auth command + flags = append(flags, "auth", "login") + + // check if hostname is provided + if len(c.Hostname) > 0 { + // add flag for hostname from provided config hostname + flags = append(flags, fmt.Sprintf("--hostname=%s", c.Hostname)) + } + // add flag for with token command + flags = append(flags, "--with-token") + + return exec.Command(_gh, flags...) +} + +// Exec formats and runs the commands for applying +// the provided configuration to the resouces. +func (c *Config) Exec() error { + logrus.Debug("running config with provided configuration") + + // create gh token file for authentication + err := c.Write() + if err != nil { + return err + } + + // open file in stdin + file, err := os.Open(c.Path) + if err != nil { + return err + } + defer file.Close() + + // create command for the gh auth login + cmd := c.Command() + + // run the config command for the gh auth login + err = execCmd(cmd, file) + if err != nil { + return err + } + + return nil +} + +// Write creates a file in the home directory of the current user. +func (c *Config) Write() error { + logrus.Trace("writing gh token file") + + // use custom filesystem which enables us to test + a := &afero.Afero{ + Fs: appFS, + } + + // check if token file content is provided + if len(c.Token) == 0 { + return nil + } + + // capture current user running commands + u, err := user.Current() + if err == nil { + // create full path for token file + c.Path = filepath.Join(u.HomeDir, "token") + } + + logrus.Debug("Creating gh token file ", c.Path) + + // send Filesystem call to create directory path for token file + err = a.Fs.MkdirAll(filepath.Dir(c.Path), 0777) + if err != nil { + return err + } + + return a.WriteFile(c.Path, []byte(c.Token), 0600) +} + +// Validate verifies the Config is properly configured. +func (c *Config) Validate() error { + logrus.Trace("validating config configuration") + + // verify action is provided + if len(c.Action) == 0 { + return ErrorNoConfigAction + } + + // verify token is provided + if len(c.Token) == 0 { + return ErrorNoConfigGitToken + } + + return nil +} diff --git a/cmd/vela-github-release/config_test.go b/cmd/vela-github-release/config_test.go new file mode 100644 index 0000000..d2b93ea --- /dev/null +++ b/cmd/vela-github-release/config_test.go @@ -0,0 +1,163 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package main + +import ( + "errors" + "fmt" + "os/exec" + "reflect" + "testing" + + "github.com/spf13/afero" +) + +func TestGithubRelease_Config_Command(t *testing.T) { + // setup types + c := &Config{ + Action: "action", + Hostname: "hostname", + Path: tokenFile, + Token: "token", + } + + // nolint:gosec // ignore for testing purposes + want := exec.Command( + _gh, + "auth", + "login", + fmt.Sprintf("--hostname=%s", c.Hostname), + "--with-token", + ) + + got := c.Command() + + if !reflect.DeepEqual(got, want) { + t.Errorf("Command is %v, want %v", got, want) + } +} + +func TestGithubRelease_Config_Exec_Error(t *testing.T) { + // setup types + c := &Config{ + Action: "action", + Hostname: "hostname", + Path: tokenFile, + Token: "token", + } + + err := c.Exec() + if err == nil { + t.Errorf("Exec should have returned err: %v", err) + } +} + +func TestGithubRelease_Config_Validate_Success(t *testing.T) { + // setup types + c := &Config{ + Action: "action", + Hostname: "hostname", + Path: tokenFile, + Token: "token", + } + + err := c.Validate() + if err != nil { + t.Errorf("Validate returned err: %v", err) + } +} + +func TestGithubRelease_Config_Validate_Error(t *testing.T) { + tests := []struct { + name string + c *Config + wantErr error + }{ + { + name: "No action provided", + c: &Config{ + Action: "", + Hostname: "hostname", + Path: tokenFile, + Token: "token", + }, + wantErr: ErrorNoConfigAction, + }, + { + name: "No token provided", + c: &Config{ + Action: "action", + Hostname: "hostname", + Path: tokenFile, + Token: "", + }, + wantErr: ErrorNoConfigGitToken, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + if err := test.c.Validate(); err == nil { + t.Errorf("Validate() should have raised an error %v", test.wantErr) + } else if !errors.Is(err, test.wantErr) { + t.Errorf("Validate() error = %v, wantErr = %v", err, test.wantErr) + } + }) + } +} + +func TestGithubRelease_Config_Write(t *testing.T) { + // setup filesystem + appFS = afero.NewMemMapFs() + + // setup types + c := &Config{ + Action: "action", + Hostname: "hostname", + Path: tokenFile, + Token: "token", + } + + err := c.Write() + if err != nil { + t.Errorf("Write returned err: %v", err) + } +} + +func TestGithubRelease_Config_Write_Error(t *testing.T) { + // setup filesystem + appFS = afero.NewReadOnlyFs(afero.NewMemMapFs()) + + // setup types + c := &Config{ + Action: "action", + Hostname: "hostname", + Path: tokenFile, + Token: "token", + } + + err := c.Write() + if err == nil { + t.Errorf("Write should have returned err") + } +} + +func TestGithubRelease_Config_Write_NoFile(t *testing.T) { + // setup filesystem + appFS = afero.NewMemMapFs() + + // setup types + c := &Config{ + Action: "action", + Hostname: "hostname", + Path: tokenFile, + Token: "token", + } + + err := c.Write() + if err != nil { + t.Errorf("Write returned err: %v", err) + } +} diff --git a/cmd/vela-github-release/create.go b/cmd/vela-github-release/create.go new file mode 100644 index 0000000..d850885 --- /dev/null +++ b/cmd/vela-github-release/create.go @@ -0,0 +1,133 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package main + +import ( + "errors" + "fmt" + "os/exec" + + "github.com/sirupsen/logrus" +) + +const createAction = "create" + +var ( + // ErrorNoCreateTag is returned when the plugin is missing the create tag. + ErrorNoCreateTag = errors.New("no create tag provided") + + // ErrorNoCreateTarget is returned when the plugin is missing the create target. + ErrorNoCreateTarget = errors.New("no create target provided") +) + +// Create represents the plugin configuration for Create config information. +type Create struct { + // save the release as a draft instead of publishing it + Draft bool + // list of asset files to be given to create the release + Files []string + // create release notes + Notes string + // read release notes from file + NotesFile string + // mark the release as a prerelease + Prerelease bool + // tag name to create a release from + Tag string + // target branch or commit SHA (default: main branch) + Target string + // release title + Title string +} + +// Command formats and outputs the Create command from +// the provided configuration to create resources. +func (c *Create) Command() *exec.Cmd { + logrus.Trace("creating gh create command from plugin configuration") + + // variable to store flags for command + var flags []string + + // add flag for release command + flags = append(flags, releaseCmd) + + // add flag for create command + flags = append(flags, createAction) + + // check if create tag is provided + if len(c.Tag) > 0 { + // add flag for tag from provided create tag + flags = append(flags, c.Tag) + } + + // add flag for files provided by create files + flags = append(flags, c.Files...) + + // add flag for draft from provided create draft + flags = append(flags, fmt.Sprintf("--draft=%t", c.Draft)) + + // check if create notes is provided + if len(c.Notes) > 0 { + // add flag for notes from provided create notes + flags = append(flags, fmt.Sprintf("--notes=%s", c.Notes)) + } + + // check if create notesfile is provided + if len(c.NotesFile) > 0 { + // add flag for notesfile from provided create notesfile + flags = append(flags, fmt.Sprintf("--notes-file=%s", c.NotesFile)) + } + + // add flag for prerelease from provided create prerelease + flags = append(flags, fmt.Sprintf("--prerelease=%t", c.Prerelease)) + + // check if create target branch is provided + if len(c.Target) > 0 { + // add flag for target from provided create target + flags = append(flags, fmt.Sprintf("--target=%s", c.Target)) + } + + // check if create title is provided + if len(c.Title) > 0 { + // add flag for title from provided create title + flags = append(flags, fmt.Sprintf("--title=%s", c.Title)) + } + + return exec.Command(_gh, flags...) +} + +// Exec formats and runs the commands for applying +// the provided configuration to the resources. +func (c *Create) Exec() error { + logrus.Debug("running create with provided configuration") + + // create command for the target branch + cmd := c.Command() + + // run the create command for the target branch + err := execCmd(cmd, nil) + if err != nil { + return err + } + + return nil +} + +// Validate verifies the Create is properly configured. +func (c *Create) Validate() error { + logrus.Trace("validating create configuration") + + // verify target branch is provided if no target provided error + if len(c.Target) == 0 { + return ErrorNoCreateTarget + } + + // verify create tag is provided if no tag provided error + if len(c.Tag) == 0 { + return ErrorNoCreateTag + } + + return nil +} diff --git a/cmd/vela-github-release/create_test.go b/cmd/vela-github-release/create_test.go new file mode 100644 index 0000000..d9d0cb4 --- /dev/null +++ b/cmd/vela-github-release/create_test.go @@ -0,0 +1,133 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package main + +import ( + "errors" + "fmt" + "os/exec" + "reflect" + "testing" +) + +func TestGithubRelease_Create_Command(t *testing.T) { + // setup types + c := &Create{ + Draft: false, + Files: []string{"file"}, + Notes: "notes", + NotesFile: "notes_file", + Prerelease: false, + Tag: "tag", + Target: "target", + Title: "title", + } + + // nolint:gosec // ignore for testing purposes + want := exec.Command( + _gh, + releaseCmd, + createAction, + "tag", + "file", + fmt.Sprintf("--draft=%t", false), + fmt.Sprintf("--notes=%s", c.Notes), + fmt.Sprintf("--notes-file=%s", c.NotesFile), + fmt.Sprintf("--prerelease=%t", false), + fmt.Sprintf("--target=%s", c.Target), + fmt.Sprintf("--title=%s", c.Title), + ) + + got := c.Command() + + if !reflect.DeepEqual(got, want) { + t.Errorf("execCmd is %v, want %v", got, want) + } +} + +func TestGithubRelease_Create_Exec_Error(t *testing.T) { + // setup types + c := &Create{ + Draft: false, + Files: []string{"file"}, + Notes: "notes", + NotesFile: "notes_file", + Prerelease: false, + Tag: "tag", + Target: "target", + Title: "title", + } + + err := c.Exec() + if err == nil { + t.Errorf("Exec should have returned err: %v", err) + } +} + +func TestGithubRelease_Create_Validate_Success(t *testing.T) { + // setup types + c := &Create{ + Draft: false, + Files: []string{"file"}, + Notes: "notes", + NotesFile: "notes_file", + Prerelease: false, + Tag: "tag", + Target: "target", + Title: "title", + } + + err := c.Validate() + if err != nil { + t.Errorf("Validate returned err: %v", err) + } +} + +func TestGithubRelease_Create_Validate_Error(t *testing.T) { + tests := []struct { + name string + c *Create + wantErr error + }{ + { + name: "No target provided", + c: &Create{ + Draft: false, + Files: []string{"file"}, + Notes: "notes", + NotesFile: "notes_file", + Prerelease: false, + Tag: "tag", + Target: "", + Title: "title", + }, + wantErr: ErrorNoCreateTarget, + }, + { + name: "No tag provided", + c: &Create{ + Draft: false, + Files: []string{"file"}, + Notes: "notes", + NotesFile: "notes_file", + Prerelease: false, + Tag: "", + Target: "target", + Title: "title", + }, + wantErr: ErrorNoCreateTag, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + if err := test.c.Validate(); err == nil { + t.Errorf("Validate() should have raised an error %v", test.wantErr) + } else if !errors.Is(err, test.wantErr) { + t.Errorf("Validate() error = %v, wantErr = %v", err, test.wantErr) + } + }) + } +} diff --git a/cmd/vela-github-release/delete.go b/cmd/vela-github-release/delete.go new file mode 100644 index 0000000..d576a7c --- /dev/null +++ b/cmd/vela-github-release/delete.go @@ -0,0 +1,84 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +// nolint: dupl // ignore code similarity to keep consistent structure +package main + +import ( + "errors" + "fmt" + "os/exec" + + "github.com/sirupsen/logrus" +) + +const deleteAction = "delete" + +var ( + // ErrorNoDeleteTag is returned when the plugin is missing the delete tag. + ErrorNoDeleteTag = errors.New("no delete tag provided") +) + +// Delete represents the plugin configuration for Delete config information. +type Delete struct { + // tag name to delete a release from + Tag string + // Skip the confirmation prompt + Yes bool +} + +// Command formats and outputs the Delete command from +// the provided configuration to delete resources. +func (d *Delete) Command() *exec.Cmd { + logrus.Trace("creating gh delete command from plugin configuration") + + // variable to store flags for command + var flags []string + + // add flag for release command + flags = append(flags, releaseCmd) + + // add flag for delete command + flags = append(flags, deleteAction) + + // check if delete tag is provided + if len(d.Tag) > 0 { + // add flag for tag from provided delete tag + flags = append(flags, d.Tag) + } + + // add flag for delete from provided delete + flags = append(flags, fmt.Sprintf("--yes=%t", d.Yes)) + + return exec.Command(_gh, flags...) +} + +// Exec formats and runs the commands for applying +// the provided configuration to the resources. +func (d *Delete) Exec() error { + logrus.Debug("running delete with provided configuration") + + // delete command for the target branch + cmd := d.Command() + + // run the delete command for the target branch + err := execCmd(cmd, nil) + if err != nil { + return err + } + + return nil +} + +// Validate verifies the Delete is properly configured. +func (d *Delete) Validate() error { + logrus.Trace("validating delete configuration") + + // verify delete tag is provided if no tag provided error + if len(d.Tag) == 0 { + return ErrorNoDeleteTag + } + + return nil +} diff --git a/cmd/vela-github-release/delete_test.go b/cmd/vela-github-release/delete_test.go new file mode 100644 index 0000000..00c6ec1 --- /dev/null +++ b/cmd/vela-github-release/delete_test.go @@ -0,0 +1,79 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package main + +import ( + "errors" + "fmt" + "os/exec" + "reflect" + "testing" +) + +func TestGithubRelease_Delete_Command(t *testing.T) { + // setup types + d := &Delete{ + Tag: "tag", + Yes: false, + } + + // nolint:gosec // ignore for testing purposes + want := exec.Command( + _gh, + releaseCmd, + deleteAction, + fmt.Sprintf(d.Tag), + fmt.Sprintf("--yes=%t", false), + ) + + got := d.Command() + + if !reflect.DeepEqual(got, want) { + t.Errorf("execCmd is %v, want %v", got, want) + } +} + +func TestGithubRelease_Delete_Exec_Error(t *testing.T) { + // setup types + d := &Delete{ + Tag: "tag", + Yes: false, + } + + err := d.Exec() + if err == nil { + t.Errorf("Exec should have returned err: %v", err) + } +} + +func TestGithubRelease_Delete_Validate_Success(t *testing.T) { + // setup types + d := &Delete{ + Tag: "tag", + Yes: false, + } + + err := d.Validate() + if err != nil { + t.Errorf("Validate returned err: %v", err) + } +} + +func TestGithubRelease_Delete_Validate_Error(t *testing.T) { + // setup types + d := &Delete{ + Tag: "", + Yes: false, + } + + err := d.Validate() + if err == nil { + t.Errorf("Validate should have returned err: %v", ErrorNoDeleteTag) + } + + if !errors.Is(err, ErrorNoDeleteTag) { + t.Errorf("Validate should have returned err: %v, instead returned %v", ErrorNoDeleteTag, err) + } +} diff --git a/cmd/vela-github-release/download.go b/cmd/vela-github-release/download.go new file mode 100644 index 0000000..33a5b2b --- /dev/null +++ b/cmd/vela-github-release/download.go @@ -0,0 +1,97 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package main + +import ( + "errors" + "fmt" + "os/exec" + + "github.com/sirupsen/logrus" +) + +const downloadAction = "download" + +var ( + // ErrorNoDownloadDirectory is returned when no download directory is provided. + ErrorNoDownloadDirectory = errors.New("no download directory provided") + + // ErrorNoDownloadTag is returned when the plugin is missing the download tag. + ErrorNoDownloadTag = errors.New("no download tag provided") +) + +// Download represents the plugin configuration for Download config information. +type Download struct { + // the directory to download files into (default ".") + Directory string + // download only assets that match a glob pattern + Patterns []string + // tag name to download a release from + Tag string +} + +// Command formats and outputs the Download command from +// the provided configuration to dowmload resources. +func (d *Download) Command() *exec.Cmd { + logrus.Trace("creating gh download command from plugin configuration") + + // variable to store flags for command + var flags []string + + // add flag for release command + flags = append(flags, releaseCmd) + + // add flag for download command + flags = append(flags, downloadAction) + + // check if download tag is provided + if len(d.Tag) > 0 { + // add flag for tag from provided download tag + flags = append(flags, d.Tag) + } + + // add flag for directory from provided download directory + flags = append(flags, fmt.Sprintf("--dir=%s", d.Directory)) + + // iterate through all downloads patterns + for _, pattern := range d.Patterns { + // add flag for patterns provided by download patterns + flags = append(flags, fmt.Sprintf("--pattern=%s", pattern)) + } + + return exec.Command(_gh, flags...) +} + +func (d *Download) Exec() error { + logrus.Debug("running download with provided configuration") + + // download command for the directory + cmd := d.Command() + + // run the download command for the directory + err := execCmd(cmd, nil) + if err != nil { + return err + } + + return nil +} + +// Validate verifies the Download is properly configured. +func (d *Download) Validate() error { + logrus.Trace("validating download configuration") + + // verify directory field is provided + if len(d.Directory) == 0 { + return ErrorNoDownloadDirectory + } + + // verify download tag is provided if no tag provided error + if len(d.Tag) == 0 { + return ErrorNoDownloadTag + } + + return nil +} diff --git a/cmd/vela-github-release/download_test.go b/cmd/vela-github-release/download_test.go new file mode 100644 index 0000000..40e82dc --- /dev/null +++ b/cmd/vela-github-release/download_test.go @@ -0,0 +1,103 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package main + +import ( + "errors" + "fmt" + "os/exec" + "reflect" + "testing" +) + +func TestGithubRelease_Download_Command(t *testing.T) { + // setup types + d := &Download{ + Directory: "dir", + Patterns: []string{"pattern"}, + Tag: "tag", + } + + // nolint:gosec // ignore for testing purposes + want := exec.Command( + _gh, + releaseCmd, + downloadAction, + d.Tag, + fmt.Sprintf("--dir=%s", d.Directory), + fmt.Sprintf("--pattern=%s", "pattern"), + ) + + got := d.Command() + + if !reflect.DeepEqual(got, want) { + t.Errorf("execCmd is %v, want %v", got, want) + } +} + +func TestGithubRelease_Download_Exec_Error(t *testing.T) { + // setup types + d := &Download{ + Directory: "dir", + Patterns: []string{"patterns"}, + Tag: "tag", + } + + err := d.Exec() + if err == nil { + t.Errorf("Exec should have returned err: %v", err) + } +} + +func TestGithubRelease_Download_Validate_Success(t *testing.T) { + // setup types + d := &Download{ + Directory: "dir", + Patterns: []string{"patterns"}, + Tag: "tag", + } + + err := d.Validate() + if err != nil { + t.Errorf("Validate returned err: %v", err) + } +} + +func TestGithubRelease_Download_Validate_Error(t *testing.T) { + tests := []struct { + name string + d *Download + wantErr error + }{ + { + name: "No directory provided", + d: &Download{ + Directory: "", + Patterns: []string{"patterns"}, + Tag: "tag", + }, + wantErr: ErrorNoDownloadDirectory, + }, + { + name: "No tag provided", + d: &Download{ + Directory: "dir", + Patterns: []string{"patterns"}, + Tag: "", + }, + wantErr: ErrorNoDownloadTag, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + if err := test.d.Validate(); err == nil { + t.Errorf("Validate() should have raised an error %v", test.wantErr) + } else if !errors.Is(err, test.wantErr) { + t.Errorf("Validate() error = %v, wantErr = %v", err, test.wantErr) + } + }) + } +} diff --git a/cmd/vela-github-release/gh.go b/cmd/vela-github-release/gh.go new file mode 100644 index 0000000..8b5bd81 --- /dev/null +++ b/cmd/vela-github-release/gh.go @@ -0,0 +1,70 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package main + +import ( + "fmt" + "runtime" + "strings" + + getter "github.com/hashicorp/go-getter" + "github.com/sirupsen/logrus" + "github.com/spf13/afero" +) + +const ( + _gh = "/bin/gh" + _ghTmp = "/bin/download" + _download = "https://github.com/cli/cli/releases/download/v%s/gh_%s_%s_%s.tar.gz//gh_%s_%s_%s/bin" +) + +// install downloads a custom version of the gh cli. +func install(customVer, defaultVer string) error { + logrus.Infof("custom gh version requested: %s", customVer) + + // use custom filesystem which enables us to test + a := &afero.Afero{ + Fs: appFS, + } + + // check if the custom version matches the default version + if strings.EqualFold(customVer, defaultVer) { + // the gh versions match so no action required + return nil + } + + logrus.Debugf("custom version does not match default: %s", defaultVer) + // rename the old gh binary since we can't overwrite it for now + // https://github.com/hashicorp/go-getter/issues/219 + err := a.Rename(_gh, fmt.Sprintf("%s.default", _gh)) + if err != nil { + return err + } + + // create the download URL to install gh + url := fmt.Sprintf(_download, customVer, customVer, runtime.GOOS, runtime.GOARCH, customVer, runtime.GOOS, runtime.GOARCH) + + logrus.Infof("downloading gh version from: %s", url) + // send the HTTP request to install gh + err = getter.Get(_ghTmp, url, []getter.ClientOption{}...) + if err != nil { + return err + } + + // getter installed a directory of files, move the binary from that to the _gh location + err = a.Rename(_ghTmp+"/gh", _gh) + if err != nil { + return err + } + + logrus.Debugf("changing ownership of the file: %s", _gh) + // ensure the gh binary is executable + err = a.Chmod(_gh, 0700) + if err != nil { + return err + } + + return nil +} diff --git a/cmd/vela-github-release/gh_test.go b/cmd/vela-github-release/gh_test.go new file mode 100644 index 0000000..1c35c13 --- /dev/null +++ b/cmd/vela-github-release/gh_test.go @@ -0,0 +1,54 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package main + +import ( + "testing" + + "github.com/spf13/afero" +) + +func TestGithub_CLI_install(t *testing.T) { + // setup filesystem + appFS = afero.NewMemMapFs() + + // run test + err := install("v0.4.0", "v0.4.0") + if err != nil { + t.Errorf("install returned err: %v", err) + } +} + +func TestGithub_CLI_install_NoBinary(t *testing.T) { + // setup filesystem + appFS = afero.NewMemMapFs() + + // run test + err := install("v0.2.0", "v0.4.0") + if err == nil { + t.Errorf("install should have returned err ") + } +} + +func TestGithub_CLI_install_NotWritable(t *testing.T) { + // setup filesystem + appFS = afero.NewMemMapFs() + + a := &afero.Afero{ + Fs: appFS, + } + + // create binary file + err := a.WriteFile(_gh, []byte("!@#$%^&*()"), 0777) + if err != nil { + t.Errorf("Unable to write file %s: %v", _gh, err) + } + + // run test + err = install("v0.2.0", "v0.4.0") + if err == nil { + t.Errorf("install should have returned err") + } +} diff --git a/cmd/vela-github-release/list.go b/cmd/vela-github-release/list.go new file mode 100644 index 0000000..d7951db --- /dev/null +++ b/cmd/vela-github-release/list.go @@ -0,0 +1,75 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package main + +import ( + "errors" + "fmt" + "os/exec" + + "github.com/sirupsen/logrus" +) + +const listAction = "list" + +var ( + // ErrorInvalidListLimit is returned when the limit is not provided. + ErrorInvalidListLimit = errors.New("List limit cannot be zero") +) + +// List represents the plugin configuration for List config information. +type List struct { + // maximum number of items to fetch (default 30) + Limit int +} + +// Command formats and outputs the List command from +// the provided configuration to list resources. +func (l *List) Command() *exec.Cmd { + logrus.Trace("creating gh list command from plugin configuration") + + // variable to store flags for command + var flags []string + + // add flag for release command + flags = append(flags, releaseCmd) + + // add flag for list command + flags = append(flags, listAction) + + // add flag for list from provided list + flags = append(flags, fmt.Sprintf("--limit=%d", l.Limit)) + + return exec.Command(_gh, flags...) +} + +// Exec formats and runs the commands for applying +// the provided configuration to the resources. +func (l *List) Exec() error { + logrus.Debug("running list with provided configuration") + + // list command for the number of items to fetch + cmd := l.Command() + + // run the list command for the limit of items + err := execCmd(cmd, nil) + if err != nil { + return err + } + + return nil +} + +// Validate verifies the List is properly configured. +func (l *List) Validate() error { + logrus.Trace("validating list configuration") + + // verify limit is provided if no limit is provided error + if l.Limit == 0 { + return ErrorInvalidListLimit + } + + return nil +} diff --git a/cmd/vela-github-release/list_test.go b/cmd/vela-github-release/list_test.go new file mode 100644 index 0000000..76aea12 --- /dev/null +++ b/cmd/vela-github-release/list_test.go @@ -0,0 +1,74 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package main + +import ( + "errors" + "fmt" + "os/exec" + "reflect" + "testing" +) + +func TestGithubRelease_List_Command(t *testing.T) { + // setup types + l := &List{ + Limit: 30, + } + + // nolint:gosec // ignore for testing purposes + want := exec.Command( + _gh, + releaseCmd, + listAction, + fmt.Sprintf("--limit=%d", l.Limit), + ) + + got := l.Command() + + if !reflect.DeepEqual(got, want) { + t.Errorf("execCmd is %v, want %v", got, want) + } +} + +func TestGithubRelease_List_Exec_Error(t *testing.T) { + // setup types + l := &List{ + Limit: 30, + } + + err := l.Exec() + if err == nil { + t.Errorf("Exec should have returned err: %v", err) + } +} + +func TestGithubRelease_List_Validate(t *testing.T) { + // setup types + l := &List{ + Limit: 30, + } + + err := l.Validate() + if err != nil { + t.Errorf("Validate returned err: %v", err) + } +} + +func TestGithubRelease_List_Validate_Error(t *testing.T) { + // setup types + l := &List{ + Limit: 0, + } + + err := l.Validate() + if err == nil { + t.Errorf("Validate should have returned err: %v", ErrorInvalidListLimit) + } + + if !errors.Is(err, ErrorInvalidListLimit) { + t.Errorf("Validate should have returned err: %v, instead returned %v", ErrorInvalidListLimit, err) + } +} diff --git a/cmd/vela-github-release/main.go b/cmd/vela-github-release/main.go new file mode 100644 index 0000000..e031e49 --- /dev/null +++ b/cmd/vela-github-release/main.go @@ -0,0 +1,290 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package main + +import ( + "encoding/json" + "fmt" + "os" + "time" + + "github.com/go-vela/vela-github-release/version" + "github.com/sirupsen/logrus" + "github.com/urfave/cli/v2" + + _ "github.com/joho/godotenv/autoload" +) + +func main() { + // capture application version information. + pluginVersion := version.New() + // serialize the version information as pretty JSON + bytes, err := json.MarshalIndent(pluginVersion, "", " ") + if err != nil { + logrus.Fatal(err) + } + + // output the version information to stdout + fmt.Fprintf(os.Stdout, "%s\n", string(bytes)) + + // create new CLI application + app := &cli.App{ + Name: "vela-github-release", + HelpName: "vela-github-release", + Usage: "Vela Github Release plugin for managing Gihub Releases in a Vela Pipeline.", + Copyright: "Copyright (c) 2022 Target Brands, Inc. All rights reserved.", + Authors: []*cli.Author{ + { + Name: "Vela Admins", + Email: "vela@target.com", + }, + }, + Action: run, + Compiled: time.Now(), + Version: pluginVersion.Semantic(), + Flags: []cli.Flag{ + &cli.StringSliceFlag{ + EnvVars: []string{"PARAMETER_FILES", "GITHUB_RELEASE_FILES"}, + FilePath: string("/vela/parameters/github-release/files,/vela/secrets/github-release/files"), + Name: "files", + Usage: "files name used for action", + }, + &cli.StringFlag{ + EnvVars: []string{"PARAMETER_LOG_LEVEL", "VELA_LOG_LEVEL", "GITHUB_RELEASE_LOG_LEVEL"}, + FilePath: string("/vela/parameters/github-release/log_level,/vela/secrets/github-release/log_level"), + Name: "log.level", + Usage: "set log level - options: (trace|debug|info|warn|error|fatal|panic)", + Value: "info", + }, + &cli.StringFlag{ + EnvVars: []string{"PARAMETER_TAG", "GITHUB_RELEASE_TAG"}, + FilePath: string("/vela/parameters/github-release/tag,/vela/secrets/github-release/tag"), + Name: "tag", + Usage: "tag name used for action", + }, + &cli.StringFlag{ + EnvVars: []string{"PARAMETER_VERSION", "VELA_GH_VERSION", "GH_VERSION"}, + FilePath: string("/vela/parameters/github-release/gh/version,/vela/secrets/github-release/gh/version"), + Name: "gh.version", + Usage: "set gh version for plugin", + }, + // Config Flags + &cli.StringFlag{ + EnvVars: []string{"PARAMETER_ACTION", "CONFIG_ACTION"}, + FilePath: string("/vela/parameters/github-release/config/action,/vela/secrets/github-release/config/action"), + Name: "config.action", + Usage: "action to perform against github instance", + }, + &cli.StringFlag{ + EnvVars: []string{"PARAMETER_HOSTNAME", "CONFIG_HOSTNAME", "GH_HOST", "GITHUB_HOST"}, + FilePath: string("/vela/parameters/github-release/config/hostname,/vela/secrets/github-release/config/hostname"), + Name: "config.hostname", + Usage: "hostname to set for github instance", + Value: "github.com", + }, + &cli.StringFlag{ + EnvVars: []string{"PARAMETER_TOKEN", "CONFIG_TOKEN", "GH_TOKEN", "GITHUB_TOKEN"}, + FilePath: string("/vela/parameters/github-release/config/token,/vela/secrets/github-release/config/token"), + Name: "config.token", + Usage: "token to set to authenticate to github instance", + }, + // Create Flags + &cli.BoolFlag{ + EnvVars: []string{"PARAMETER_DRAFT", "CREATE_DRAFT"}, + FilePath: string("/vela/parameters/github-release/create/draft,/vela/secrets/github-release/create/draft"), + Name: "create.draft", + Usage: "save the release as a draft instead of publishing it", + }, + &cli.StringFlag{ + EnvVars: []string{"PARAMETER_NOTES", "CREATE_NOTES"}, + FilePath: string("/vela/parameters/github-release/create/notes,/vela/secrets/github-release/create/notes"), + Name: "create.notes", + Usage: "create release notes", + }, + &cli.StringFlag{ + EnvVars: []string{"PARAMETER_NOTES_FILE", "CREATE_NOTES_FILE"}, + FilePath: string("/vela/parameters/github-release/create/notes-file,/vela/secrets/github-release/create/notes-file"), + Name: "create.notes_file", + Usage: "read release notes from file", + }, + &cli.BoolFlag{ + EnvVars: []string{"PARAMETER_PRERELEASE", "CREATE_PRERELEASE"}, + FilePath: string("/vela/parameters/github-release/create/prerelease,/vela/secrets/github-release/create/prerelease"), + Name: "create.prerelease", + Usage: "mark the release as a prerelease", + }, + &cli.StringFlag{ + EnvVars: []string{"PARAMETER_TARGET", "CREATE_TARGET"}, + FilePath: string("/vela/parameters/github-release/create/target,/vela/secrets/github-release/create/target"), + Name: "create.target", + Usage: "target branch or commit SHA", + Value: "main", + }, + &cli.StringFlag{ + EnvVars: []string{"PARAMETER_TITLE", "CREATE_TITLE"}, + FilePath: string("/vela/parameters/github-release/create/title,/vela/secrets/github-release/create/title"), + Name: "create.title", + Usage: "Release title", + }, + // Delete Flags + &cli.BoolFlag{ + EnvVars: []string{"PARAMETER_YES", "DELETE_YES"}, + FilePath: string("/vela/parameters/github-release/delete/yes,/vela/secrets/github-release/delete/yes"), + Name: "delete.yes", + Usage: "skip the confirmation prompt", + // TODO: should this be set with default to bypass the prompt? : Value: true, + }, + // Download Flags + &cli.StringFlag{ + EnvVars: []string{"PARAMETER_DIR", "DOWNLOAD_DIR"}, + FilePath: string("/vela/parameters/github-release/download/dir,/vela/secrets/github-release/download/dir"), + Name: "download.dir", + Usage: "the directory to download files", + Value: ".", + }, + &cli.StringSliceFlag{ + EnvVars: []string{"PARAMETER_PATTERNS", "DOWNLOAD_PATTERNS"}, + FilePath: string("/vela/parameters/github-release/download/patterns,/vela/secrets/github-release/download/patterns"), + Name: "download.patterns", + Usage: "download only assets that match glob patterns", + }, + // List Flags + &cli.IntFlag{ + EnvVars: []string{"PARAMETER_LIMIT", "LIST_LIMIT"}, + FilePath: string("/vela/parameters/github-release/list/limit,/vela/secrets/github-release/list/limit"), + Name: "list.limit", + Usage: "maximum number of items to fetch", + Value: 30, + }, + // Upload Flags + &cli.BoolFlag{ + EnvVars: []string{"PARAMETER_CLOBBER", "UPLOAD_CLOBBER"}, + FilePath: string("/vela/parameters/github-release/upload/clobber,/vela/secrets/github-release/upload/clobber"), + Name: "upload.clobber", + Usage: "overwrite existing assets of the same name", + }, + // View Flags + &cli.BoolFlag{ + EnvVars: []string{"PARAMETER_WEB", "VIEW_WEB"}, + FilePath: string("/vela/parameters/github-release/view/web,/vela/secrets/github-release/view/web"), + Name: "view.web", + Usage: "open the release in the browser", + }, + }, + } + + if err := app.Run(os.Args); err != nil { + logrus.Fatal(err) + } +} + +// run executes the plugin based off the configuration provided. +func run(c *cli.Context) error { + // set the log level for the plugin + switch c.String("log.level") { + case "t", "trace", "Trace", "TRACE": + logrus.SetLevel(logrus.TraceLevel) + case "d", "debug", "Debug", "DEBUG": + logrus.SetLevel(logrus.DebugLevel) + case "w", "warn", "Warn", "WARN": + logrus.SetLevel(logrus.WarnLevel) + case "e", "error", "Error", "ERROR": + logrus.SetLevel(logrus.ErrorLevel) + case "f", "fatal", "Fatal", "FATAL": + logrus.SetLevel(logrus.FatalLevel) + case "p", "panic", "Panic", "PANIC": + logrus.SetLevel(logrus.PanicLevel) + case "i", "info", "Info", "INFO": + fallthrough + default: + logrus.SetLevel(logrus.InfoLevel) + } + + if c.IsSet("ci") { + logrus.SetFormatter(&logrus.TextFormatter{ + DisableColors: true, + FullTimestamp: true, + }) + } else { + logrus.SetFormatter(&logrus.TextFormatter{ + ForceColors: true, + FullTimestamp: false, + PadLevelText: true, + }) + } + + logrus.WithFields(logrus.Fields{ + "code": "https://github.com/go-vela/vela-github-release", + "docs": "https://go-vela.github.io/docs/plugins/registry/github-release/", + "registry": "https://hub.docker.com/r/target/vela-github-release", + }).Info("Vela Github Release Plugin") + + // capture custom gh version requested + version := c.String("gh.version") + + // check is a custom gh version was requested + if len(version) > 0 { + // attempt to install the custom gh version + if err := install(version, os.Getenv("PLUGIN_GH_VERSION")); err != nil { + return err + } + } + + // create the plugin + p := &Plugin{ + // config configuration + Config: &Config{ + Action: c.String("config.action"), + Hostname: c.String("config.hostname"), + Path: tokenFile, + Token: c.String("config.token"), + }, + // create configuration + Create: &Create{ + Draft: c.Bool("create.draft"), + Files: c.StringSlice("files"), + Notes: c.String("create.notes"), + NotesFile: c.String("create.notes_file"), + Prerelease: c.Bool("create.prerelease"), + Tag: c.String("tag"), + Target: c.String("create.target"), + Title: c.String("create.title"), + }, + // delete configuration + Delete: &Delete{ + Yes: c.Bool("delete.yes"), + Tag: c.String("tag"), + }, + // download configuration + Download: &Download{ + Directory: c.String("download.dir"), + Patterns: c.StringSlice("download.patterns"), + Tag: c.String("tag"), + }, + // list configuration + List: &List{ + Limit: c.Int("list.limit"), + }, + // upload configuration + Upload: &Upload{ + Clobber: c.Bool("upload.clobber"), + Files: c.StringSlice("files"), + Tag: c.String("tag"), + }, + // view configuration + View: &View{ + Tag: c.String("tag"), + Web: c.Bool("view.web"), + }, + } + + // validate the plugin + if err := p.Validate(); err != nil { + return err + } + + // execute the plugin + return p.Exec() +} diff --git a/cmd/vela-github-release/plugin.go b/cmd/vela-github-release/plugin.go new file mode 100644 index 0000000..3693819 --- /dev/null +++ b/cmd/vela-github-release/plugin.go @@ -0,0 +1,135 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package main + +import ( + "errors" + "fmt" + + "github.com/sirupsen/logrus" +) + +// releaseCmd defines the core command for gh release plugin. +const releaseCmd = "release" + +var ( + // ErrInvalidAction defines the error type when the + // Action provided to the Plugin is unsupported. + ErrInvalidAction = errors.New("invalid action provided") +) + +// Plugin represents the configuration loaded for the plugin. +type Plugin struct { + // config arguments loaded for the plugin + Config *Config + // create arguments loaded for the plugin + Create *Create + // delete arguments loaded for the plugin + Delete *Delete + // download arguments loaded for the plugin + Download *Download + // list arguments loaded for the plugin + List *List + // upload arguments loaded for the plugin + Upload *Upload + // view arguments loaded fo rthe plugin + View *View +} + +// Exec formats and runs the commands for gh plugin. +func (p *Plugin) Exec() error { + logrus.Debug("running plugin with provided configuration") + + // output gh version for troubleshooting + err := execCmd(versionCmd(), nil) + if err != nil { + return err + } + + // execute config configuration + err = p.Config.Exec() + if err != nil { + return err + } + + // execute action specific configuration + switch p.Config.Action { + case createAction: + // execute create action + return p.Create.Exec() + case deleteAction: + // execute delete action + return p.Delete.Exec() + case downloadAction: + // execute download action + return p.Download.Exec() + case listAction: + // execute list action + return p.List.Exec() + case uploadAction: + // execute upload action + return p.Upload.Exec() + case viewAction: + // execute view action + return p.View.Exec() + default: + return fmt.Errorf( + "%w: %s (Valid actions: %s, %s, %s, %s, %s, %s)", + ErrInvalidAction, + p.Config.Action, + createAction, + deleteAction, + downloadAction, + listAction, + uploadAction, + viewAction, + ) + } +} + +// Validate verfies the plugin is properly configured. +func (p *Plugin) Validate() error { + logrus.Debug("validating plugin configuration") + + // validate config configuration + err := p.Config.Validate() + if err != nil { + return err + } + + // validate action specific configuration + switch p.Config.Action { + case createAction: + // validate create configuration + return p.Create.Validate() + case deleteAction: + // validate delete configuration + return p.Delete.Validate() + case downloadAction: + // validate download configuration + return p.Download.Validate() + case listAction: + // validate list configuration + return p.List.Validate() + case uploadAction: + // validate upload configuration + return p.Upload.Validate() + case viewAction: + // validate view configuration + return p.View.Validate() + default: + return fmt.Errorf( + "%w: %s (Valid actions: %s, %s, %s, %s, %s, %s)", + ErrInvalidAction, + p.Config.Action, + createAction, + deleteAction, + downloadAction, + listAction, + uploadAction, + viewAction, + ) + } +} diff --git a/cmd/vela-github-release/upload.go b/cmd/vela-github-release/upload.go new file mode 100644 index 0000000..e966ec4 --- /dev/null +++ b/cmd/vela-github-release/upload.go @@ -0,0 +1,88 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package main + +import ( + "errors" + "fmt" + "os/exec" + + "github.com/sirupsen/logrus" +) + +const uploadAction = "upload" + +var ( + // ErrorNoUploadTag is returned when the plugin is missing the upload tag. + ErrorNoUploadTag = errors.New("no upload tag provided") +) + +// Upload represents the plugin configuration for Upload config information. +type Upload struct { + // list of asset files to be given to upload + Files []string + // overwrite existing assets of the same name + Clobber bool + // tag name to upload a release from + Tag string +} + +// Command formats and outputs the Upload command from +// the provided configuration to upload resources. +func (u *Upload) Command() *exec.Cmd { + logrus.Trace("creating gh upload command from plugin configuration") + + // variable to store flags for command + var flags []string + + // add flag for release command + flags = append(flags, releaseCmd) + + // add flag for upload command + flags = append(flags, uploadAction) + + // check if upload tag is provided + if len(u.Tag) > 0 { + // add flag for tag from provided upload tag + flags = append(flags, u.Tag) + } + + // add flag for files provided by upload files + flags = append(flags, u.Files...) + + // add flag for upload from provided upload + flags = append(flags, fmt.Sprintf("--clobber=%t", u.Clobber)) + + return exec.Command(_gh, flags...) +} + +// Exec formats and runs the commands for applying +// the provided configuration to the resources. +func (u *Upload) Exec() error { + logrus.Debug("running upload with the provided configuration") + + // upload command for the existing asset + cmd := u.Command() + + // run the upload command for the existng asset + err := execCmd(cmd, nil) + if err != nil { + return err + } + + return nil +} + +// Validate verifies the Upload is properly configured. +func (u *Upload) Validate() error { + logrus.Trace("validating upload configuration") + + // verify upload tag is provided if no tag provided error + if len(u.Tag) == 0 { + return ErrorNoUploadTag + } + + return nil +} diff --git a/cmd/vela-github-release/upload_test.go b/cmd/vela-github-release/upload_test.go new file mode 100644 index 0000000..cf298b6 --- /dev/null +++ b/cmd/vela-github-release/upload_test.go @@ -0,0 +1,84 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package main + +import ( + "errors" + "fmt" + "os/exec" + "reflect" + "testing" +) + +func TestGithubRelease_Upload_Command(t *testing.T) { + // setup types + u := &Upload{ + Clobber: false, + Files: []string{"files"}, + Tag: "tag", + } + + // nolint:gosec // ignore for testing purposes + want := exec.Command( + _gh, + releaseCmd, + uploadAction, + "tag", + "files", + fmt.Sprintf("--clobber=%t", u.Clobber), + ) + + got := u.Command() + + if !reflect.DeepEqual(got, want) { + t.Errorf("execCmd is %v, want %v", got, want) + } +} + +func TestGithubRelease_Upload_Exec_Error(t *testing.T) { + // setup types + u := &Upload{ + Clobber: false, + Files: []string{"files"}, + Tag: "tag", + } + + err := u.Exec() + if err == nil { + t.Errorf("Exec should have returned err: %v", err) + } +} + +func TestGithubRelease_Upload_Validate(t *testing.T) { + // setup types + u := &Upload{ + Clobber: true, + Files: []string{"files"}, + Tag: "tag", + } + + err := u.Validate() + if err != nil { + t.Errorf("Validate returned err: %v", err) + } +} + +func TestGithubRelease_Upload_Validate_Error(t *testing.T) { + // setup types + u := &Upload{ + Clobber: false, + Files: []string{""}, + Tag: "", + } + + err := u.Validate() + if err == nil { + t.Errorf("Validate should have returned err: %v", ErrorNoUploadTag) + } + + if !errors.Is(err, ErrorNoUploadTag) { + t.Errorf("Validate should have returned err: %v, instead returned %v", ErrorNoUploadTag, err) + } +} diff --git a/cmd/vela-github-release/view.go b/cmd/vela-github-release/view.go new file mode 100644 index 0000000..8ebf574 --- /dev/null +++ b/cmd/vela-github-release/view.go @@ -0,0 +1,84 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +// nolint: dupl // ignore code similarity to keep consistent structure +package main + +import ( + "errors" + "fmt" + "os/exec" + + "github.com/sirupsen/logrus" +) + +const viewAction = "view" + +var ( + // ErrorNoViewTag is returned when the plugin is missing the view tag. + ErrorNoViewTag = errors.New("no view tag provided") +) + +// View represents the plugin configuration for View config information. +type View struct { + // tag name to view a release from + Tag string + // open the release in the browser + Web bool +} + +// Command formats and outputs the View command from +// the provided configuration to view resources. +func (v *View) Command() *exec.Cmd { + logrus.Trace("creatig gh view command from plugin configuration") + + // variable to store flags for command + var flags []string + + // add flag for release command + flags = append(flags, releaseCmd) + + // add flag for view command + flags = append(flags, viewAction) + + // check if view tag is provided + if len(v.Tag) > 0 { + // add flag for tag from provided view tag + flags = append(flags, v.Tag) + } + + // add flag for the view from provided view + flags = append(flags, fmt.Sprintf("--web=%t", v.Web)) + + return exec.Command(_gh, flags...) +} + +// Exec formats and runs the commands for applying +// the provided configuration to the resources. +func (v *View) Exec() error { + logrus.Debug("running view with provided configuration") + + // view command for the release in a browser + cmd := v.Command() + + // run the view command for the release in a browser + err := execCmd(cmd, nil) + if err != nil { + return err + } + + return nil +} + +// Validate verifies the View is properly configured. +func (v *View) Validate() error { + logrus.Trace("validating view configuration") + + // verify view tag is provided if no tag provided error + if len(v.Tag) == 0 { + return ErrorNoViewTag + } + + return nil +} diff --git a/cmd/vela-github-release/view_test.go b/cmd/vela-github-release/view_test.go new file mode 100644 index 0000000..144b4ed --- /dev/null +++ b/cmd/vela-github-release/view_test.go @@ -0,0 +1,79 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package main + +import ( + "errors" + "fmt" + "os/exec" + "reflect" + "testing" +) + +func TestGithubRelease_View_Command(t *testing.T) { + // setup types + v := &View{ + Tag: "tag", + Web: false, + } + + // nolint:gosec // ignore for testing purposes + want := exec.Command( + _gh, + releaseCmd, + viewAction, + "tag", + fmt.Sprintf("--web=%t", v.Web), + ) + + got := v.Command() + + if !reflect.DeepEqual(got, want) { + t.Errorf("execCmd is %v, want %v", got, want) + } +} + +func TestGithubRelease_View_Exec_Error(t *testing.T) { + // setup types + v := &View{ + Tag: "tag", + Web: false, + } + + err := v.Exec() + if err == nil { + t.Errorf("Exec should have returned err: %v", err) + } +} + +func TestGithubRelease_View_Validate_Success(t *testing.T) { + // setup types + v := &View{ + Tag: "tag", + Web: false, + } + + err := v.Validate() + if err != nil { + t.Errorf("Validate returned err: %v", err) + } +} + +func TestGithubRelease_View_Validate_Error(t *testing.T) { + // setup types + v := &View{ + Tag: "", + Web: false, + } + + err := v.Validate() + if err == nil { + t.Errorf("Validate should have returned err: %v", ErrorNoViewTag) + } + + if !errors.Is(err, ErrorNoViewTag) { + t.Errorf("Validate should have returned err: %v, instead returned %v", ErrorNoViewTag, err) + } +} diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 0000000..cf9fb4a --- /dev/null +++ b/codecov.yml @@ -0,0 +1,52 @@ +# The is the default codecov.io yaml configuration all projects use +# that do not have their own codecov.yml already in the project. +# +# https://docs.codecov.io/docs/codecov-yaml#section-default-yaml + +# This section provides the generic configuration for codecov. +# +# https://docs.codecov.io/docs/codecovyml-reference#section-codecov +codecov: + require_ci_to_pass: yes + +# This section provides the configuration for the +# coverage report codecov analyzes for results. +# +# https://docs.codecov.io/docs/codecovyml-reference#section-coverage +coverage: + precision: 2 + round: down + range: "70...100" + + # https://docs.codecov.io/docs/commit-status + status: + # set rules for the project status report + project: + default: + target: 90% + threshold: 0% + # disable the patch status report + patch: off + # disable the changes status report + changes: off + +# This section provides the configuration for the +# parsers codecov uses for the coverage report. +# +# https://docs.codecov.io/docs/codecovyml-reference#section-parsers +parsers: + gcov: + branch_detection: + conditional: yes + loop: yes + method: no + macro: no + +# This section provides the configuration for the +# comments codecov makes to open pull requests. +# +# https://docs.codecov.io/docs/codecovyml-reference#section-comment +comment: + layout: "reach, diff, flags, files" + behavior: default + require_changes: no diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..c6a723e --- /dev/null +++ b/go.mod @@ -0,0 +1,47 @@ +module github.com/go-vela/vela-github-release + +go 1.17 + +require ( + github.com/Masterminds/semver/v3 v3.1.1 + github.com/go-vela/types v0.12.0 + github.com/hashicorp/go-getter v1.5.11 + github.com/joho/godotenv v1.4.0 + github.com/sirupsen/logrus v1.8.1 + github.com/spf13/afero v1.8.2 + github.com/urfave/cli/v2 v2.3.0 +) + +require ( + cloud.google.com/go v0.100.2 // indirect + cloud.google.com/go/compute v1.5.0 // indirect + cloud.google.com/go/iam v0.3.0 // indirect + cloud.google.com/go/storage v1.21.0 // indirect + github.com/aws/aws-sdk-go v1.43.17 // indirect + github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/google/go-cmp v0.5.7 // indirect + github.com/googleapis/gax-go/v2 v2.1.1 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-safetemp v1.0.0 // indirect + github.com/hashicorp/go-version v1.4.0 // indirect + github.com/jmespath/go-jmespath v0.4.0 // indirect + github.com/klauspost/compress v1.15.1 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/ulikunitz/xz v0.5.10 // indirect + go.opencensus.io v0.23.0 // indirect + golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect + golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a // indirect + golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5 // indirect + golang.org/x/text v0.3.7 // indirect + golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect + google.golang.org/api v0.71.0 // indirect + google.golang.org/appengine v1.6.7 // indirect + google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6 // indirect + google.golang.org/grpc v1.45.0 // indirect + google.golang.org/protobuf v1.27.1 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..3f6b54e --- /dev/null +++ b/go.sum @@ -0,0 +1,708 @@ +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.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.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= +cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= +cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= +cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= +cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= +cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= +cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= +cloud.google.com/go v0.100.1/go.mod h1:fs4QogzfH5n2pBXBP9vRiU+eCny7lD2vmFZy79Iuw1U= +cloud.google.com/go v0.100.2 h1:t9Iw5QH5v4XtlEQaCtUY7x6sCABps8sW0acw7e2WQ6Y= +cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= +cloud.google.com/go/compute v1.2.0/go.mod h1:xlogom/6gr8RJGBe7nT2eGsQYAFUbbv8dbC29qE3Xmw= +cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= +cloud.google.com/go/compute v1.5.0 h1:b1zWmYuuHz7gO9kDcM/EpHGr06UgsYNRpNJzI2kFiLM= +cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/iam v0.1.1/go.mod h1:CKqrcnI/suGpybEHxZ7BMehL0oA4LpdyJdUlTl9jVMw= +cloud.google.com/go/iam v0.3.0 h1:exkAomrVUuzx9kWFI1wm3KI0uoDeUFPB4kKGzx6x+Gc= +cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= +cloud.google.com/go/storage v1.21.0 h1:HwnT2u2D309SFDHQII6m18HlrCi3jAXhUMTLOWXYH14= +cloud.google.com/go/storage v1.21.0/go.mod h1:XmRlxkgPjlBONznT2dDUU/5XlpU2OjMnKuqnZI01LAA= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +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/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc= +github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= +github.com/aws/aws-sdk-go v1.43.17 h1:jDPBz1UuTxmyRo0eLgaRiro0fiI1zL7lkscqYxoEDLM= +github.com/aws/aws-sdk-go v1.43.17/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= +github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= +github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= +github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4= +github.com/buildkite/yaml v0.0.0-20181016232759-0caa5f0796e3/go.mod h1:5hCug3EZaHXU3FdCA3gJm0YTNi+V+ooA2qNTiVpky4A= +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/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.1 h1:r/myEWzV9lfsM1tFLgDyu0atFtJ1fXn261LKYj/3DxU= +github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +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/drone/envsubst v1.0.3/go.mod h1:N2jZmlMufstn1KEqvbHjw40h1KyTmnVzHcSc9bFiJ2g= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-vela/types v0.12.0 h1:RnliZ5sZ0ceDRNyjp8o5uPKMIgLF7Gd7JRJWgOLgOPw= +github.com/go-vela/types v0.12.0/go.mod h1:nMZJ/0tb0HO8/AVaJXHuR5slG9UPuP9or+CnkuyFcL4= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/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/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +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/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +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-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.2.1 h1:d8MncMlErDFTwQGBK1xhv026j9kqhvw1Qv9IbWT1VLQ= +github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= +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-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +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/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= +github.com/googleapis/gax-go/v2 v2.1.1 h1:dp3bWCh+PPO1zjRRiCSczJav13sBvG4UhNyVTa1KqdU= +github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= +github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-getter v1.5.11 h1:wioTuNmaBU3IE9vdFtFMcmZWj0QzLc6DYaP6sNe5onY= +github.com/hashicorp/go-getter v1.5.11/go.mod h1:9i48BP6wpWweI/0/+FBjqLrp9S8XtwUGjiu0QkWHEaY= +github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo= +github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I= +github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go-version v1.4.0 h1:aAQzgqIrRKRa7w75CKpbBxYsmUoPjzVm1W59ca1L0J4= +github.com/hashicorp/go-version v1.4.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +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/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg= +github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.11.2/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.15.1 h1:y9FcTHGyrebwfP0ZZqFiaxTaiDnUrGkJkI+f583BL1A= +github.com/klauspost/compress v1.15.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +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/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/microcosm-cc/bluemonday v1.0.17/go.mod h1:Z0r70sCuXHig8YpBzCc5eGHAap2K7e/u082ZUpDRRqM= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= +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/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.8.2 h1:xehSyVa0YnHWsJ49JFljMpg1HX19V6NDZ1fkm1Xznbo= +github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8= +github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M= +github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +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.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +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-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/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-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +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/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/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/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.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +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-20190108225652-1e06a53dbb7e/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-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-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +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-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/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-20200222125558-5a598a2470a0/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/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +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-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a h1:qfl7ob3DIEs3Ml9oLuPwY2N04gymzAW04WsUQHIClgM= +golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +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-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/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-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/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-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5 h1:y/woIyUBFbpQGKS0u1aHF/40WUDnek3fPOyD08H5Vng= +golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/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/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +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-20180917221912-90fa682c2a6e/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-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +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-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-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-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-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/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-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/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-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +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/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +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.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= +google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= +google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= +google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= +google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= +google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= +google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= +google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= +google.golang.org/api v0.64.0/go.mod h1:931CdxA8Rm4t6zqTFGSsgwbAEZ2+GMYurbndwSimebM= +google.golang.org/api v0.66.0/go.mod h1:I1dmXYpX7HGwz/ejRxwQp2qj5bFAz93HiCU1C1oYd9M= +google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= +google.golang.org/api v0.69.0/go.mod h1:boanBiw+h5c3s+tBPgEzLDRHfFLWV0qXxRHz3ws7C80= +google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= +google.golang.org/api v0.71.0 h1:SgWof18M8V2NylsX7bL4fM28j+nFdRopHZbdipaaw20= +google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= +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.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +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-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-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= +google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= +google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211223182754-3ac035c7e7cb/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220111164026-67b88f271998/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220114231437-d2e6a121cae0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220201184016-50beb8ab5c44/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220211171837-173942840c17/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220216160803-4663080d8bc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6 h1:FglFEfyj61zP3c6LgjmVHxYxZWXYul9oiS1EZqD5gLc= +google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.45.0 h1:NEpgUqV3Z+ZjkqMsxMg11IaDrXY4RY6CQukSGK0uI1M= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/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/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/cheggaaa/pb.v1 v1.0.27/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +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.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/version/version.go b/version/version.go new file mode 100644 index 0000000..acd7f6e --- /dev/null +++ b/version/version.go @@ -0,0 +1,65 @@ +// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package version + +import ( + "fmt" + "runtime" + + "github.com/go-vela/types/version" + + "github.com/Masterminds/semver/v3" + + "github.com/sirupsen/logrus" +) + +var ( + // Arch represents the architecture information for the package. + Arch = runtime.GOARCH + // Commit represents the git commit information for the package. + Commit string + // Compiler represents the compiler information for the package. + Compiler = runtime.Compiler + // Date represents the build date information for the package. + Date string + // Go represents the golang version information for the package. + Go = runtime.Version() + // OS represents the operating system information for the package. + OS = runtime.GOOS + // Tag represents the git tag information for the package. + Tag string +) + +// New creates a new version object for Vela that is used throughout the application. +func New() *version.Version { + // check if a semantic tag was provided + if len(Tag) == 0 { + logrus.Warning("no semantic tag provided - defaulting to v0.0.0") + + // set a fallback default for the tag + Tag = "v0.0.0" + } + + v, err := semver.NewVersion(Tag) + if err != nil { + fmt.Println(fmt.Errorf("unable to parse semantic version for %s: %w", Tag, err)) + } + + return &version.Version{ + Canonical: Tag, + Major: v.Major(), + Minor: v.Minor(), + Patch: v.Patch(), + PreRelease: v.Prerelease(), + Metadata: version.Metadata{ + Architecture: Arch, + BuildDate: Date, + Compiler: Compiler, + GitCommit: Commit, + GoVersion: Go, + OperatingSystem: OS, + }, + } +}