From 98279da27adbe4db0fa2ba4d6ce2e79586468a98 Mon Sep 17 00:00:00 2001 From: Christie Wilson Date: Thu, 25 Mar 2021 15:10:09 -0400 Subject: [PATCH] =?UTF-8?q?Add=20custom=20task=20that=20runs=20a=20Pipelin?= =?UTF-8?q?e=20as=20a=20TaskRun=20=F0=9F=8D=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds a custom task that allows user to run simple sequential Pipelines as one TaskRun - which means the Pipeline can refer to multiple Tasks but run on only one pod. It only supports a subset of Pipeline functionality (more detail on what and why in the README) but is enough that folks can do a lot of what they would have previously used PipelineResources for, e.g. doing a git clone and then doing something with the data, in the same pod, and emit results such as the exact commit sha used. Next steps will be to expand the functionality supported, get feedback, and if the feedback is good, promote this to a top level Pipeline API feature. Experimental project proposal: https://github.com/tektoncd/community/issues/447 --- pipeline-to-taskrun/OWNERS | 6 + pipeline-to-taskrun/README.md | 438 +++++ pipeline-to-taskrun/cmd/controller/main.go | 27 + pipeline-to-taskrun/config/100-namespace.yaml | 21 + .../config/200-serviceaccount.yaml | 23 + .../config/201-clusterrole.yaml | 46 + pipeline-to-taskrun/config/201-role.yaml | 33 + .../config/201-rolebinding.yaml | 31 + .../config/202-clusterrolebinding.yaml | 30 + .../config/400-controller-service.yaml | 41 + .../config/500-controller.yaml | 66 + .../config/config-logging.yaml | 53 + .../examples/clone-test-upload.yaml | 52 + .../pipeline-taskrun-pipelinerun.yaml | 56 + .../examples/pipeline-taskrun-run.yaml | 26 + pipeline-to-taskrun/examples/pvc.yaml | 10 + pipeline-to-taskrun/examples/run-pvc.yaml | 11 + pipeline-to-taskrun/go.mod | 37 + pipeline-to-taskrun/go.sum | 1478 +++++++++++++++++ .../pipelinetotaskrun/controller.go | 74 + .../pkg/reconciler/pipelinetotaskrun/fetch.go | 72 + .../reconciler/pipelinetotaskrun/ordering.go | 74 + .../pipelinetotaskrun/ordering_test.go | 154 ++ .../pipelinetotaskrun/pipelinetotaskrun.go | 257 +++ .../pipelinetotaskrun_test.go | 1009 +++++++++++ .../pkg/reconciler/pipelinetotaskrun/steps.go | 201 +++ .../pipelinetotaskrun/steps_test.go | 446 +++++ .../reconciler/pipelinetotaskrun/taskrun.go | 59 + .../testdata/expected-taskrun.yaml | 242 +++ .../testdata/gcs-upload.yaml | 59 + .../pipelinetotaskrun/testdata/git-clone.yaml | 134 ++ .../pipelinetotaskrun/testdata/go-test.yaml | 59 + .../reconciler/pipelinetotaskrun/validate.go | 137 ++ .../pipelinetotaskrun/workspaces.go | 39 + .../pipelinetotaskrun/workspaces_test.go | 93 ++ pipeline-to-taskrun/test/README.md | 4 + pipeline-to-taskrun/test/controller.go | 309 ++++ pipeline-to-taskrun/test/presubmit-tests.sh | 66 + pipeline-to-taskrun/test/yaml.go | 76 + 39 files changed, 6049 insertions(+) create mode 100644 pipeline-to-taskrun/OWNERS create mode 100644 pipeline-to-taskrun/README.md create mode 100644 pipeline-to-taskrun/cmd/controller/main.go create mode 100644 pipeline-to-taskrun/config/100-namespace.yaml create mode 100644 pipeline-to-taskrun/config/200-serviceaccount.yaml create mode 100644 pipeline-to-taskrun/config/201-clusterrole.yaml create mode 100644 pipeline-to-taskrun/config/201-role.yaml create mode 100644 pipeline-to-taskrun/config/201-rolebinding.yaml create mode 100644 pipeline-to-taskrun/config/202-clusterrolebinding.yaml create mode 100644 pipeline-to-taskrun/config/400-controller-service.yaml create mode 100644 pipeline-to-taskrun/config/500-controller.yaml create mode 100644 pipeline-to-taskrun/config/config-logging.yaml create mode 100644 pipeline-to-taskrun/examples/clone-test-upload.yaml create mode 100644 pipeline-to-taskrun/examples/pipeline-taskrun-pipelinerun.yaml create mode 100644 pipeline-to-taskrun/examples/pipeline-taskrun-run.yaml create mode 100644 pipeline-to-taskrun/examples/pvc.yaml create mode 100644 pipeline-to-taskrun/examples/run-pvc.yaml create mode 100644 pipeline-to-taskrun/go.mod create mode 100644 pipeline-to-taskrun/go.sum create mode 100644 pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/controller.go create mode 100644 pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/fetch.go create mode 100644 pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/ordering.go create mode 100644 pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/ordering_test.go create mode 100644 pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/pipelinetotaskrun.go create mode 100644 pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/pipelinetotaskrun_test.go create mode 100644 pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/steps.go create mode 100644 pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/steps_test.go create mode 100644 pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/taskrun.go create mode 100644 pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/testdata/expected-taskrun.yaml create mode 100644 pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/testdata/gcs-upload.yaml create mode 100644 pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/testdata/git-clone.yaml create mode 100644 pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/testdata/go-test.yaml create mode 100644 pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/validate.go create mode 100644 pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/workspaces.go create mode 100644 pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/workspaces_test.go create mode 100644 pipeline-to-taskrun/test/README.md create mode 100644 pipeline-to-taskrun/test/controller.go create mode 100755 pipeline-to-taskrun/test/presubmit-tests.sh create mode 100644 pipeline-to-taskrun/test/yaml.go diff --git a/pipeline-to-taskrun/OWNERS b/pipeline-to-taskrun/OWNERS new file mode 100644 index 000000000..293ed3d05 --- /dev/null +++ b/pipeline-to-taskrun/OWNERS @@ -0,0 +1,6 @@ +# The OWNERS file is used by prow to automatically merge approved PRs. + +approvers: +- bobcatfish +- jerop +- wlynch diff --git a/pipeline-to-taskrun/README.md b/pipeline-to-taskrun/README.md new file mode 100644 index 000000000..7b7c52af4 --- /dev/null +++ b/pipeline-to-taskrun/README.md @@ -0,0 +1,438 @@ +# Pipeline to TaskRun + +This is a controller that enables an experimental [custom task](https://github.com/tektoncd/pipeline/blob/main/docs/runs.md) +that will allow you to execute a Pipeline (with [limited features](#supported-pipeline-features)) via a TaskRun, enabling you to +run a Pipeline in a pod ([TEP-0044](https://github.com/tektoncd/community/blob/main/teps/0044-decouple-task-composition-from-scheduling.md)). + +* [Install](#install) +* [Usage](#usage) + * [Invoke via a `Run`](#invoke-via-a-run) + * [Invoke from a `Pipeline`](#invoke-from-a-pipeline) +* [Supported Pipeline Features](#supported-pipeline-features) +* [Examples](#examples) +* [Tests](#tests) + +## Usage + +### Invoke via a `Run` + +To execute a Pipeline via a TaskRun using this custom task, create a [`Run`](https://github.com/tektoncd/pipeline/blob/master/docs/runs.md) +with: + +* `apiVersion: tekton.dev/v1alpha1` +* `kind: PipelineToTaskRun` +* `name: PipelineName` - Where `PipelineName` is the name of the Pipeline you'd like to run +* Any required runtime information (e.g. params), complete list below + +The full list of supported fields: + +- [`apiVersion`][kubernetes-overview] - Specifies the API version, `tekton.dev/v1alpha1` +- [`kind`][kubernetes-overview] - Identifies this resource object as a `Run` object +- [`metadata`][kubernetes-overview] - Specifies the metadata that uniquely identifies the `Run`, such as a `name` +- [`spec`][kubernetes-overview] - Specifies the configuration for the `Run` + - [`ref`][kubernetes-overview] - Specifies the Pipeline to TaskRun `Custom Task` + - [`apiVersion`][kubernetes-overview] - Specifies the API version, `tekton.dev/v1alpha1` + - [`kind`][kubernetes-overview] - Identifies this resource object as a `PipelineToTaskRun` object + - [`name`][kubernetes-overview] - Identifies the `Pipeline` object to be executed + - Optional: + - [`params`](https://github.com/tektoncd/pipeline/blob/main/docs/pipelineruns.md#specifying-parameters) - Specifies values for + [pipeline level params](https://github.com/tektoncd/pipeline/blob/main/docs/pipelines.md#specifying-workspaces) + - [`serviceAccountName`](https://github.com/tektoncd/pipeline/blob/main/docs/pipelineruns.md#specifying-custom-serviceaccount-credentials) - Specifies a `ServiceAccount` to use for the TaskRun. + - [`workspaces`](https://github.com/tektoncd/pipeline/blob/main/docs/pipelineruns.md#specifying-workspaces) - Specifies the physical volumes to use for + [the workspaces required by the Pipeline](https://github.com/tektoncd/pipeline/blob/main/docs/pipelines.md#specifying-workspaces) + +See [pipeline-taskrun-run.yaml](examples/pipeline-taskrun-run.yaml) for a complete example +([the examples section shows you how to try it out](#examples). + +### Invoke from a `Pipeline` + +You can use this custom task to run a sub pipeline (similar to [pipeline in a pipeline](../pipelines-in-pipelines)) but +within one TaskRun. To do this [specify the PipelineToTaskRun custom task](https://github.com/tektoncd/pipeline/blob/main/docs/pipelines.md#specifying-the-target-custom-task): + +* `apiVersion: tekton.dev/v1alpha1` +* `kind: PipelineToTaskRun` +* `name: PipelineName` - Where `PipelineName` is the name of the Pipeline you'd like to run + +You can provide the following runtime values in the same way as you would for a +[task in a pipeline](https://github.com/tektoncd/pipeline/blob/main/docs/pipelines.md#adding-tasks-to-the-pipeline): +- `params` - Specifies values for [pipeline level params](https://github.com/tektoncd/pipeline/blob/main/docs/pipelines.md#specifying-workspaces) +- [`workspaces`](https://github.com/tektoncd/pipeline/blob/main/docs/pipelines.md#specifying-workspaces) - Specifies the physical volumes to use for + [the workspaces required by the Pipeline](https://github.com/tektoncd/pipeline/blob/main/docs/pipelines.md#specifying-workspaces) + +See [pipeline-taskrun-pipelinerun.yaml](examples/pipeline-taskrun-pipelinerun.yaml) for a complete example +([the examples section shows you how to try it out](#examples). + +## Supported Pipeline Features + +Since this custom task works by executing a Pipeline as a [TaskRun](https://github.com/tektoncd/pipeline/blob/main/docs/taskruns.md) +it can only support a subset of Pipeline features. + +Currently supported features: + +* Sequential tasks (specified using [`runAfter`](https://github.com/tektoncd/pipeline/blob/main/docs/pipelines.md#using-the-runafter-parameter)) +* [Params](https://github.com/tektoncd/pipeline/blob/main/docs/pipelines.md#specifying-parameters) +* [Workspaces](https://github.com/tektoncd/pipeline/blob/main/docs/pipelines.md#specifying-workspaces) + +### Potential future features + +These features may be added in the future: + +* [Array params](https://github.com/tektoncd/pipeline/blob/main/docs/tasks.md#specifying-parameters) - since we do a lot + of variable renaming and replacement, array params were left out of the initial version +* Passing workspace paths and params via pipeline tasks - Since [all uses of params are namespaced](#params) + and [workspaces are remapped](#workspaces), all uses of these via variable replacement must be updated. This + has been applied to the Task definitions, but not to the pipeline tasks where they can also be used + via param values. +* [Pipeline level results](https://github.com/tektoncd/pipeline/blob/main/docs/pipelines.md#emitting-results-from-a-pipeline) +* Exposing Task results as Pipeline level results +* [Passing results between tasks](https://github.com/tektoncd/pipeline/blob/main/docs/pipelines.md#passing-one-tasks-results-into-the-parameters-or-whenexpressions-of-another) +* [Sidecars](https://github.com/tektoncd/pipeline/blob/main/docs/tasks.md#specifying-sidecars) + (if we support this, all would have to start up simultaneously which may not be the desired behavior) +* Workspace features: + * [mountPaths](https://github.com/tektoncd/pipeline/blob/main/docs/workspaces.md#using-workspaces-in-tasks) + * [subPaths](https://github.com/tektoncd/pipeline/blob/main/docs/workspaces.md#using-workspaces-in-pipelines) + * [optional](https://github.com/tektoncd/pipeline/blob/main/docs/workspaces.md#optional-workspaces) + * [readOnly](https://github.com/tektoncd/pipeline/blob/main/docs/workspaces.md#using-workspaces-in-tasks) + * [isolated](https://github.com/tektoncd/pipeline/blob/main/docs/workspaces.md#isolating-workspaces-to-specific-steps-or-sidecars) + * In addition further thought will have to be given to support workspaces that combine + [mountPaths](https://github.com/tektoncd/pipeline/blob/main/docs/workspaces.md#using-workspaces-in-tasks) and + or [Pipeline task level subpaths](https://github.com/tektoncd/pipeline/blob/main/docs/workspaces.md#using-workspaces-in-pipelines) with + [volumeclaimtemplates](https://github.com/tektoncd/pipeline/blob/main/docs/workspaces.md#volumeclaimtemplate) + (see [tektoncd/pipeline#3440](https://github.com/tektoncd/pipeline/issues/3440) - it is not possible to have two + different workspace declarations in the taskspec which are mapped to one volumeClaimTemplate at runtime) +* Specifying Tasks in a Pipeline via [Bundles](https://github.com/tektoncd/pipeline/blob/main/docs/tekton-bundle-contracts.md) +* These fields would be easy to support one of, but it's not clear how to handle cases where more than one task declares them (since in the taskrun they would apply to the entire task): + * [step templates](https://github.com/tektoncd/pipeline/blob/main/docs/tasks.md#specifying-a-step-template) + * [timeout](https://github.com/tektoncd/pipeline/blob/main/docs/pipelines.md#configuring-the-failure-timeout) + * [retries](https://github.com/tektoncd/pipeline/blob/main/docs/pipelines.md#using-the-retries-parameter) +* [Volumes and volume mounts](https://github.com/tektoncd/pipeline/blob/main/docs/tasks.md#specifying-volumes) - + still [not clear that we really need these in addition to workspaces](https://github.com/tektoncd/pipeline/issues/2058) +* Contextual variable replacement that assumes a PipelineRun, for example [`context.pipelineRun.name`](https://github.com/tektoncd/pipeline/blob/main/docs/variables.md#variables-available-in-a-pipeline) + +### Features unlikely to be supported + +These features are not supported by TaskRuns so this custom task is unlikely to support them (unless the design +is changed substantially, [see "What comes next?" in the proposal](https://github.com/tektoncd/community/issues/447)): + +* [Parallel tasks](https://github.com/tektoncd/pipeline/blob/main/docs/pipelines.md#configuring-the-task-execution-order) +* [When expressions](https://github.com/tektoncd/pipeline/blob/main/docs/pipelines.md#guard-task-execution-using-whenexpressions) + (and [Conditions](https://github.com/tektoncd/pipeline/blob/main/docs/pipelines.md#guard-task-execution-using-conditions)) +* [Custom tasks](https://github.com/tektoncd/pipeline/blob/main/docs/pipelines.md#using-custom-tasks) +* [Finally tasks](https://github.com/tektoncd/pipeline/blob/main/docs/pipelines.md#adding-finally-to-the-pipeline) + (maybe if we allow step failure ([TEP-0040](https://github.com/tektoncd/community/blob/main/teps/0040-ignore-step-errors.md)) + we can use that to make finally steps work??) +* PipelineResources - both because of + [questions around the future of the feature](https://github.com/tektoncd/pipeline/blob/main/docs/resources.md#why-arent-pipelineresources-in-beta) + and because TaskRuns have no [linking via from](https://github.com/tektoncd/pipeline/blob/main/docs/pipelines.md#using-the-from-parameter) + +## How does this work? + +This custom task will take a Pipeline (using [Supported Pipeline Features](#supported-pipeline-features)) and +run in one TaskRun by combining the steps from each Task into one Task spec embedded in the TaskRun. +But how does this actually work, considering that there can be collisions and duplication between names +of params, steps, workspaces, etc.? + +### Params + +The custom task will add params of each of the Pipeline's Tasks to the resulting task spec. To deal with collisions, +each param is namespaced by prepending it with the name of the pipeline task it came from. + +For example, given the following pipeline Task: + +```yaml + - name: grab-source + taskRef: + name: git-clone + params: + - name: url + value: $(params.git-url) +``` + +Using a Task which declares this params: + +```yaml + params: + - name: url + description: git url to clone + type: string +``` + +The resulting Task spec in the TaskRun that executes the Pipeline will declare: + +```yaml + params: + - description: git url to clone + name: grab-source-url + type: string +``` + +Fields in the Task which used variable replacements for these params will be updated to use the new +name, for example this portion of the step's script: + +```yaml + /ko-app/git-init \ + -url "$(params.url)" \ +``` + +Will become: + +```yaml + /ko-app/git-init \ + -url "$(params.grab-source-url)" \ +``` + +### Steps + +The custom task will add the step of each of the Pipeline's Tasks to the resulting task spec. To deal with collisions, +each step is namespaced by prepending it with the name of the pipeline task it came from. If the step +has no name, it will be left unnamed. + +For example, given the following pipeline Task: + +```yaml + - name: grab-source + taskRef: + name: git-clone + params: + - name: url + value: $(params.git-url) +``` + +Which contains this step: + +```yaml + steps: + - name: clone +``` + +The step in the Task spec of the resulting TaskRun that executes the Pipeline will contain this step: + +```yaml + steps: + - name: grab-source-clone +``` + +_What if the resulting step name is too long to be a valid container? It will be truncated to the maximum length +of 63 characters._ + +### Workspaces + +Workspaces that are declared in a Pipeline and passed to Tasks must be remapped to make sense in the context +of a TaskRun. This means removing a layer of Workspace mapping: + +* **PipelineRun**: In the context of a PipelineRun (the normal mode of Pipeline execution), + there will be the following layers of mapping: + * A Task declares Workspaces it needs + * A Pipeline declares Workspace it needs + * In each Pipeline Task, the Pipeline will map from its declared Workspaces to the Workspaces the Task needs + * In the PipelineRun, actual volumes/secrets/etc will be provided for each Workspace the Pipeline declares +* **Task**: In the Context of a TaskRun (which the Pipeline will be mapped to), there will be the following + layers of mapping: + * A Task declares Workspaces it needs + * In the TaskRun, actual volumes/secrets/etc will be provided for each Workspace the Pipeline declares + +So in order to map a Pipeline's execution into a TaskRun, we need to remove the intermediary layer of the +Workspaces declared by the Pipeline and mapped to each Pipeline Task. + +For example, given these two Tasks's workspace declarations: + +```yaml +apiVersion: tekton.dev/v1beta1 +kind: Task +metadata: + name: git-clone + workspaces: + - name: output + steps: + - name: clone + image: some-git-image + script: |- + echo $(workspaces.output.path) +--- +apiVersion: tekton.dev/v1beta1 +kind: Task +metadata: + name: gcs-upload + workspaces: + - name: credentials + - name: source + steps: + - name: upload + image: some-gsutil-image + script: |- + echo $(workspaces.source.path) + echo $(workspaces.credentials.path) +``` + +Say that a Pipeline maps these workspaces like this: + +```yaml +spec: + workspaces: + - name: where-it-all-happens + - name: gcs-creds + tasks: + - name: grab-source + taskRef: + name: git-clone + workspaces: + - name: output + workspace: where-it-all-happens + - name: upload-results + taskRef: + name: gcs-upload + workspaces: + - name: source + workspace: where-it-all-happens + - name: credentials + workspace: gcs-creds +``` + +And finally in the custom task Run, the workspaces are defined like this: + +```yaml + workspaces: + - name: where-it-all-happens + volumeClaimTemplate: + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + - name: gcs-creds + secret: + secretName: mikey +``` + +What we ultimately have is 1 workspace that is mapping to a secret called `mikey` and +2 workspaces mapping to a persistent volume claim template - indicating that ultimately +both of those workspaces are intended to use the same volume. + +To ensure that this intent is respected, instead of declaring 3 different workspaces in our +generated TaskRun, we will declare just one workspace which will be bound to the `volumeClaimTemplate` +and we will rewrite the Tasks to use this workspace. + +For the above example, the resulting TaskRun will look like this: + +```yaml +spec: + taskSpec: + workspaces: + - name: where-it-all-happens + - name: gcs-creds + steps: + - name: clone + image: some-git-image + script: |- + echo $(workspaces.where-it-all-happens.path) + - name: upload + image: some-gsutil-image + script: |- + echo $(workspaces.where-it-all-happens.path) + echo $(workspaces.gcs-creds.path) + workspaces: + - name: where-it-all-happens + volumeClaimTemplate: + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + - name: gcs-creds + secret: + secretName: mikey +``` + +## Install + +1. Install and configure [`ko`](https://github.com/google/ko). + +2. Install with `ko`: +``` +ko apply -f config/ +``` + +This will build and install the `Pipeline-To-TaskRun Controller` on your cluster, in the namespace `tekton-pipeline-to-taskrun`. + +```commandline +$ k get pods -n tekton-pipeline-to-taskrun + +NAME READY STATUS RESTARTS AGE +pipeline-to-taskrun-controller-654bdc4cc8-7bvvn 1/1 Running 0 3m4s +``` + +To look at the logs: + +``` +kubectl -n tekton-pipeline-to-taskrun logs $(kubectl -n tekton-pipeline-to-taskrun get pods -l app=pipeline-to-taskrun-controller -o name) +``` + +## Examples + +The example pipeline [clone-test-upload.yaml](examples/clone-test-upload.yaml) is a Pipeline that will: +1. Download from git +2. Run `go test` and capture the output +3. Upload the output to GCS + +### Requirements + +* [Enable custom tasks](#enable-custom-tasks-in-tekton-pipelines) +* [Get GCS credentials](#gcs-credentials) + +#### Enable custom tasks in Tekton Pipelines + +To run the example that invokes the custom task from a Pipeline +([examples/pipeline-taskrun-pipelinerun.yaml](examples/pipeline-taskrun-pipelinerun.yaml)) you must enable custom +tasks in Tekton Pipelines +[by setting `enable-custom-tasks` to true](https://github.com/tektoncd/pipeline/blob/main/docs/install.md#customizing-the-pipelines-controller-behavior). + +#### GCS Credentials + +In order to run (3) you will need to grab GCS credentials and store them in secret. The Pipeline expects a secret to be +provided via the workspaces `gcs-creds` +[at the path `service-account.json`](https://github.com/tektoncd/catalog/tree/main/task/gcs-upload/0.1#parameters) that +corresponds to a service account that has +[bucket write permissions (e.g. storage object admin)](https://cloud.google.com/storage/docs/access-control/iam-permissions). + +### Running + +```bash +# Install the Tasks from the catalog that we'll be using in our Pipeline +tkn hub install task git-clone +tkn hub install task golang-test +tkn hub install task gcs-upload + +# Install the Pipeline that we'll be running +kubectl apply -f examples/clone-test-upload.yaml + +# To make sure everything is working, you can create the equivalent PipelineRun +# In this example we're using a secret called `mikey` to upload to the bucket `christies-empty-bucket` +# and it will run the unit tests for tektoncd/chains (as a random example with a quick test suite :D) +tkn pipeline start clone-test-upload \ + -p git-url="https://github.com/tektoncd/chains" \ + -p package="github.com/tektoncd/chains/pkg" \ + -p packages="./pkg/..." \ + -p gcs-location="gs://christies-empty-bucket" \ + -w name=where-it-all-happens,volumeClaimTemplateFile=examples/pvc.yaml \ + -w name=gcs-creds,secret=mikey + +# make the pvc we'll be using +kubectl create -f examples/run-pvc.yaml + +# run as a Run (using the same config as the `tkn pipeline start` above) +kubectl create -f examples/pipeline-taskrun-run.yaml + +# run as a custom task invoked from another pipeline (using the same config as the `tkn pipeline start` above) +kubectl create -f examples/pipeline-taskrun-pipelinerun.yaml +``` + +## Tests + +``` +go test ./pkg/... +``` + +[kubernetes-overview]: +https://kubernetes.io/docs/concepts/overview/working-with-objects/kubernetes-objects/#required-fields \ No newline at end of file diff --git a/pipeline-to-taskrun/cmd/controller/main.go b/pipeline-to-taskrun/cmd/controller/main.go new file mode 100644 index 000000000..ba954a5d3 --- /dev/null +++ b/pipeline-to-taskrun/cmd/controller/main.go @@ -0,0 +1,27 @@ +/* +Copyright 2021 The Tekton Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "github.com/tektoncd/experimental/pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun" + //"github.com/tektoncd/experimental/pipeline-in-a-pod/pkg/reconciler/pipelinetotaskrun" + "knative.dev/pkg/injection/sharedmain" +) + +func main() { + sharedmain.Main(pipelinetotaskrun.ControllerName, pipelinetotaskrun.NewController) +} diff --git a/pipeline-to-taskrun/config/100-namespace.yaml b/pipeline-to-taskrun/config/100-namespace.yaml new file mode 100644 index 000000000..888ccc01e --- /dev/null +++ b/pipeline-to-taskrun/config/100-namespace.yaml @@ -0,0 +1,21 @@ +# Copyright 2021 The Tekton Authors +# +# 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 +# +# https://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. + +apiVersion: v1 +kind: Namespace +metadata: + name: tekton-pipeline-to-taskrun + labels: + app.kubernetes.io/instance: default + app.kubernetes.io/part-of: tekton-pipeline-to-taskrun diff --git a/pipeline-to-taskrun/config/200-serviceaccount.yaml b/pipeline-to-taskrun/config/200-serviceaccount.yaml new file mode 100644 index 000000000..f8ccaadee --- /dev/null +++ b/pipeline-to-taskrun/config/200-serviceaccount.yaml @@ -0,0 +1,23 @@ +# Copyright 2021 The Tekton Authors +# +# 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 +# +# https://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. + +apiVersion: v1 +kind: ServiceAccount +metadata: + name: pipeline-to-taskrun-controller + namespace: tekton-pipeline-to-taskrun + labels: + app.kubernetes.io/component: pipeline-to-taskrun-controller + app.kubernetes.io/instance: default + app.kubernetes.io/part-of: tekton-pipeline-to-taskrun diff --git a/pipeline-to-taskrun/config/201-clusterrole.yaml b/pipeline-to-taskrun/config/201-clusterrole.yaml new file mode 100644 index 000000000..70127aeb8 --- /dev/null +++ b/pipeline-to-taskrun/config/201-clusterrole.yaml @@ -0,0 +1,46 @@ +# Copyright 2021 The Tekton Authors +# +# 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 +# +# https://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. + +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: pipeline-to-taskrun-controller-cluster-access + labels: + app.kubernetes.io/component: pipeline-to-taskrun-controller + app.kubernetes.io/instance: default + app.kubernetes.io/part-of: tekton-pipeline-to-taskrun +rules: + # Controller needs cluster access to all Run CRs. + - apiGroups: ["tekton.dev"] + resources: ["runs", "taskruns"] + verbs: ["get", "list", "create", "update", "delete", "patch", "watch"] + - apiGroups: ["tekton.dev"] + resources: ["pipelines", "tasks"] + verbs: ["get", "list"] + - apiGroups: ["tekton.dev"] + resources: ["runs/finalizers"] + verbs: ["get", "list", "create", "update", "delete", "patch", "watch"] + - apiGroups: ["tekton.dev"] + resources: ["runs/status", "pipelineruns/status"] + verbs: ["get", "list", "create", "update", "delete", "patch", "watch"] + + # Controller needs cluster access to leases for leader election. + - apiGroups: ["coordination.k8s.io"] + resources: ["leases"] + verbs: ["get", "list", "create", "update", "delete", "patch", "watch"] + + # Controller needs permission to emit events associated with Run CRs. + - apiGroups: [""] + resources: ["events"] + verbs: ["get", "list", "create", "update", "delete", "patch", "watch"] diff --git a/pipeline-to-taskrun/config/201-role.yaml b/pipeline-to-taskrun/config/201-role.yaml new file mode 100644 index 000000000..002674173 --- /dev/null +++ b/pipeline-to-taskrun/config/201-role.yaml @@ -0,0 +1,33 @@ +# Copyright 2021 The Tekton Authors +# +# 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 +# +# https://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. + +kind: Role +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: pipeline-to-taskrun-controller + namespace: tekton-pipeline-to-taskrun + labels: + app.kubernetes.io/component: pipeline-to-taskrun-controller + app.kubernetes.io/instance: default + app.kubernetes.io/part-of: tekton-pipeline-to-taskrun +rules: + - apiGroups: [""] + resources: ["configmaps"] + verbs: ["list", "watch"] + + # The controller needs access to these configmaps for logging information and runtime configuration. + - apiGroups: [""] + resources: ["configmaps"] + verbs: ["get"] + resourceNames: ["config-logging", "config-observability", "config-leader-election"] diff --git a/pipeline-to-taskrun/config/201-rolebinding.yaml b/pipeline-to-taskrun/config/201-rolebinding.yaml new file mode 100644 index 000000000..6bdf9505c --- /dev/null +++ b/pipeline-to-taskrun/config/201-rolebinding.yaml @@ -0,0 +1,31 @@ +# Copyright 2021 The Tekton Authors +# +# 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 +# +# https://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. + +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: RoleBinding +metadata: + name: pipeline-to-taskrun-controller + namespace: tekton-pipeline-to-taskrun + labels: + app.kubernetes.io/component: pipeline-to-taskrun-controller + app.kubernetes.io/instance: default + app.kubernetes.io/part-of: tekton-pipeline-to-taskrun +subjects: + - kind: ServiceAccount + name: pipeline-to-taskrun-controller + namespace: tekton-pipeline-to-taskrun +roleRef: + kind: Role + name: pipeline-to-taskrun-controller + apiGroup: rbac.authorization.k8s.io diff --git a/pipeline-to-taskrun/config/202-clusterrolebinding.yaml b/pipeline-to-taskrun/config/202-clusterrolebinding.yaml new file mode 100644 index 000000000..b00fdde1f --- /dev/null +++ b/pipeline-to-taskrun/config/202-clusterrolebinding.yaml @@ -0,0 +1,30 @@ +# Copyright 2021 The Tekton Authors +# +# 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 +# +# https://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. + +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRoleBinding +metadata: + name: pipeline-to-taskrun-controller-cluster-access + labels: + app.kubernetes.io/component: pipeline-to-taskrun-controller + app.kubernetes.io/instance: default + app.kubernetes.io/part-of: tekton-pipeline-to-taskrun +subjects: + - kind: ServiceAccount + name: pipeline-to-taskrun-controller + namespace: tekton-pipeline-to-taskrun +roleRef: + kind: ClusterRole + name: pipeline-to-taskrun-controller-cluster-access + apiGroup: rbac.authorization.k8s.io diff --git a/pipeline-to-taskrun/config/400-controller-service.yaml b/pipeline-to-taskrun/config/400-controller-service.yaml new file mode 100644 index 000000000..b2a207ce5 --- /dev/null +++ b/pipeline-to-taskrun/config/400-controller-service.yaml @@ -0,0 +1,41 @@ +# Copyright 2021 The Tekton Authors +# +# 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 +# +# https://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. + +apiVersion: v1 +kind: Service +metadata: + labels: + app.kubernetes.io/name: pipeline-to-taskrun-controller + app.kubernetes.io/component: pipeline-to-taskrun-controller + app.kubernetes.io/instance: default + app.kubernetes.io/version: devel + app.kubernetes.io/part-of: tekton-pipeline-to-taskrun + # tekton.dev/release value replaced with inputs.params.versionTag in pipeline/tekton/publish.yaml + pipeline.tekton.dev/release: "devel" + # labels below are related to istio and should not be used for resource lookup + app: pipeline-to-taskrun-controller + version: "devel" + name: pipeline-to-taskrun-controller + namespace: tekton-pipeline-to-taskrun +spec: + ports: + - name: http-metrics + port: 9090 + protocol: TCP + targetPort: 9090 + selector: + app.kubernetes.io/name: pipeline-to-taskrun-controller + app.kubernetes.io/component: pipeline-to-taskrun-controller + app.kubernetes.io/instance: default + app.kubernetes.io/part-of: tekton-pipeline-to-taskrun diff --git a/pipeline-to-taskrun/config/500-controller.yaml b/pipeline-to-taskrun/config/500-controller.yaml new file mode 100644 index 000000000..b502a9776 --- /dev/null +++ b/pipeline-to-taskrun/config/500-controller.yaml @@ -0,0 +1,66 @@ +# Copyright 2021 The Tekton Authors +# +# 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 +# +# https://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 + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: pipeline-to-taskrun-controller + namespace: tekton-pipeline-to-taskrun + labels: + app.kubernetes.io/name: pipeline-to-taskrun-controller + app.kubernetes.io/component: pipeline-to-taskrun-controller + app.kubernetes.io/instance: default + app.kubernetes.io/version: devel + app.kubernetes.io/part-of: tekton-pipeline-to-taskrun +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: pipeline-to-taskrun-controller + app.kubernetes.io/component: pipeline-to-taskrun-controller + app.kubernetes.io/instance: default + app.kubernetes.io/part-of: pip + template: + metadata: + annotations: + cluster-autoscaler.kubernetes.io/safe-to-evict: "false" + labels: + app.kubernetes.io/name: pipeline-to-taskrun-controller + app.kubernetes.io/component: pipeline-to-taskrun-controller + app.kubernetes.io/instance: default + app.kubernetes.io/version: devel + app.kubernetes.io/part-of: pip + app: pipeline-to-taskrun-controller + spec: + serviceAccountName: pipeline-to-taskrun-controller + containers: + - name: pipeline-to-taskrun-controller + image: ko://github.com/tektoncd/experimental/pipeline-to-taskrun/cmd/controller + volumeMounts: + - name: config-logging + mountPath: /etc/config-logging + env: + - name: SYSTEM_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + # If you are changing these names, you will also need to update + # the controller's Role in 200-role.yaml to include the new + # values in the "configmaps" "get" rule. + - name: CONFIG_LOGGING_NAME + value: config-logging + volumes: + - name: config-logging + configMap: + name: config-logging diff --git a/pipeline-to-taskrun/config/config-logging.yaml b/pipeline-to-taskrun/config/config-logging.yaml new file mode 100644 index 000000000..d74ae96ab --- /dev/null +++ b/pipeline-to-taskrun/config/config-logging.yaml @@ -0,0 +1,53 @@ +# Copyright 2021 The Tekton Authors +# +# 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 +# +# https://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 + +apiVersion: v1 +kind: ConfigMap +metadata: + name: config-logging + namespace: tekton-pipeline-to-taskrun + labels: + app.kubernetes.io/instance: default + app.kubernetes.io/part-of: tekton-pipeline-to-taskrun +data: + # Common configuration for all knative codebase + zap-logger-config: | + { + "level": "info", + "development": false, + "sampling": { + "initial": 100, + "thereafter": 100 + }, + "outputPaths": ["stdout"], + "errorOutputPaths": ["stderr"], + "encoding": "json", + "encoderConfig": { + "timeKey": "ts", + "levelKey": "level", + "nameKey": "logger", + "callerKey": "caller", + "messageKey": "msg", + "stacktraceKey": "stacktrace", + "lineEnding": "", + "levelEncoder": "", + "timeEncoder": "", + "durationEncoder": "", + "callerEncoder": "" + } + } + + # Log level overrides + loglevel.controller: "info" + loglevel.webhook: "info" diff --git a/pipeline-to-taskrun/examples/clone-test-upload.yaml b/pipeline-to-taskrun/examples/clone-test-upload.yaml new file mode 100644 index 000000000..b075f6892 --- /dev/null +++ b/pipeline-to-taskrun/examples/clone-test-upload.yaml @@ -0,0 +1,52 @@ +apiVersion: tekton.dev/v1beta1 +kind: Pipeline +metadata: + name: clone-test-upload +spec: + params: + - name: git-url + - name: package + - name: packages + - name: gcs-location + workspaces: + - name: where-it-all-happens + - name: gcs-creds + tasks: + - name: grab-source + taskRef: + name: git-clone + params: + - name: url + value: $(params.git-url) + workspaces: + - name: output + workspace: where-it-all-happens + - name: run-tests + runAfter: [grab-source] + taskRef: + name: golang-test + params: + - name: package + value: $(params.package) + - name: packages + # HACKS to write the test results to a file + # alternatives: write a Task that writes output to a file, capture stdout + # (in the pipeline), and/or capture logs + value: "$(params.packages) > $(workspaces.source.path)/test-results" + workspaces: + - name: source + workspace: where-it-all-happens + - name: upload-results + runAfter: [run-tests] + taskRef: + name: gcs-upload + workspaces: + - name: source + workspace: where-it-all-happens + - name: credentials + workspace: gcs-creds + params: + - name: path + value: "test-results" + - name: location + value: $(params.gcs-location) diff --git a/pipeline-to-taskrun/examples/pipeline-taskrun-pipelinerun.yaml b/pipeline-to-taskrun/examples/pipeline-taskrun-pipelinerun.yaml new file mode 100644 index 000000000..151d04757 --- /dev/null +++ b/pipeline-to-taskrun/examples/pipeline-taskrun-pipelinerun.yaml @@ -0,0 +1,56 @@ +apiVersion: tekton.dev/v1beta1 +kind: PipelineRun +metadata: + generateName: pipeline-taskrun-pipelinerun- +spec: + workspaces: + - name: where-it-all-happens + persistentVolumeClaim: + claimName: pvc + - name: gcs-creds + secret: + secretName: mikey + pipelineSpec: + workspaces: + - name: where-it-all-happens + - name: gcs-creds + tasks: + - name: before + taskSpec: + steps: + - name: echo + image: ubuntu + script: | + #!/usr/bin/env bash + echo "Hello before Pipeline to TaskRun!" + - name: pipeline-as-taskrun + taskRef: + apiVersion: tekton.dev/v1alpha1 + kind: PipelineToTaskRun + name: clone-test-upload + runAfter: + - before + params: + - name: git-url + value: "https://github.com/tektoncd/chains" + - name: package + value: "github.com/tektoncd/chains/pkg" + - name: packages + value: "./pkg/..." + - name: gcs-location + value: "gs://christies-empty-bucket" + workspaces: + - name: where-it-all-happens + workspace: where-it-all-happens + - name: gcs-creds + workspace: gcs-creds + - name: after + taskSpec: + steps: + - name: echo + image: ubuntu + script: | + #!/usr/bin/env bash + echo "Bye after Pipeline to TaskRun!" + runAfter: + - pipeline-as-taskrun \ No newline at end of file diff --git a/pipeline-to-taskrun/examples/pipeline-taskrun-run.yaml b/pipeline-to-taskrun/examples/pipeline-taskrun-run.yaml new file mode 100644 index 000000000..c71b0cf95 --- /dev/null +++ b/pipeline-to-taskrun/examples/pipeline-taskrun-run.yaml @@ -0,0 +1,26 @@ +apiVersion: tekton.dev/v1alpha1 +kind: Run +metadata: + generateName: pipeline-taskrun-run- +spec: + ref: + apiVersion: tekton.dev/v1alpha1 + kind: PipelineToTaskRun + name: clone-test-upload + params: + - name: git-url + value: "https://github.com/tektoncd/chains" + - name: package + value: "github.com/tektoncd/chains/pkg" + - name: packages + value: "./pkg/..." + - name: gcs-location + value: "gs://christies-empty-bucket" + workspaces: + - name: where-it-all-happens + persistentVolumeClaim: + claimName: pvc + - name: gcs-creds + secret: + secretName: mikey + diff --git a/pipeline-to-taskrun/examples/pvc.yaml b/pipeline-to-taskrun/examples/pvc.yaml new file mode 100644 index 000000000..7ee734697 --- /dev/null +++ b/pipeline-to-taskrun/examples/pvc.yaml @@ -0,0 +1,10 @@ +# https://github.com/tektoncd/cli/pull/1066 +metadata: + name: pvc +spec: + accessModes: + - ReadWriteOnce + volumeMode: Filesystem + resources: + requests: + storage: 1Gi \ No newline at end of file diff --git a/pipeline-to-taskrun/examples/run-pvc.yaml b/pipeline-to-taskrun/examples/run-pvc.yaml new file mode 100644 index 000000000..1f3477dfb --- /dev/null +++ b/pipeline-to-taskrun/examples/run-pvc.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: pvc +spec: + accessModes: + - ReadWriteOnce + volumeMode: Filesystem + resources: + requests: + storage: 1Gi \ No newline at end of file diff --git a/pipeline-to-taskrun/go.mod b/pipeline-to-taskrun/go.mod new file mode 100644 index 000000000..a33f035ee --- /dev/null +++ b/pipeline-to-taskrun/go.mod @@ -0,0 +1,37 @@ +module github.com/tektoncd/experimental/pipeline-to-taskrun + +go 1.15 + +require ( + github.com/docker/go-metrics v0.0.1 // indirect + github.com/fsnotify/fsnotify v1.4.9 // indirect + github.com/fvbommel/sortorder v1.0.2 // indirect + github.com/gobuffalo/envy v1.7.1 // indirect + github.com/google/go-cmp v0.5.5 + github.com/hashicorp/go-multierror v1.1.0 + github.com/markbates/inflect v1.0.4 // indirect + github.com/rogpeppe/go-internal v1.5.2 // indirect + github.com/tektoncd/pipeline v0.24.0 + github.com/theupdateframework/notary v0.7.0 // indirect + go.uber.org/zap v1.16.0 + k8s.io/api v0.20.2 + k8s.io/apimachinery v0.19.7 + k8s.io/client-go v11.0.1-0.20190805182717-6502b5e7b1b5+incompatible + knative.dev/pkg v0.0.0-20210331065221-952fdd90dbb0 + sigs.k8s.io/structured-merge-diff/v3 v3.0.1-0.20200706213357-43c19bbb7fba // indirect +) + +// Knative deps +replace ( + contrib.go.opencensus.io/exporter/stackdriver => contrib.go.opencensus.io/exporter/stackdriver v0.12.9-0.20191108183826-59d068f8d8ff + github.com/Azure/azure-sdk-for-go => github.com/Azure/azure-sdk-for-go v38.2.0+incompatible +) + +// Pin k8s deps to v0.18.8 +replace ( + k8s.io/api => k8s.io/api v0.18.8 + k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.18.8 + k8s.io/apimachinery => k8s.io/apimachinery v0.18.8 + k8s.io/client-go => k8s.io/client-go v0.18.8 + k8s.io/kube-openapi => k8s.io/kube-openapi v0.0.0-20200410145947-bcb3869e6f29 +) diff --git a/pipeline-to-taskrun/go.sum b/pipeline-to-taskrun/go.sum new file mode 100644 index 000000000..c9285fcc4 --- /dev/null +++ b/pipeline-to-taskrun/go.sum @@ -0,0 +1,1478 @@ +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.43.0/go.mod h1:BOSR3VbTLkk6FDC/TcffxP4NF/FFBGA5ku+jvKOP7pg= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.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.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw= +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.64.0/go.mod h1:xfORb36jGvE+6EexW71nMEtL025s3x6xvuYUKM4JLv4= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0 h1:eWRCuwubtDrCJG0oSUMgnsbD4CmPFQF2ei4OFbXvwww= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +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/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/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.11.0/go.mod h1:/PAbprKS+5msVYogBmczjWalDXnQ9mr64yEq9YnyPeo= +contrib.go.opencensus.io/exporter/ocagent v0.7.1-0.20200907061046-05415f1de66d h1:LblfooH1lKOpp1hIhukktmSAxFkqMPFk9KR6iZ0MJNI= +contrib.go.opencensus.io/exporter/ocagent v0.7.1-0.20200907061046-05415f1de66d/go.mod h1:IshRmMJBhDfFj5Y67nVhMYTTIze91RUeT73ipWKs/GY= +contrib.go.opencensus.io/exporter/prometheus v0.2.1-0.20200609204449-6bcf6f8577f0 h1:2O3c1g5CzMc1+Uah4Waot9Obm0yw70VXJzWaP6Fz3nw= +contrib.go.opencensus.io/exporter/prometheus v0.2.1-0.20200609204449-6bcf6f8577f0/go.mod h1:MjHoxkI7Ny27toPeFkRbXbzVjzIGkwOAptrAy8Mxtm8= +contrib.go.opencensus.io/exporter/stackdriver v0.12.9-0.20191108183826-59d068f8d8ff h1:g4QkFNN0ak+sCs/jqbhYLNkQaF1NVaKVoQ4Xm1RV3wM= +contrib.go.opencensus.io/exporter/stackdriver v0.12.9-0.20191108183826-59d068f8d8ff/go.mod h1:XyyafDnFOsqoxHJgTFycKZMrRUrPThLh2iYTJF6uoO0= +contrib.go.opencensus.io/exporter/zipkin v0.1.2/go.mod h1:mP5xM3rrgOjpn79MM8fZbj3gsxcuytSqtH0dxSWW1RE= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +git.apache.org/thrift.git v0.12.0/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= +github.com/Azure/azure-sdk-for-go v38.2.0+incompatible h1:ZeCdp1E/V5lI8oLR/BjWQh0OW9aFBYlgXGKRVIWNPXY= +github.com/Azure/azure-sdk-for-go v38.2.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-autorest v13.4.0+incompatible h1:YI49AKujDVk2KcLPKYGfkP7DlwU1xlRdI8GA0JWVYvE= +github.com/Azure/go-autorest v13.4.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= +github.com/Azure/go-autorest/autorest v0.9.3/go.mod h1:GsRuLYvwzLjjjRoWEIyMUaYq8GNUx2nRB378IPt/1p0= +github.com/Azure/go-autorest/autorest v0.9.6 h1:5YWtOnckcudzIw8lPPBcWOnmIFWMtHci1ZWAZulMSx0= +github.com/Azure/go-autorest/autorest v0.9.6/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630= +github.com/Azure/go-autorest/autorest v0.10.2 h1:NuSF3gXetiHyUbVdneJMEVyPUYAe5wh+aN08JYAf1tI= +github.com/Azure/go-autorest/autorest v0.10.2/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630= +github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= +github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= +github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= +github.com/Azure/go-autorest/autorest/adal v0.9.5 h1:Y3bBUV4rTuxenJJs41HU3qmqsb+auo+a3Lz+PlJPpL0= +github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= +github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= +github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= +github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= +github.com/Azure/go-autorest/autorest/mocks v0.4.1 h1:K0laFcLE6VLTOwNgSxaGbUcLPuGXlNkbVvq4cW4nIHk= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/to v0.2.0/go.mod h1:GunWKJp1AEqgMaGLV+iocmRAJWqST1wQYhyyjXJ3SJc= +github.com/Azure/go-autorest/autorest/to v0.3.0 h1:zebkZaadz7+wIQYgC7GXaz3Wb28yKYfVkkBKwc38VF8= +github.com/Azure/go-autorest/autorest/to v0.3.0/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA= +github.com/Azure/go-autorest/autorest/validation v0.1.0 h1:ISSNzGUh+ZSzizJWOWzs8bwpXIePbGLW4z/AmUFGH5A= +github.com/Azure/go-autorest/autorest/validation v0.1.0/go.mod h1:Ha3z/SqBeaalWQvokg3NZAlQTalVMtOIAs1aGK7G6u8= +github.com/Azure/go-autorest/autorest/validation v0.2.0 h1:15vMO4y76dehZSq7pAaOLQxC6dZYsSrj2GQpflyM/L4= +github.com/Azure/go-autorest/autorest/validation v0.2.0/go.mod h1:3EEqHnBxQGHXRYq3HT1WyXAvT7LLY3tl70hw6tQIbjI= +github.com/Azure/go-autorest/logger v0.1.0 h1:ruG4BSDXONFRrZZJ2GUXDiUyVpayPmb1GnWeHDdaNKY= +github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= +github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= +github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/DataDog/zstd v1.3.6-0.20190409195224-796139022798/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/GoogleCloudPlatform/cloud-builders/gcs-fetcher v0.0.0-20191203181535-308b93ad1f39/go.mod h1:yfGmCjKuUzk9WzubMlW2zwjhCraIc/J+M40cufdemRM= +github.com/GoogleCloudPlatform/k8s-cloud-provider v0.0.0-20190822182118-27a4ced34534/go.mod h1:iroGtC8B3tQiqtds1l+mgk/BBOrxbqjH+eUfFQYRc14= +github.com/GoogleCloudPlatform/k8s-cloud-provider v0.0.0-20200415212048-7901bc822317/go.mod h1:DF8FZRxMHMGv/vP2lQP6h+dYzzjpuRn24VeRiYn3qjQ= +github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/Shopify/logrus-bugsnag v0.0.0-20170309145241-6dbc35f2c30d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= +github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= +github.com/Shopify/sarama v1.23.1/go.mod h1:XLH1GYJnLVE0XCr6KdJGVJRTwY30moWNJ4sERjXX6fs= +github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= +github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= +github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= +github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= +github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= +github.com/alecthomas/jsonschema v0.0.0-20180308105923-f2c93856175a/go.mod h1:qpebaTNSsyUn5rPSJMsfqEtDw71TTggXM6stUDI16HA= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d h1:UQZhZ2O0vMHr2cI+DC1Mbh0TJxzA3RcLoMsFw+aXw7E= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= +github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= +github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= +github.com/aws/aws-sdk-go v1.23.20/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.28.2/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.31.6/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= +github.com/aws/aws-sdk-go v1.31.12 h1:SxRRGyhlCagI0DYkhOg+FgdXGXzRTE3vEX/gsgFaiKQ= +github.com/aws/aws-sdk-go v1.31.12/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= +github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= +github.com/beorn7/perks v0.0.0-20150223135152-b965b613227f/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bitly/go-hostpool v0.1.0/go.mod h1:4gOCgp6+NZnVqlKyZ/iBZFTAJKembaVENUpMkpg42fw= +github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= +github.com/blang/semver v3.5.0+incompatible h1:CGxCgetQ64DKk7rdZ++Vfnb1+ogGNnB17OJKJXD2Cfs= +github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= +github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= +github.com/blendle/zapdriver v1.3.1 h1:C3dydBOWYRiOk+B8X9IVZ5IOe+7cl+tGOexN4QqHfpE= +github.com/blendle/zapdriver v1.3.1/go.mod h1:mdXfREi6u5MArG4j9fewC+FGnXaBR+T4Ox4J2u4eHCc= +github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= +github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b/go.mod h1:ac9efd0D1fsDb3EJvhqgXRbFx7bs2wqZ10HQPeU8U/Q= +github.com/bugsnag/bugsnag-go v1.0.5-0.20150529004307-13fd6b8acda0/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= +github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= +github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= +github.com/c2h5oh/datasize v0.0.0-20171227191756-4eba002a5eae/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M= +github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= +github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/census-instrumentation/opencensus-proto v0.3.0 h1:t/LhUZLVitR1Ow2YOnduCsavhwFUklBMoGVYUCqmCqk= +github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.0/go.mod h1:dgIUBU3pDso/gPgZ1osOZ0iQf77oPR28Tjxl5dIMyVM= +github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +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/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudevents/sdk-go/v2 v2.1.0 h1:bmgrU8k+K2ppZ+G/q5xEQx/Xk9HRtJmkrEO3qtDO2k0= +github.com/cloudevents/sdk-go/v2 v2.1.0/go.mod h1:3CTrpB4+u7Iaj6fd7E2Xvm5IxMdRoaAhqaRVnOr2rCU= +github.com/cloudflare/cfssl v0.0.0-20180223231731-4e2dcbde5004/go.mod h1:yMWuSON2oQp+43nFtAV/uvKQIFpSPerB57DCt9t8sSA= +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/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= +github.com/containerd/containerd v1.3.0 h1:xjvXQWABwS2uiv3TWgQt5Uth60Gu86LTGZXMJkjc7rY= +github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/stargz-snapshotter/estargz v0.0.0-20201223015020-a9a0c2d64694 h1:OVQ4FVXeE6OjzuUifzER+7EulqTqw/94oKSqnooEowQ= +github.com/containerd/stargz-snapshotter/estargz v0.0.0-20201223015020-a9a0c2d64694/go.mod h1:E9uVkkBKf0EaC39j2JVW9EzdNhYvpz6eQIjILHebruk= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +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/denisenkom/go-mssqldb v0.0.0-20191128021309-1d7a30a10f73/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-gk v0.0.0-20140819190930-201884a44051/go.mod h1:qm+vckxRlDt0aOla0RYJJVeqHZlWfOm2UIxHaqPB46E= +github.com/dgryski/go-gk v0.0.0-20200319235926-a69029f61654/go.mod h1:qm+vckxRlDt0aOla0RYJJVeqHZlWfOm2UIxHaqPB46E= +github.com/dgryski/go-lttb v0.0.0-20180810165845-318fcdf10a77/go.mod h1:Va5MyIzkU0rAM92tn3hb3Anb7oz7KcnixF49+2wOMe4= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= +github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017 h1:2HQmlpI3yI9deH18Q6xiSOIjXD4sLI55Y/gfpa8/558= +github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v20.10.2+incompatible h1:CR/6BZX5w3TLgAHZTyRpVh3yi+Q8Sj5j1fCsb0J2rCk= +github.com/docker/cli v20.10.2+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug= +github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7 h1:Cvj7S8I4Xpx78KAl6TwTmMHuHlZ/0SM60NUneGJQ7IE= +github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v20.10.2+incompatible h1:vFgEHPqWBTp4pTjdLwjAA4bSo3gvIGOYwuJTlEjVBCw= +github.com/docker/docker v20.10.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker-credential-helpers v0.6.3 h1:zI2p9+1NQYdnG6sMU26EX4aVGlqbInSQxQXLvzJ4RPQ= +github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= +github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c h1:lzqkGL9b3znc+ZUgi7FlLnqjQhcXxkNM/quxIjBVMD0= +github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c/go.mod h1:CADgU4DSXK5QUlFslkQu2yW2TKzFZcXq/leZfM0UH5Q= +github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI= +github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8= +github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= +github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= +github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dvsekhvalnov/jose2go v0.0.0-20170216131308-f21a8cedbbae/go.mod h1:7BvyPhdbLxMXIYTFPLsyJRFMsKmOZnQmzh6Gb+uquuM= +github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-resiliency v1.2.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful v2.9.5+incompatible h1:spTtZBk5DYEvbxMVutUuTyh1Ao2r4iyvLdACqsl/Ljk= +github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful v2.15.0+incompatible h1:8KpYO/Xl/ZudZs5RNOEhWMBY4hmzlZhhRd9cu+jrZP4= +github.com/emicklei/go-restful v2.15.0+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= +github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= +github.com/envoyproxy/go-control-plane v0.9.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/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= +github.com/evanphx/json-patch v0.0.0-20200808040245-162e5629780b/go.mod h1:NAJj0yf/KaRKURN6nyi7A9IZydMivZEm9oQLWNjfKDc= +github.com/evanphx/json-patch v4.5.0+incompatible h1:ouOWdg56aJriqS0huScTkVXPC5IcNrDCXZ6OoTAWu7M= +github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.9.0+incompatible h1:kLcOMZeuLAJvL2BPWLMIj5oaZQobrkAqrL+WFZwQses= +github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= +github.com/form3tech-oss/jwt-go v3.2.2+incompatible h1:TcekIExNqud5crz4xD2pavyTgWiPvpYe4Xau31I0PRk= +github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= +github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fvbommel/sortorder v1.0.2 h1:mV4o8B2hKboCdkJm+a7uX/SIpZob4JzUpc5GGnM45eo= +github.com/fvbommel/sortorder v1.0.2/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0= +github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= +github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= +github.com/go-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-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logr/logr v0.1.0 h1:M1Tv3VzNlEHg6uyACnRdtrploV2P7wZqH8BoQMtz0cg= +github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-logr/logr v0.4.0 h1:K7/B1jt6fIBQVd4Owv2MqGQClcgf0R266+7C/QjRcLc= +github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI= +github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= +github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= +github.com/go-openapi/analysis v0.19.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk= +github.com/go-openapi/analysis v0.19.5/go.mod h1:hkEAkxagaIvIP7VTn8ygJNkd4kAYON2rCu0v0ObL0AU= +github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= +github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= +github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94= +github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= +github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= +github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= +github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= +github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= +github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= +github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/jsonreference v0.19.3 h1:5cxNfTy0UVC3X8JL5ymxzyoUZmo8iZb+jeTWn7tUa8o= +github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/jsonreference v0.19.5 h1:1WJP/wi4OjB4iV8KVbH73rQaoialJrqv8gitZLxGLtM= +github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= +github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= +github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= +github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= +github.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix5jWFxsNPs= +github.com/go-openapi/loads v0.19.4/go.mod h1:zZVHonKd8DXyxyw4yfnVjPzBjIQcLt0CCsn0N0ZrQsk= +github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA= +github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64= +github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4= +github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= +github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= +github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= +github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY= +github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/spec v0.19.6 h1:rMMMj8cV38KVXK7SFc+I2MWClbEfbK705+j+dyqun5g= +github.com/go-openapi/spec v0.19.6/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk= +github.com/go-openapi/spec v0.20.2 h1:pFPUZsiIbZ20kLUcuCGeuQWG735fPMxW7wHF9BWlnQU= +github.com/go-openapi/spec v0.20.2/go.mod h1:RW6Xcbs6LOyWLU/mXGdzn2Qc+3aj+ASfI7rvSZh1Vls= +github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= +github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= +github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY= +github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU= +github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= +github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= +github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= +github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.7 h1:VRuXN2EnMSsZdauzdss6JBC29YotDqG59BZ+tdlIL1s= +github.com/go-openapi/swag v0.19.7/go.mod h1:ao+8BpOPyKdpQz3AOJfbeEVpLmWAvlT1IfTe5McPyhY= +github.com/go-openapi/swag v0.19.13 h1:233UVgMy1DlmCYYfOiFpta6e2urloh+sEs5id6lyzog= +github.com/go-openapi/swag v0.19.13/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= +github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA= +github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= +github.com/go-sql-driver/mysql v1.3.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gobuffalo/envy v1.6.5/go.mod h1:N+GkhhZ/93bGZc6ZKhJLP6+m+tCNPKwgSpH9kaifseQ= +github.com/gobuffalo/envy v1.7.1/go.mod h1:FurDp9+EDPE4aIUS3ZLyD+7/9fpx7YRt/ukY6jIHf0w= +github.com/gobuffalo/flect v0.2.2/go.mod h1:vmkQwuZYhN5Pc4ljYQZzP+1sq+NEkK+lh20jmEmX3jc= +github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= +github.com/gogo/protobuf v1.0.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.2.2-0.20190730201129-28a6bbf47e48/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9/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 h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/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/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/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 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/gonum/blas v0.0.0-20181208220705-f22b278b28ac/go.mod h1:P32wAyui1PQ58Oce/KYkOqQv8cVw1zAapXOl+dRFGbc= +github.com/gonum/diff v0.0.0-20181124234638-500114f11e71/go.mod h1:22dM4PLscQl+Nzf64qNBurVJvfyvZELT0iRW2l/NN70= +github.com/gonum/floats v0.0.0-20181209220543-c233463c7e82/go.mod h1:PxC8OnwL11+aosOB5+iEPoV3picfs8tUpkVd0pDo+Kg= +github.com/gonum/integrate v0.0.0-20181209220457-a422b5c0fdf2/go.mod h1:pDgmNM6seYpwvPos3q+zxlXMsbve6mOIPucUnUOrI7Y= +github.com/gonum/internal v0.0.0-20181124074243-f884aa714029/go.mod h1:Pu4dmpkhSyOzRwuXkOgAvijx4o+4YMUJJo9OvPYMkks= +github.com/gonum/lapack v0.0.0-20181123203213-e4cdc5a0bff9/go.mod h1:XA3DeT6rxh2EAE789SSiSJNqxPaC0aE9J8NTOI0Jo/A= +github.com/gonum/mathext v0.0.0-20181121095525-8a4bf007ea55/go.mod h1:fmo8aiSEWkJeiGXUJf+sPvuDgEFgqIoZSs843ePKrGg= +github.com/gonum/matrix v0.0.0-20181209220409-c518dec07be9/go.mod h1:0EXg4mc1CNP0HCqCz+K4ts155PXIlUywf0wqN+GfPZw= +github.com/gonum/stat v0.0.0-20181125101827-41a0da705a5b/go.mod h1:Z4GIJBJO3Wa4gD4vbwQxXXZ+WHmW6E9ixmNrwvs0iZs= +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/certificate-transparency-go v1.0.10-0.20180222191210-5ab67e519c93/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg= +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 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-containerregistry v0.2.1 h1:LLZgLTDguTVJ9eEHh/zTtr347CpFhH6MSYculNas5bY= +github.com/google/go-containerregistry v0.2.1/go.mod h1:Ts3Wioz1r5ayWx8sS6vLcWltWcM1aqFjd/eVrkFhrWM= +github.com/google/go-containerregistry v0.4.1-0.20210128200529-19c2b639fab1 h1:o2ykCuuhHeUwtzNg89pH2hi+821aqjLWkaREVR3ziTQ= +github.com/google/go-containerregistry v0.4.1-0.20210128200529-19c2b639fab1/go.mod h1:GU9FUA/X9rd2cV3ZoUNaWihp27tki6/38EsVzL2Dyzc= +github.com/google/go-containerregistry/pkg/authn/k8schain v0.0.0-20210129212729-5c4818de4025 h1:3o5qj2tOnL5eMB9b8YbcJ25sJI8oLrfy6Z0YYZl6lGY= +github.com/google/go-containerregistry/pkg/authn/k8schain v0.0.0-20210129212729-5c4818de4025/go.mod h1:n9wRxRfKkHy6ZFyj0jJQHw11P+mGLnED4sqegwrXxDk= +github.com/google/go-github/v27 v27.0.6/go.mod h1:/0Gr8pJ55COkmv+S/yPKCczSkUPIM/LnFyubufRNIS0= +github.com/google/go-licenses v0.0.0-20200602185517-f29a4c695c3d/go.mod h1:g1VOUGKZYIqe8lDq2mL7plhAWXqrEaGUs7eIjthN1sk= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/licenseclassifier v0.0.0-20190926221455-842c0d70d702/go.mod h1:qsqn2hxC+vURpyBRygGUuinTO42MFRLcsmQ/P8v94+M= +github.com/google/mako v0.0.0-20190821191249-122f8dcef9e3/go.mod h1:YzLcVlL+NqWnmUEPuhS1LxDDwGO9WNbVlEXaF4IH35g= +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/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190723021845-34ac40c74b70/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/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/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= +github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go v2.0.2+incompatible h1:silFMLAnr330+NRuag/VjIGF7TLp/LBrV2CJKFLWEww= +github.com/googleapis/gax-go v2.0.2+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.2.2/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.4.0 h1:BXDUo8p/DaxC+4FJY/SSx3gvnx9C1VdHNgaUkiEL5mk= +github.com/googleapis/gnostic v0.4.0/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU= +github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= +github.com/googleapis/gnostic v0.5.3 h1:2qsuRm+bzgwSIKikigPASa2GhW8H2Dn4Qq7UxD8K/48= +github.com/googleapis/gnostic v0.5.3/go.mod h1:TRWw1s4gxBGjSe301Dai3c7wXJAZy57+/6tawkOvqHQ= +github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= +github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc= +github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.14.6/go.mod h1:zdiPV4Yse/1gnckTHtghG4GkDEdKCRJduHpTxT3/jcw= +github.com/grpc-ecosystem/grpc-gateway v1.14.8 h1:hXClj+iFpmLM8i3lkO6i4Psli4P2qObQuQReiII26U8= +github.com/grpc-ecosystem/grpc-gateway v1.14.8/go.mod h1:NZE8t6vs6TnwLL/ITkaK8W3ecMLGAbh2jXTclvpiwYo= +github.com/h2non/gock v1.0.9/go.mod h1:CZMcB0Lg5IWnr9bF79pPMg9WeV6WumxQiUJ1UvdO1iE= +github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= +github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= +github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI= +github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.9 h1:UauaLniWCFHWd+Jp9oCEkTBj8VO/9DKg3PV3VCNMDIg= +github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/influxdata/tdigest v0.0.0-20180711151920-a7d76c6f093a/go.mod h1:9GkyshztGufsdPQWjH+ifgnIr3xNUL5syI70g2dzU1o= +github.com/influxdata/tdigest v0.0.0-20181121200506-bf2b5ad3c0a9/go.mod h1:Js0mqiSBE6Ffsg94weZZ2c+v/ciT8QRHFOap7EKDrR0= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= +github.com/jcmturner/gofork v0.0.0-20190328161633-dc7c13fece03/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= +github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= +github.com/jenkins-x/go-scm v1.5.117/go.mod h1:PCT338UhP/pQ0IeEeMEf/hoLTYKcH7qjGEKd7jPkeYg= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jinzhu/gorm v0.0.0-20170222002820-5409931a1bb8/go.mod h1:Vla75njaFJ8clLU1W44h34PjIkijhjHIYnZxMqCdxqo= +github.com/jinzhu/inflection v0.0.0-20170102125226-1c35d901db3d/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.3.0 h1:OS12ieG61fsCg5+qLJ+SsW9NicxNkg3b25OyT2yCeUc= +github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik= +github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8= +github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +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/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/juju/loggo v0.0.0-20190526231331-6e530bcce5d8/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= +github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= +github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= +github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= +github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/lib/pq v0.0.0-20150723085316-0dad96c0b94f/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= +github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= +github.com/lightstep/tracecontext.go v0.0.0-20181129014701-1757c391b1ac h1:+2b6iGRJe3hvV/yVXrd41yVEjxuFHxasJqDhkIjS4gk= +github.com/lightstep/tracecontext.go v0.0.0-20181129014701-1757c391b1ac/go.mod h1:Frd2bnT3w5FB5q49ENTfVlztJES+1k/7lyWX2+9gq/M= +github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= +github.com/magiconair/properties v1.5.3/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/mailru/easyjson v0.7.1-0.20191009090205-6c0755d89d1e h1:jcoUdG1TzY/M/eM5BLFLP8DJeMximx5NQYSlLL9YeWc= +github.com/mailru/easyjson v0.7.1-0.20191009090205-6c0755d89d1e/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= +github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/markbates/inflect v1.0.4/go.mod h1:1fR9+pO2KHEO9ZRtto13gDwwZaAKstQzferVeWqbgNs= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-sqlite3 v1.6.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= +github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.17/go.mod h1:WgzbA6oji13JREwiNsRDNfl7jYdPnmz+VEuLrA+/48M= +github.com/miekg/pkcs11 v1.0.2/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +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/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20150613213606-2caf8efc9366/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/moby/term v0.0.0-20200312100748-672ec06f55cd h1:aY7OQNf2XqY/JQ6qREWamhI/81os/agb2BAGpcx5yWI= +github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= +github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= +github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= +github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= +github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= +github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.2/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= +github.com/onsi/ginkgo v1.12.1 h1:mFwc4LvZ0xpSvDZ3E+k8Yte0hLOMxXUlP+yXtJqkYfQ= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.10.3 h1:gph6h/qe9GSUw1NhH1gp+qb+h8rXD8Cy60Z32Qw3ELA= +github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= +github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= +github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ= +github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= +github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= +github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= +github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA= +github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= +github.com/openzipkin/zipkin-go v0.2.0/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/openzipkin/zipkin-go v0.2.5 h1:UwtQQx2pyPIgWYHRg+epgdx1/HnBQTgN3/oIYEJTQzU= +github.com/openzipkin/zipkin-go v0.2.5/go.mod h1:KpXfKdgRDnnhsxw4pNIH9Md5lyFqKUa4YDFlwRYAMyE= +github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw= +github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= +github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs= +github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= +github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= +github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= +github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/pierrec/lz4 v0.0.0-20190327172049-315a67e90e41/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= +github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= +github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pierrec/lz4 v2.2.6+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= +github.com/prometheus/client_golang v0.9.0-pre1.0.20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= +github.com/prometheus/client_golang v1.2.1/go.mod h1:XMU6Z2MjaRKVu/dC1qupJI9SiNkDYzz3xecMgSW/F+U= +github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.8.0 h1:zvJNkoCFAnYFNC24FV8nW4JdRJ3GIFcLbg65lL/JDcw= +github.com/prometheus/client_golang v1.8.0/go.mod h1:O9VU6huf47PktckDQfMTX0Y8tY0/7TSWwj+ITvv0TnM= +github.com/prometheus/client_golang v1.9.0 h1:Rrch9mh17XcxvEu9D9DEpb4isxjGBtcevQjKvxPRQIU= +github.com/prometheus/client_golang v1.9.0/go.mod h1:FqZLKOZnGdFAhOK4nqGHa7D66IdsO+O441Eve7ptJDU= +github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= +github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.14.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= +github.com/prometheus/common v0.15.0 h1:4fgOnadei3EZvgRwxJ7RMpG1k1pOZth5Pc13tyspaKM= +github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= +github.com/prometheus/common v0.19.0 h1:Itb4+NjG9wRdkAWgVucbM/adyIXxEhbw0866e0uZE6A= +github.com/prometheus/common v0.19.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= +github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/prometheus/procfs v0.0.6/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.2.0 h1:wH4vA7pcjKuZzjF7lM8awk4fnuJO6idemZXoKnULUx4= +github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/statsd_exporter v0.15.0 h1:UiwC1L5HkxEPeapXdm2Ye0u1vUJfTj7uwT5yydYpa1E= +github.com/prometheus/statsd_exporter v0.15.0/go.mod h1:Dv8HnkoLQkeEjkIE4/2ndAA7WL1zHKK7WMqFQqu72rw= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rcrowley/go-metrics v0.0.0-20190706150252-9beb055b7962/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +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/rogpeppe/go-internal v1.3.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.5.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto= +github.com/rubiojr/go-vhd v0.0.0-20200706105327-02e210299021/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/shurcooL/githubv4 v0.0.0-20190718010115-4ba037080260/go.mod h1:hAF0iLZy4td2EX+/8Tw+4nodhlMrwN3HupfaXj3zkGo= +github.com/shurcooL/graphql v0.0.0-20181231061246-d48a9a75455f/go.mod h1:AuYgA5Kyo4c7HfUmvRGs/6rGlMMV/6B1bVnB9JxJEEg= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/cast v0.0.0-20150508191742-4d07383ffe94/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.1/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8= +github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +github.com/spf13/jwalterweatherman v0.0.0-20141219030609-3d60171a6431/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.0/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v0.0.0-20150530192845-be5ff3e4840c/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= +github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI= +github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= +github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= +github.com/streadway/quantile v0.0.0-20150917103942-b0c588724d25/go.mod h1:lbP8tGiBjZ5YWIc2fzuRpTaz0b/53vT6PEs3QuAWzuU= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/tektoncd/experimental v0.7.0 h1:gxk3GF3hAq7JS1ysmgbMkjTsnWhX/Muw3mNU5fSmUpo= +github.com/tektoncd/pipeline v0.20.0 h1:JW9YgkzQAvW2vzU1zpwyz3IALqzyMNBnfLOzz88mZ0A= +github.com/tektoncd/pipeline v0.20.0/go.mod h1:xF5WxMLvp/05oGZ+Fvqcbglmf4HVU9u1keXHaM+rR14= +github.com/tektoncd/pipeline v0.24.0 h1:gdUAJ/7fmA3imZtk+Mrwo5L34imNr3YLR4SfN0OzzBk= +github.com/tektoncd/pipeline v0.24.0/go.mod h1:ChFD/vfu14VOtCVlLWdtlvOwXfBfVotULoNV6yz+CKY= +github.com/tektoncd/plumbing v0.0.0-20201021153918-6b7e894737b5/go.mod h1:WTWwsg91xgm+jPOKoyKVK/yRYxnVDlUYeDlypB1lDdQ= +github.com/tektoncd/plumbing v0.0.0-20210420200944-17170d5e7bc9/go.mod h1:WTWwsg91xgm+jPOKoyKVK/yRYxnVDlUYeDlypB1lDdQ= +github.com/theupdateframework/notary v0.7.0 h1:QyagRZ7wlSpjT5N2qQAh/pN+DVqgekv4DzbAiAiEL3c= +github.com/theupdateframework/notary v0.7.0/go.mod h1:c9DRxcmhHmVLDay4/2fUYdISnHqbFDGRSlXPO0AhYWw= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tsenart/go-tsz v0.0.0-20180814232043-cdeb9e1e981e/go.mod h1:SWZznP1z5Ki7hDT2ioqiFKEse8K9tU2OUvaRI0NeGQo= +github.com/tsenart/vegeta/v12 v12.8.4/go.mod h1:ZiJtwLn/9M4fTPdMY7bdbIeyNeFVE8/AHbWFqCsUuho= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/vdemeester/k8s-pkg-credentialprovider v1.18.1-0.20201019120933-f1d16962a4db h1:lWvSzFrGhtYgApDvR5X+43rqfpLzRumLzypyL1YhDww= +github.com/vdemeester/k8s-pkg-credentialprovider v1.18.1-0.20201019120933-f1d16962a4db/go.mod h1:grWy0bkr1XO6hqbaaCKaPXqkBVlMGHYG6PGykktwbJc= +github.com/vdemeester/k8s-pkg-credentialprovider v1.19.7 h1:MJ5fV2Z0OyIuPvFVs0vi6VjTjxpdK1QT8oX/aWiUjYM= +github.com/vdemeester/k8s-pkg-credentialprovider v1.19.7/go.mod h1:K2nMO14cgZitdwBqdQps9tInJgcaXcU/7q5F59lpbNI= +github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= +github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= +github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= +github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= +github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +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= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= +go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= +go.etcd.io/etcd v0.5.0-alpha.5.0.20200819165624-17cef6e3e9d5/go.mod h1:skWido08r9w6Lq/w70DO5XYIKMu4QFu1+4VsqLQuJy8= +go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= +go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= +go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= +go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4-0.20200608061201-1901b56b9515/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5 h1:dntmOdLpSpHlVqbW5Eay97DelsZHe+55D+xC6i0dDS0= +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.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/automaxprocs v1.3.0 h1:II28aZoGdaglS5vVNnspf28lnZpXScxtIozx1lAjdb0= +go.uber.org/automaxprocs v1.3.0/go.mod h1:9CWT6lKIep8U41DDaPiH6eFscnTyjfTANNQNx6LrIcA= +go.uber.org/automaxprocs v1.4.0 h1:CpDZl6aOlLhReez+8S3eEotD7Jx0Os++lemPlMULQP0= +go.uber.org/automaxprocs v1.4.0/go.mod h1:/mTEdr7LvHhs0v7mjdxDreTz1OG5zdZGqgOnhWiR/+Q= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +go.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM= +go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191117063200-497ca9f6d64f/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0 h1:hb9wdF1z5waM+dSIICn1l0DkLVDT3hqhhQsDNUmHPRE= +golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY= +golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +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-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-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 h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mobile v0.0.0-20190806162312-597adff16ade/go.mod h1:AlhUtkH4DA4asiFC5RgK7ZKmauvtkAVcy9L0epCzlWo= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.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.1 h1:Kvvh58BN8Y9/lBi7hTekvtMpm07eUZ0ck5pRHpsMWrY= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190912160710-24e19bdeb0f2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191119073136-fc4aabc6c914/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-20200520004742-59133d7f0dd7/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-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +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 h1:lwlPPsmjDKK0J6eG6xDWd5XPehI0R024zxjDnw3esPA= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777 h1:003p0dJM77cxMSyCPFphvZf/Y5/NXf5fzg6ufd1/Oew= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +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 h1:Lm4OryKCca1vehdsWogr9N4t7NfZxLbJoc/H0w4K4S4= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210126194326-f9ce19ea3013 h1:55H5j7lotzuFCEOKDsMch+fRNUQ9DgtyHOUP31FNqKc= +golang.org/x/oauth2 v0.0.0-20210126194326-f9ce19ea3013/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +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 h1:DcqTD9SDLc+1P/r1EmRBwnVsrOwW+kk2vWf9n+1sGhs= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190912141932-bc967efca4b8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191113165036-4c7a9d0fe056/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191119060738-e882bf8e40c2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-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-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/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-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/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 h1:kzM6+9dur93BcC2kVlYl34cHU+TYZLanmpSJHVMmL64= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf h1:MZ2shdL+ZM/XzY3ZGOnh4Nlpnxz5GSOhOmtHo3iPU6M= +golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +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 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e h1:EHBhcS0mlXEAVwNyO2dLfjToGsyY4j24pTs2ScHnX7s= +golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 h1:Hir2P/De0WpUhtrKGGjvSb2YxUgyZ7EFOSLIcSSpiwE= +golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-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-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= +golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= +golang.org/x/tools v0.0.0-20190807223507-b346f7fd45de/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-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-20191118222007-07fc4c7f2b98/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-20200103221440-774c71fcf114/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-20200505023115-26f46d2f7ef8/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-20200616133436-c1934b75d054/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-20200619180055-7c47624df98f/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-20200817023811-d00afeaade8f/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200827163409-021d7c6f1ec3/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20200916195026-c9a70fc28ce3/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= +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-20201211185031-d93e913c1a58/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +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= +gomodules.xyz/jsonpatch/v2 v2.1.0 h1:Phva6wqu+xR//Njw6iorylFFgn/z547tw5Ne3HZPQ+k= +gomodules.xyz/jsonpatch/v2 v2.1.0/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU= +gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= +gonum.org/v1/netlib v0.0.0-20181029234149-ec6d1f5cefe6/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.6.1-0.20190607001116-5213b8090861/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.10.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.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.15.1-0.20200106000736-b8fc810ca6b5/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.1/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.25.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 h1:l2Nfbl2GPXdWorv+dT2XfinX2jOOw4zv1VhLstx+6rE= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.2/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/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-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= +google.golang.org/genproto v0.0.0-20190716160619-c506a9f90610/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-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-20200527145253-8367513e4ece/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +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-20200815001618-f69a88009b70/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-20200827165113-ac2560b5e952/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-20201019141844-1ed22bb0c154/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-20201211151036-40ec1c210f7a h1:GnJAhasbD8HiT8DZMvsEx3QLVy/X0icq/MGr0MqRJ2M= +google.golang.org/genproto v0.0.0-20201211151036-40ec1c210f7a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d h1:HV9Z9qMhQEsdlvxNFELgQ11RkMzO3CMkjEySjCtuLes= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/grpc v1.0.5/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.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.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0 h1:raiipEjMOIC/TO2AvyTxP25XFdLxNIBwzDh3FM3XztI= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.36.0 h1:o1bcQ6imQMIOpdrO3SWf2z5RV72WbDwdXuK0MDlc8As= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +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 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= +gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/cenkalti/backoff.v2 v2.2.1/go.mod h1:S0QdOvT2AlerfSBkp0O+dk+bbIMaNbEmVk876gPCthU= +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/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U= +gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/evanphx/json-patch.v4 v4.9.0 h1:T7W7A7+DTEpLTC11pkf8yfaeRfqhRj/gOPf+LtaJdNY= +gopkg.in/evanphx/json-patch.v4 v4.9.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gcfg.v1 v1.2.0/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= +gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= +gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/jcmturner/aescts.v1 v1.0.1/go.mod h1:nsR8qBOg+OucoIW+WMhB3GspUQXq9XorLnQb9XtvcOo= +gopkg.in/jcmturner/dnsutils.v1 v1.0.1/go.mod h1:m3v+5svpVOhtFAP/wSz+yzh4Mc0Fg7eRhxkJMWSIz9Q= +gopkg.in/jcmturner/gokrb5.v7 v7.2.3/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM= +gopkg.in/jcmturner/gokrb5.v7 v7.3.0/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM= +gopkg.in/jcmturner/rpc.v1 v1.1.0/go.mod h1:YIdkC4XfD6GXbzje11McwsDuOlZQSb9W4vfLvuNnlv8= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/rethinkdb/rethinkdb-go.v6 v6.2.1/go.mod h1:WbjuEoo1oadwzQ4apSDU+JTvmllEHtsNHS6y7vFc7iw= +gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98= +gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g= +gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/warnings.v0 v0.1.1/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/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.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20190709130402-674ba3eaed22/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +gotest.tools/v3 v3.0.2 h1:kG1BFyqVHuQoVQiR1bWGnfz/fmHvvuiSPIV7rvl360E= +gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= +honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.2/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +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= +honnef.co/go/tools v0.0.1-2020.1.5 h1:nI5egYTGJakVyOryqLs1cQO5dO0ksin5XXs2pspk75k= +honnef.co/go/tools v0.0.1-2020.1.5/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +k8s.io/api v0.18.8 h1:aIKUzJPb96f3fKec2lxtY7acZC9gQNDLVhfSGpxBAC4= +k8s.io/api v0.18.8/go.mod h1:d/CXqwWv+Z2XEG1LgceeDmHQwpUJhROPx16SlxJgERY= +k8s.io/apiextensions-apiserver v0.18.8 h1:pkqYPKTHa0/3lYwH7201RpF9eFm0lmZDFBNzhN+k/sA= +k8s.io/apiextensions-apiserver v0.18.8/go.mod h1:7f4ySEkkvifIr4+BRrRWriKKIJjPyg9mb/p63dJKnlM= +k8s.io/apimachinery v0.18.8 h1:jimPrycCqgx2QPearX3to1JePz7wSbVLq+7PdBTTwQ0= +k8s.io/apimachinery v0.18.8/go.mod h1:6sQd+iHEqmOtALqOFjSWp2KZ9F0wlU/nWm0ZgsYWMig= +k8s.io/apiserver v0.18.8/go.mod h1:12u5FuGql8Cc497ORNj79rhPdiXQC4bf53X/skR/1YM= +k8s.io/apiserver v0.19.7/go.mod h1:DmWVQggNePspa+vSsVytVbS3iBSDTXdJVt0akfHacKk= +k8s.io/client-go v0.18.8 h1:SdbLpIxk5j5YbFr1b7fq8S7mDgDjYmUxSbszyoesoDM= +k8s.io/client-go v0.18.8/go.mod h1:HqFqMllQ5NnQJNwjro9k5zMyfhZlOwpuTLVrxjkYSxU= +k8s.io/cloud-provider v0.18.8/go.mod h1:cn9AlzMPVIXA4HHLVbgGUigaQlZyHSZ7WAwDEFNrQSs= +k8s.io/cloud-provider v0.19.7/go.mod h1:aO/VpUwkG+JQN7ZXc5WBLZ5NBXuq/Y5B6vri6U94PZ8= +k8s.io/code-generator v0.18.8/go.mod h1:TgNEVx9hCyPGpdtCWA34olQYLkh3ok9ar7XfSsr8b6c= +k8s.io/code-generator v0.19.7/go.mod h1:lwEq3YnLYb/7uVXLorOJfxg+cUu2oihFhHZ0n9NIla0= +k8s.io/component-base v0.18.8 h1:BW5CORobxb6q5mb+YvdwQlyXXS6NVH5fDXWbU7tf2L8= +k8s.io/component-base v0.18.8/go.mod h1:00frPRDas29rx58pPCxNkhUfPbwajlyyvu8ruNgSErU= +k8s.io/component-base v0.19.7 h1:ZXS2VRWOWBOc2fTd1zjzhi/b/mkqFT9FDqiNsn1cH30= +k8s.io/component-base v0.19.7/go.mod h1:YX8spPBgwl3I6UGcSdQiEMAqRMSUsGQOW7SEr4+Qa3U= +k8s.io/csi-translation-lib v0.18.8/go.mod h1:6cA6Btlzxy9s3QrS4BCZzQqclIWnTLr6Jx3H2ctAzY4= +k8s.io/csi-translation-lib v0.19.7/go.mod h1:WghizPQuzuygr2WdpgN2EjcNpDD2V4EAbxFXsgHgSBk= +k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20200114144118-36b2048a9120/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20200205140755-e0e292d8aa12/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20200428234225-8167cfdcfc14/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20201113003025-83324d819ded/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= +k8s.io/gengo v0.0.0-20201214224949-b6c5ce23f027/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= +k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= +k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= +k8s.io/klog/v2 v2.0.0 h1:Foj74zO6RbjjP4hBEKjnYtjjAhGg4jNynUdYF6fJrok= +k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/klog/v2 v2.5.0 h1:8mOnjf1RmUPW6KRqQCfYSZq/K20Unmp3IhuZUhxl8KI= +k8s.io/klog/v2 v2.5.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= +k8s.io/kube-openapi v0.0.0-20200410145947-bcb3869e6f29 h1:NeQXVJ2XFSkRoPzRo8AId01ZER+j8oV4SZADT4iBOXQ= +k8s.io/kube-openapi v0.0.0-20200410145947-bcb3869e6f29/go.mod h1:F+5wygcW0wmRTnM3cOgIqGivxkwSWIWT5YdsDbeAOaU= +k8s.io/legacy-cloud-providers v0.18.8 h1:IGASZSYJjkMk5d1HU9+zskZqoRG3zccVzvA3hV7hCL0= +k8s.io/legacy-cloud-providers v0.18.8/go.mod h1:tgp4xYf6lvjrWnjQwTOPvWQE9IVqSBGPF4on0IyICQE= +k8s.io/legacy-cloud-providers v0.19.7 h1:YJ/l/8/Hn56I9m1cudK8aNypRA/NvI/hYhg8fo/CTus= +k8s.io/legacy-cloud-providers v0.19.7/go.mod h1:dsZk4gH9QIwAtHQ8CK0Ps257xlfgoXE3tMkMNhW2xDU= +k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +k8s.io/utils v0.0.0-20200603063816-c1c6865ac451 h1:v8ud2Up6QK1lNOKFgiIVrZdMg7MpmSnvtrOieolJKoE= +k8s.io/utils v0.0.0-20200603063816-c1c6865ac451/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20210111153108-fddb29f9d009 h1:0T5IaWHO3sJTEmCP6mUlBvMukxPKUQWqiI/YuiBNMiQ= +k8s.io/utils v0.0.0-20210111153108-fddb29f9d009/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +knative.dev/hack v0.0.0-20201214230143-4ed1ecb8db24/go.mod h1:PHt8x8yX5Z9pPquBEfIj0X66f8iWkWfR0S/sarACJrI= +knative.dev/hack v0.0.0-20210325223819-b6ab329907d3/go.mod h1:PHt8x8yX5Z9pPquBEfIj0X66f8iWkWfR0S/sarACJrI= +knative.dev/pkg v0.0.0-20210107022335-51c72e24c179/go.mod h1:hckgW978SdzPA2H5EDvRPY8xsnPuDZLJLbPf8Jte7Q0= +knative.dev/pkg v0.0.0-20210114223020-f0ea5e6b9c4e h1:3k5tzvlM9VGZFiXRj8UKc3CUpMGpqBlEbIY0Dp3F3NU= +knative.dev/pkg v0.0.0-20210114223020-f0ea5e6b9c4e/go.mod h1:hckgW978SdzPA2H5EDvRPY8xsnPuDZLJLbPf8Jte7Q0= +knative.dev/pkg v0.0.0-20210331065221-952fdd90dbb0 h1:z05hcB4br0qz7JdwIoUSTXLTF+7ThuJ+R6NFfXd1Y4Q= +knative.dev/pkg v0.0.0-20210331065221-952fdd90dbb0/go.mod h1:PD5g8hUCXq6iR3tILjmZeJBvQfXGnHMPKryq54qHJhg= +pgregory.net/rapid v0.3.3/go.mod h1:UYpPVyjFHzYBGHIxLFoupi8vwk6rXNzRY9OMvVxFIOU= +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= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.7/go.mod h1:PHgbrJT7lCHcxMU+mDHEm+nx46H4zuuHZkDP6icnhu0= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.9/go.mod h1:dzAXnQbTRyDlZPJX2SUPEqvnB+j7AJjtlox7PEwigU0= +sigs.k8s.io/structured-merge-diff/v2 v2.0.1/go.mod h1:Wb7vfKAodbKgf6tn1Kl0VvGj7mRH6DGaRcixXEJXTsE= +sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= +sigs.k8s.io/structured-merge-diff/v3 v3.0.1-0.20200706213357-43c19bbb7fba h1:AAbnc5KQuTWKuh2QSnyghKIOTFzB0Jayv7/OFDn3Cy4= +sigs.k8s.io/structured-merge-diff/v3 v3.0.1-0.20200706213357-43c19bbb7fba/go.mod h1:V06abazjHneE37ZdSY/UUwPVgcJMKI/jU5XGUjgIKoc= +sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= +sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= diff --git a/pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/controller.go b/pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/controller.go new file mode 100644 index 000000000..73df882e0 --- /dev/null +++ b/pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/controller.go @@ -0,0 +1,74 @@ +/* +Copyright 2021 The Tekton Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pipelinetotaskrun + +import ( + context "context" + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + pipelineclient "github.com/tektoncd/pipeline/pkg/client/injection/client" + run "github.com/tektoncd/pipeline/pkg/client/injection/informers/pipeline/v1alpha1/run" + taskruninformer "github.com/tektoncd/pipeline/pkg/client/injection/informers/pipeline/v1beta1/taskrun" + v1alpha1run "github.com/tektoncd/pipeline/pkg/client/injection/reconciler/pipeline/v1alpha1/run" + pipelinecontroller "github.com/tektoncd/pipeline/pkg/controller" + tkncontroller "github.com/tektoncd/pipeline/pkg/controller" + "k8s.io/client-go/tools/cache" + configmap "knative.dev/pkg/configmap" + controller "knative.dev/pkg/controller" + logging "knative.dev/pkg/logging" +) + +const ( + ControllerName = "pipelinetotaskrun-controller" + kind = "PipelineToTaskRun" +) + +// NewController creates a Reconciler for Run and returns the result of NewImpl. +func NewController(ctx context.Context, cmw configmap.Watcher) *controller.Impl { + logger := logging.FromContext(ctx) + + pipelineClientSet := pipelineclient.Get(ctx) + runInformer := run.Get(ctx) + taskRunInformer := taskruninformer.Get(ctx) + + r := &Reconciler{ + pipelineClientSet: pipelineClientSet, + runLister: runInformer.Lister(), + taskRunLister: taskRunInformer.Lister(), + } + + impl := v1alpha1run.NewImpl(ctx, r, func(impl *controller.Impl) controller.Options { + return controller.Options{ + AgentName: ControllerName, + } + }) + + logger.Info("Setting up event handlers") + + // Add event handler for Runs + runInformer.Informer().AddEventHandler(cache.FilteringResourceEventHandler{ + FilterFunc: tkncontroller.FilterRunRef(v1alpha1.SchemeGroupVersion.String(), kind), + Handler: controller.HandleAll(impl.Enqueue), + }) + + // Add event handler for TaskRuns controlled by Run + taskRunInformer.Informer().AddEventHandler(cache.FilteringResourceEventHandler{ + FilterFunc: pipelinecontroller.FilterOwnerRunRef(runInformer.Lister(), v1alpha1.SchemeGroupVersion.String(), kind), + Handler: controller.HandleAll(impl.EnqueueControllerOf), + }) + + return impl +} diff --git a/pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/fetch.go b/pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/fetch.go new file mode 100644 index 000000000..8448f8e00 --- /dev/null +++ b/pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/fetch.go @@ -0,0 +1,72 @@ +/* +Copyright 2021 The Tekton Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pipelinetotaskrun + +import ( + "context" + "fmt" + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" + tektonv1beta1 "github.com/tektoncd/pipeline/pkg/client/clientset/versioned/typed/pipeline/v1beta1" + listers "github.com/tektoncd/pipeline/pkg/client/listers/pipeline/v1beta1" + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func getTaskRunIfExists(lister listers.TaskRunLister, namespace, name string) (*v1beta1.TaskRun, error) { + tr, err := lister.TaskRuns(namespace).Get(name) + if err != nil { + if errors.IsNotFound(err) { + return nil, nil + } + return nil, fmt.Errorf("couldn't fetch taskrun %v", err) + } + return tr, nil +} + +func getPipelineSpec(ctx context.Context, tv1beta1 tektonv1beta1.TektonV1beta1Interface, namespace, pipeline string) (*v1beta1.PipelineSpec, error) { + p, err := tv1beta1.Pipelines(namespace).Get(ctx, pipeline, metav1.GetOptions{}) + if err != nil { + return nil, err + } + return &p.Spec, nil +} + +func getTaskSpecs(ctx context.Context, tv1beta1 tektonv1beta1.TektonV1beta1Interface, pSpec *v1beta1.PipelineSpec, namespace string) (map[string]*v1beta1.TaskSpec, error) { + taskSpecs := map[string]*v1beta1.TaskSpec{} + for _, ptask := range pSpec.Tasks { + var taskSpec *v1beta1.TaskSpec + if ptask.TaskRef == nil { + taskSpec = &ptask.TaskSpec.TaskSpec + } else { + var err error + taskSpec, err = getTaskSpec(ctx, tv1beta1, namespace, ptask.TaskRef.Name) + if err != nil { + return nil, fmt.Errorf("couldn't fetch taskspec for %s: %v", ptask.Name, err) + } + } + taskSpecs[ptask.Name] = taskSpec + } + return taskSpecs, nil +} + +func getTaskSpec(ctx context.Context, tv1beta1 tektonv1beta1.TektonV1beta1Interface, namespace, task string) (*v1beta1.TaskSpec, error) { + t, err := tv1beta1.Tasks(namespace).Get(ctx, task, metav1.GetOptions{}) + if err != nil { + return nil, err + } + return &t.Spec, nil +} diff --git a/pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/ordering.go b/pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/ordering.go new file mode 100644 index 000000000..0de3c10e3 --- /dev/null +++ b/pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/ordering.go @@ -0,0 +1,74 @@ +/* +Copyright 2021 The Tekton Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pipelinetotaskrun + +import ( + "fmt" + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" +) + +type linkedTask struct { + task *v1beta1.PipelineTask + next *linkedTask +} + +func putTasksInOrder(tasks []v1beta1.PipelineTask) ([]v1beta1.PipelineTask, error) { + seen := map[string]*linkedTask{} + var root *linkedTask + + for i := 0; i < len(tasks); i++ { + seen[tasks[i].Name] = &linkedTask{task: &tasks[i]} + } + + for _, task := range tasks { + if len(task.RunAfter) > 1 { + return nil, fmt.Errorf("fan in not yet supported but %s has more than one runAfter", task.Name) + } + l, _ := seen[task.Name] + if len(task.RunAfter) == 0 { + if root != nil { + return nil, fmt.Errorf("parallel tasks not yet supported by %s and %s are trying to run in parallel", task.Name, root.task.Name) + } else { + root = l + } + } else { + before, ok := seen[task.RunAfter[0]] + if !ok { + return nil, fmt.Errorf("task %s trying to run after task %s which is not present", task.Name, task.RunAfter[0]) + } + before.next = l + } + } + if root == nil { + return nil, fmt.Errorf("invalid sequence, there was no starting task (probably a loop?)") + } + + ordered := []v1beta1.PipelineTask{*root.task} + curr := root.next + for { + if curr == nil { + if len(ordered) < len(tasks) { + return nil, fmt.Errorf("sequence was not completely connected, gap after %s", ordered[len(ordered)-1].Name) + } + break + } + ordered = append(ordered, *curr.task) + curr = curr.next + } + + return ordered, nil +} diff --git a/pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/ordering_test.go b/pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/ordering_test.go new file mode 100644 index 000000000..56ebed8b7 --- /dev/null +++ b/pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/ordering_test.go @@ -0,0 +1,154 @@ +package pipelinetotaskrun + +import ( + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" + "testing" +) + +func TestPutTasksInOrderUnsupported(t *testing.T) { + for _, tc := range []struct { + name string + tasks []v1beta1.PipelineTask + }{{ + name: "parallel", + tasks: []v1beta1.PipelineTask{{ + Name: "starts", + }, { + Name: "alsostarts", + }}, + }, { + name: "fan in", + tasks: []v1beta1.PipelineTask{{ + Name: "out1", + }, { + Name: "out2", + }, { + Name: "in", + RunAfter: []string{"out1", "out2"}, + }}, + }, { + name: "fan out", + tasks: []v1beta1.PipelineTask{{ + Name: "first", + }, { + Name: "out1", + RunAfter: []string{"first"}, + }, { + Name: "out2", + RunAfter: []string{"first"}, + }}, + }, { + name: "cycle", + tasks: []v1beta1.PipelineTask{{ + Name: "first", + RunAfter: []string{"second"}, + }, { + Name: "second", + RunAfter: []string{"first"}, + }}, + }} { + t.Run(tc.name, func(t *testing.T) { + _, err := putTasksInOrder(tc.tasks) + if err == nil { + t.Fatalf("expected error for unsupported tasks but got none") + } + }) + } +} + +func TestPutTasksInOrder(t *testing.T) { + for _, tc := range []struct { + name string + tasks []v1beta1.PipelineTask + expectedOrder []string + }{{ + name: "oneTask", + tasks: []v1beta1.PipelineTask{{ + Name: "first", + }}, + expectedOrder: []string{"first"}, + }, { + name: "twoTask", + tasks: []v1beta1.PipelineTask{{ + Name: "first", + }, { + Name: "second", + RunAfter: []string{"first"}, + }}, + expectedOrder: []string{"first", "second"}, + }, { + name: "twoTaskReversed", + tasks: []v1beta1.PipelineTask{{ + Name: "second", + RunAfter: []string{"first"}, + }, { + Name: "first", + }}, + expectedOrder: []string{"first", "second"}, + }, { + name: "threeTask", + tasks: []v1beta1.PipelineTask{{ + Name: "first", + }, { + Name: "second", + RunAfter: []string{"first"}, + }, { + Name: "third", + RunAfter: []string{"second"}, + }}, + expectedOrder: []string{"first", "second", "third"}, + }, { + name: "threeTaskUnordered1", + tasks: []v1beta1.PipelineTask{{ + Name: "second", + RunAfter: []string{"first"}, + }, { + Name: "third", + RunAfter: []string{"second"}, + }, { + Name: "first", + }}, + expectedOrder: []string{"first", "second", "third"}, + }, { + name: "threeTaskUnordered2", + tasks: []v1beta1.PipelineTask{{ + Name: "third", + RunAfter: []string{"second"}, + }, { + Name: "first", + }, { + Name: "second", + RunAfter: []string{"first"}, + }}, + expectedOrder: []string{"first", "second", "third"}, + }, { + name: "threeTaskReversed", + tasks: []v1beta1.PipelineTask{{ + Name: "third", + RunAfter: []string{"second"}, + }, { + Name: "second", + RunAfter: []string{"first"}, + }, { + Name: "first", + }}, + expectedOrder: []string{"first", "second", "third"}, + }} { + t.Run(tc.name, func(t *testing.T) { + sequence, err := putTasksInOrder(tc.tasks) + if err != nil { + t.Fatalf("did not expect error but got %v", err) + } + if len(sequence) != len(tc.expectedOrder) { + t.Fatalf("returned sequence had length %d but expected %d", len(sequence), len(tc.expectedOrder)) + } + for i := 0; i < len(sequence); i++ { + if sequence[i].Name != tc.expectedOrder[i] { + t.Errorf("expected %s in position %d but got %s", tc.expectedOrder[i], i, sequence[i].Name) + } + } + + }) + } +} + diff --git a/pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/pipelinetotaskrun.go b/pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/pipelinetotaskrun.go new file mode 100644 index 000000000..33f5e74bf --- /dev/null +++ b/pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/pipelinetotaskrun.go @@ -0,0 +1,257 @@ +/* +Copyright 2021 The Tekton Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pipelinetotaskrun + +import ( + "context" + "encoding/json" + "fmt" + "reflect" + "time" + + "github.com/hashicorp/go-multierror" + "github.com/tektoncd/pipeline/pkg/apis/pipeline" + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" + clientset "github.com/tektoncd/pipeline/pkg/client/clientset/versioned" + "github.com/tektoncd/pipeline/pkg/client/injection/reconciler/pipeline/v1alpha1/run" + listersalpha "github.com/tektoncd/pipeline/pkg/client/listers/pipeline/v1alpha1" + listers "github.com/tektoncd/pipeline/pkg/client/listers/pipeline/v1beta1" + "github.com/tektoncd/pipeline/pkg/reconciler/events" + "go.uber.org/zap" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "knative.dev/pkg/apis" + "knative.dev/pkg/controller" + "knative.dev/pkg/logging" + "knative.dev/pkg/reconciler" +) + +const ( + // ReasonRunFailedValidation indicates that the reason for failure status is that Run failed validation + ReasonRunFailedValidation = "ReasonRunFailedValidation" + + // ReasonRunFailedCreatingPipelineRun indicates that the reason for failure status is that Run failed + // to create PipelineRun + ReasonRunFailedCreatingPipelineRun = "ReasonRunFailedCreatingPipelineRun" +) + +// Reconciler implements controller.Reconciler for Run resources. +type Reconciler struct { + pipelineClientSet clientset.Interface + runLister listersalpha.RunLister + taskRunLister listers.TaskRunLister +} + +// Check that our Reconciler implements Interface +var _ run.Interface = (*Reconciler)(nil) + +// ReconcileKind implements Interface.ReconcileKind. +func (r *Reconciler) ReconcileKind(ctx context.Context, run *v1alpha1.Run) reconciler.Event { + logger := logging.FromContext(ctx) + + if run.Spec.Ref == nil || + run.Spec.Ref.APIVersion != v1alpha1.SchemeGroupVersion.String() || run.Spec.Ref.Kind != kind { + logger.Warn("Should not have been notified about Run %s/%s; will do nothing", run.Namespace, run.Name) + return nil + } + + logger.Infof("Reconciling Run %s/%s at %v", run.Namespace, run.Name, time.Now()) + + // If the Run has not started, initialize the Condition and set the start time. + if !run.HasStarted() { + logger.Infof("Starting new Run %s/%s", run.Namespace, run.Name) + run.Status.InitializeConditions() + // In case node time was not synchronized, when controller has been scheduled to other nodes. + if run.Status.StartTime.Sub(run.CreationTimestamp.Time) < 0 { + logger.Warnf("Run %s/%s createTimestamp %s is after the Run started %s", run.Namespace, run.Name, run.CreationTimestamp, run.Status.StartTime) + run.Status.StartTime = &run.CreationTimestamp + } + // Send the "Started" event + afterCondition := run.Status.GetCondition(apis.ConditionSucceeded) + events.Emit(ctx, nil, afterCondition, run) + } + + if run.IsDone() { + logger.Infof("Run %s/%s is done", run.Namespace, run.Name) + return nil + } + + var merr error + + beforeCondition := run.Status.GetCondition(apis.ConditionSucceeded) + + if err := r.reconcile(ctx, run); err != nil { + logger.Errorf("Reconcile error: %v", err.Error()) + merr = multierror.Append(merr, controller.NewPermanentError(err)) + } + + if err := r.updateLabelsAndAnnotations(ctx, run); err != nil { + logger.Warn("Failed to update Run labels/annotations", zap.Error(err)) + merr = multierror.Append(merr, err) + } + + afterCondition := run.Status.GetCondition(apis.ConditionSucceeded) + events.Emit(ctx, beforeCondition, afterCondition, run) + + // Only transient errors that should retry the reconcile are returned + return merr + +} + +func (r *Reconciler) reconcile(ctx context.Context, run *v1alpha1.Run) error { + logger := logging.FromContext(ctx) + + // confirm the run spec is valid + if err := validateRun(run); err != nil { + logger.Errorf("Run %s/%s is invalid because of %v", run.Namespace, run.Name, err) + run.Status.MarkRunFailed(ReasonRunFailedValidation, + "Run has an invalid spec: %v", err) + return controller.NewPermanentError(fmt.Errorf("run %s/%s is invalid because of %v", run.Namespace, run.Name, err)) + } + + // fetch the taskrun and, if present, update the run status + tr, err := getTaskRunIfExists(r.taskRunLister, run.Namespace, run.Name) + if err != nil { + logger.Errorf("Run %s/%s got an error fetching taskRun: %v", run.Namespace, run.Name, err) + return fmt.Errorf("couldn't fetch taskrun %v", err) + } + if tr != nil { + logger.Infof("Found a TaskRun object %s", tr.Name) + return updateRunStatus(ctx, run, tr) + } + + // get the pipeline that we're going to be running in a taskrun + pSpec, err := getPipelineSpec(ctx, r.pipelineClientSet.TektonV1beta1(), run.Namespace, run.Spec.Ref.Name) + if err != nil { + run.Status.MarkRunFailed(ReasonRunFailedValidation, + "Pipeline couldn't be fetched - %v", err) + return controller.NewPermanentError(fmt.Errorf("run %s/%s is invalid because of %v", run.Namespace, run.Name, err)) + return fmt.Errorf("couldn't fetch pipeline spec %s: %v", run.Spec.Ref.Name, err) + } + if err := validatePipelineSpec(pSpec); err != nil { + run.Status.MarkRunFailed(ReasonRunFailedValidation, + "Pipeline is invalid - %v", err) + return fmt.Errorf("pipeline spec for %s is invalid: %v", run.Spec.Ref.Name, err) + } + + // get all the tasks we need to run this pipeline + taskSpecs, err := getTaskSpecs(ctx, r.pipelineClientSet.TektonV1beta1(), pSpec, run.Namespace) + if err != nil { + run.Status.MarkRunFailed(ReasonRunFailedValidation, + "Not all of the pipeline's tasks could be fetched - %v", err) + return fmt.Errorf("couldn't fetch pipeline's tasks: %v", err) + } + if err := validateTaskSpecs(taskSpecs); err != nil { + run.Status.MarkRunFailed(ReasonRunFailedValidation, + "Not all tasks are valid - %v", err) + return fmt.Errorf("pipeline's tasks are invalid: %v", err) + } + + tr, err = getMergedTaskRun(run, pSpec, taskSpecs) + if err != nil { + run.Status.MarkRunFailed(ReasonRunFailedValidation, + "Could not create TaskRun for the pipeline - %v", err) + return fmt.Errorf("couldn't create taskrun for pipeline %s: %v", run.Spec.Ref.Name, err) + } + + logger.Infof("Creating a new TaskRun object %s", tr.Name) + if _, err := r.pipelineClientSet.TektonV1beta1().TaskRuns(run.Namespace).Create(ctx, tr, metav1.CreateOptions{}); err != nil { + logger.Errorf("Run %s/%s got an error creating TaskRun - %v", run.Namespace, run.Name, err) + run.Status.MarkRunFailed(ReasonRunFailedCreatingPipelineRun, + "Run got an error creating pipelineRun - %v", err) + return err + } + + return nil +} + +func updateRunStatus(ctx context.Context, run *v1alpha1.Run, taskRun *v1beta1.TaskRun) error { + logger := logging.FromContext(ctx) + + c := taskRun.GetStatusCondition().GetCondition(apis.ConditionSucceeded) + if c.IsTrue() { + logger.Infof("TaskRun created by Run %s/%s has succeeded", run.Namespace, run.Name) + run.Status.MarkRunSucceeded(c.Reason, c.Message) + } else if c.IsFalse() { + logger.Infof("TaskRun created by Run %s/%s has failed", run.Namespace, run.Name) + run.Status.MarkRunFailed(c.Reason, c.Message) + } else if c.IsUnknown() { + logger.Infof("TaskRun created by Run %s/%s is still running", run.Namespace, run.Name) + + reason, message := "", "" + if c != nil { + reason, message = c.Reason, c.Message + } + run.Status.MarkRunRunning(reason, message) + } else { + logger.Errorf("TaskRun created by Run %s/%s has an unexpected ConditionSucceeded", run.Namespace, run.Name) + return fmt.Errorf("unexpected ConditionSucceded - %s", c) + } + + return nil +} + +func getObjectMeta(run *v1alpha1.Run) metav1.ObjectMeta { + return metav1.ObjectMeta{ + Name: run.Name, + Namespace: run.Namespace, + OwnerReferences: []metav1.OwnerReference{run.GetOwnerReference()}, + Labels: getLabels(run), + Annotations: getAnnotations(run), + } +} + + +func getLabels(run *v1alpha1.Run) map[string]string { + labels := make(map[string]string, len(run.ObjectMeta.Labels)+1) + for key, val := range run.ObjectMeta.Labels { + labels[key] = val + } + labels[pipeline.GroupName+pipeline.RunKey] = run.Name + return labels +} + +func getAnnotations(run *v1alpha1.Run) map[string]string { + annotations := make(map[string]string, len(run.ObjectMeta.Annotations)+1) + for key, val := range run.ObjectMeta.Annotations { + annotations[key] = val + } + return annotations +} + +func (r *Reconciler) updateLabelsAndAnnotations(ctx context.Context, run *v1alpha1.Run) error { + newRun, err := r.runLister.Runs(run.Namespace).Get(run.Name) + if err != nil { + return fmt.Errorf("error getting Run %s when updating labels/annotations: %w", run.Name, err) + } + if !reflect.DeepEqual(run.ObjectMeta.Labels, newRun.ObjectMeta.Labels) || !reflect.DeepEqual(run.ObjectMeta.Annotations, newRun.ObjectMeta.Annotations) { + mergePatch := map[string]interface{}{ + "metadata": map[string]interface{}{ + "labels": run.ObjectMeta.Labels, + "annotations": run.ObjectMeta.Annotations, + }, + } + patch, err := json.Marshal(mergePatch) + if err != nil { + return err + } + _, err = r.pipelineClientSet.TektonV1alpha1().Runs(run.Namespace).Patch(ctx, run.Name, types.MergePatchType, patch, metav1.PatchOptions{}) + return err + } + return nil +} diff --git a/pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/pipelinetotaskrun_test.go b/pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/pipelinetotaskrun_test.go new file mode 100644 index 000000000..97dab16c0 --- /dev/null +++ b/pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/pipelinetotaskrun_test.go @@ -0,0 +1,1009 @@ +/* + Copyright 2021 The Tekton Authors + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package pipelinetotaskrun + +import ( + "context" + "fmt" + "github.com/google/go-cmp/cmp/cmpopts" + "io/ioutil" + "strings" + "testing" + "time" + + "github.com/google/go-cmp/cmp" + "github.com/tektoncd/experimental/pipeline-to-taskrun/test" + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" + ttesting "github.com/tektoncd/pipeline/pkg/reconciler/testing" + "github.com/tektoncd/pipeline/test/diff" + "github.com/tektoncd/pipeline/test/names" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + ktesting "k8s.io/client-go/testing" + "k8s.io/client-go/tools/record" + "knative.dev/pkg/apis" + "knative.dev/pkg/configmap" + "knative.dev/pkg/controller" + "knative.dev/pkg/logging" + "knative.dev/pkg/reconciler" +) + +func getController(t *testing.T, d test.Data) (test.Assets, func()) { + ctx, _ := ttesting.SetupFakeContext(t) + ctx, cancel := context.WithCancel(ctx) + c, informers := test.SeedTestData(t, ctx, d) + + configMapWatcher := configmap.NewStaticWatcher() + ctl := NewController(ctx, configMapWatcher) + + if la, ok := ctl.Reconciler.(reconciler.LeaderAware); ok { + la.Promote(reconciler.UniversalBucket(), func(reconciler.Bucket, types.NamespacedName) {}) + } + if err := configMapWatcher.Start(ctx.Done()); err != nil { + t.Fatalf("error starting configmap watcher: %v", err) + } + + return test.Assets{ + Logger: logging.FromContext(ctx), + Controller: ctl, + Clients: c, + Informers: informers, + Recorder: controller.GetEventRecorder(ctx).(*record.FakeRecorder), + }, cancel +} + +func checkRunCondition(t *testing.T, run *v1alpha1.Run, expectedStatus corev1.ConditionStatus, expectedReason string, expectedMessage string) error { + failed := false + condition := run.Status.GetCondition(apis.ConditionSucceeded) + if condition == nil { + t.Error("Condition missing in Run") + failed = true + } else { + if condition.Status != expectedStatus { + t.Errorf("Expected Run status to be %v but was %v", expectedStatus, condition) + failed = true + } + if condition.Reason != expectedReason { + t.Errorf("Expected reason to be %q but was %q", expectedReason, condition.Reason) + failed = true + } + if condition.Message != expectedMessage { + t.Errorf("Expected message to be %q but was %q", expectedMessage, condition.Message) + failed = true + } + } + if run.Status.StartTime == nil { + t.Errorf("Expected Run start time to be set but it wasn't") + failed = true + } + if expectedStatus == corev1.ConditionUnknown { + if run.Status.CompletionTime != nil { + t.Errorf("Expected Run completion time to not be set but it was") + failed = true + } + } else if run.Status.CompletionTime == nil { + t.Errorf("Expected Run completion time to be set but it wasn't") + failed = true + } + if failed { + return fmt.Errorf("run was invalid") + } + return nil +} + +func checkEvents(fr *record.FakeRecorder, testName string, wantEvents []string) error { + // The fake recorder runs in a go routine, so the timeout is here to avoid waiting + // on the channel forever if fewer than expected events are received. + // We only hit the timeout in case of failure of the test, so the actual value + // of the timeout is not so relevant. It's only used when tests are going to fail. + timer := time.NewTimer(1 * time.Second) + foundEvents := []string{} + for ii := 0; ii < len(wantEvents)+1; ii++ { + // We loop over all the events that we expect. Once they are all received + // we exit the loop. If we never receive enough events, the timeout takes us + // out of the loop. + select { + case event := <-fr.Events: + foundEvents = append(foundEvents, event) + if ii > len(wantEvents)-1 { + return fmt.Errorf(`received extra event "%s" for test "%s"`, event, testName) + } + wantEvent := wantEvents[ii] + if !(strings.HasPrefix(event, wantEvent)) { + return fmt.Errorf(`expected event "%s" but got "%s" instead for test "%s"`, wantEvent, event, testName) + } + case <-timer.C: + if len(foundEvents) > len(wantEvents) { + return fmt.Errorf(`received %d events but %d expected for test "%s". Found events: %#v`, len(foundEvents), len(wantEvents), testName, foundEvents) + } + } + } + return nil +} + +func getRunName(run *v1alpha1.Run) string { + return strings.Join([]string{run.Namespace, run.Name}, "/") +} + +func getCreatedTaskRun(clients test.Clients) *v1beta1.TaskRun { + for _, a := range clients.Pipeline.Actions() { + if a.GetVerb() == "create" { + obj := a.(ktesting.CreateAction).GetObject() + if tr, ok := obj.(*v1beta1.TaskRun); ok { + return tr + } + } + } + return nil +} + +func running(tr *v1beta1.TaskRun) *v1beta1.TaskRun { + trWithStatus := tr.DeepCopy() + trWithStatus.Status.SetCondition(&apis.Condition{ + Type: apis.ConditionSucceeded, + Status: corev1.ConditionUnknown, + Reason: v1beta1.TaskRunReasonRunning.String(), + }) + return trWithStatus +} + +func successful(tr *v1beta1.TaskRun) *v1beta1.TaskRun { + trWithStatus := tr.DeepCopy() + trWithStatus.Status.SetCondition(&apis.Condition{ + Type: apis.ConditionSucceeded, + Status: corev1.ConditionTrue, + Reason: v1beta1.TaskRunReasonSuccessful.String(), + }) + return trWithStatus +} + +func failed(tr *v1beta1.TaskRun) *v1beta1.TaskRun { + trWithStatus := tr.DeepCopy() + trWithStatus.Status.SetCondition(&apis.Condition{ + Type: apis.ConditionSucceeded, + Status: corev1.ConditionFalse, + Reason: v1beta1.TaskRunReasonFailed.String(), + }) + return trWithStatus +} + +var p = &v1beta1.Pipeline{ + ObjectMeta: metav1.ObjectMeta{ + Name: "pipeline", + Namespace: "foo", + }, + Spec: v1beta1.PipelineSpec{ + Tasks: []v1beta1.PipelineTask{{ + Name: "task", + TaskSpec: &v1beta1.EmbeddedTask{TaskSpec: v1beta1.TaskSpec{ + Steps: []v1beta1.Step{{Container: corev1.Container{ + Image: "ubuntu", + Command: []string{"/bin/bash"}, + Args: []string{"-c", "echo hello world"}, + }}}, + }}, + }}, + }, +} + +var blockOwnerDeletion = true +var isController = true +var tr = &v1beta1.TaskRun{ + ObjectMeta: metav1.ObjectMeta{ + Name: "run-with-pipeline", + Namespace: "foo", + Labels: map[string]string{ + "tekton.dev/run": "run-with-pipeline", + }, + OwnerReferences: []v1.OwnerReference{ + { + APIVersion: "tekton.dev/v1alpha1", + Kind: "Run", + Name: "run-with-pipeline", + Controller: &isController, + BlockOwnerDeletion: &blockOwnerDeletion, + }, + }, + Annotations: map[string]string{}, + }, + Spec: v1beta1.TaskRunSpec{ + ServiceAccountName: "default", + TaskSpec: &v1beta1.TaskSpec{ + Steps: []v1beta1.Step{{Container: corev1.Container{ + Image: "ubuntu", + Command: []string{"/bin/bash"}, + Args: []string{"-c", "echo hello world"}, + }}}, + }, + }, +} + +var runWithPipeline = &v1alpha1.Run{ + ObjectMeta: metav1.ObjectMeta{ + Name: "run-with-pipeline", + Namespace: "foo", + }, + Spec: v1alpha1.RunSpec{ + Ref: &v1alpha1.TaskRef{ + APIVersion: "tekton.dev/v1alpha1", + Kind: "PipelineToTaskRun", + Name: "pipeline", + }, + }, +} + +var runWithoutPipelineName = &v1alpha1.Run{ + ObjectMeta: metav1.ObjectMeta{ + Name: "run-with-missing-pipeline", + Namespace: "foo", + }, + Spec: v1alpha1.RunSpec{ + Ref: &v1alpha1.TaskRef{ + APIVersion: "tekton.dev/v1alpha1", + Kind: "PipelineToTaskRun", + }, + }, +} + +var runWithoutKind = &v1alpha1.Run{ + ObjectMeta: metav1.ObjectMeta{ + Name: "run-with-missing-pipeline", + Namespace: "foo", + }, + Spec: v1alpha1.RunSpec{ + Ref: &v1alpha1.TaskRef{ + APIVersion: "tekton.dev/v1alpha1", + Name: "pipeline", + }, + }, +} + +var runWithoutAPIVersion = &v1alpha1.Run{ + ObjectMeta: metav1.ObjectMeta{ + Name: "run-with-missing-pipeline", + Namespace: "foo", + }, + Spec: v1alpha1.RunSpec{ + Ref: &v1alpha1.TaskRef{ + Kind: "PipelineToTaskRun", + Name: "pipeline", + }, + }, +} + +func TestReconcile(t *testing.T) { + testcases := []struct { + name string + pipeline *v1beta1.Pipeline + run *v1alpha1.Run + taskRun *v1beta1.TaskRun + expectedStatus corev1.ConditionStatus + expectedReason v1beta1.TaskRunReason + expectedMessage string + expectedEvents []string + expectedTaskRun *v1beta1.TaskRun + }{{ + name: "Reconcile a new run that references a pipeline", + pipeline: p, + run: runWithPipeline, + expectedTaskRun: tr, + expectedStatus: corev1.ConditionUnknown, + expectedReason: v1beta1.TaskRunReasonStarted, + expectedEvents: []string{ + "Normal Started ", + }, + }, { + name: "Reconcile a run with a running TaskRun", + pipeline: p, + run: runWithPipeline, + taskRun: running(tr), + expectedStatus: corev1.ConditionUnknown, + expectedReason: v1beta1.TaskRunReasonRunning, + expectedEvents: []string{ + "Normal Started ", + "Normal Running ", + }, + }, { + name: "Reconcile a run with a failed PipelineRun", + pipeline: p, + run: runWithPipeline, + taskRun: failed(tr), + expectedStatus: corev1.ConditionFalse, + expectedReason: v1beta1.TaskRunReasonFailed, + expectedEvents: []string{ + "Normal Started ", + "Warning Failed ", + }, + }, { + name: "Reconcile a run with a successful PipelineRun", + pipeline: p, + run: runWithPipeline, + taskRun: successful(tr), + expectedStatus: corev1.ConditionTrue, + expectedReason: v1beta1.TaskRunReasonSuccessful, + expectedEvents: []string{ + "Normal Started ", + "Normal Succeeded ", + }, + }, + } + for _, tc := range testcases { + t.Run(tc.name, func(t *testing.T) { + ctx := context.Background() + names.TestingSeed() + + optionalTaskRuns := []*v1beta1.TaskRun{tc.taskRun} + if tc.taskRun == nil { + optionalTaskRuns = nil + } + + d := test.Data{ + Runs: []*v1alpha1.Run{tc.run}, + Pipelines: []*v1beta1.Pipeline{tc.pipeline}, + TaskRuns: optionalTaskRuns, + } + + testAssets, _ := getController(t, d) + + if err := testAssets.Controller.Reconciler.Reconcile(ctx, getRunName(tc.run)); err != nil { + t.Fatalf("couldn't reconcile run %v", err) + } + + run, err := testAssets.Clients.Pipeline.TektonV1alpha1().Runs(tc.run.Namespace).Get(ctx, tc.run.Name, metav1.GetOptions{}) + if err != nil { + t.Fatalf("Error getting reconciled run from fake client: %s", err) + } + + createdTaskRun := getCreatedTaskRun(testAssets.Clients) + if tc.expectedTaskRun != nil { + if createdTaskRun == nil { + t.Fatalf("A TaskRun should have been created but was not") + } else { + if d := cmp.Diff(tc.expectedTaskRun, createdTaskRun); d != "" { + t.Errorf("Expected TaskRun was not created. Diff %s", diff.PrintWantGot(d)) + } + } + } + + if err := checkRunCondition(t, run, tc.expectedStatus, tc.expectedReason.String(), tc.expectedMessage); err != nil { + t.Fatalf("run is invalid") + } + + if err := checkEvents(testAssets.Recorder, tc.name, tc.expectedEvents); err != nil { + t.Errorf(err.Error()) + } + }) + } +} + +func fromFile(t *testing.T, filename string) string { + b, err := ioutil.ReadFile(filename) + if err != nil { + t.Fatalf("couldn't load test data %s from file: %v", filename, err) + } + return string(b) +} + +func createDataFromFiles(t *testing.T) test.Data { + ns := "some-ns" + taskFiles := []string{"testdata/gcs-upload.yaml", "testdata/git-clone.yaml", "testdata/go-test.yaml"} + tasks := []*v1beta1.Task{} + for i, taskFile := range taskFiles { + tasks = append(tasks, test.MustParseTask(t, fromFile(t, taskFile))) + tasks[i].Namespace = ns + } + examplePath := "../../../examples" + pipeline := test.MustParsePipeline(t, fromFile(t, examplePath+"/clone-test-upload.yaml")) + run := test.MustParseRun(t, fromFile(t, examplePath+"/pipeline-taskrun-run.yaml")) + + run.Name = "some-run" + pipeline.Namespace = ns + run.Namespace = ns + + return test.Data{ + Runs: []*v1alpha1.Run{run}, + Pipelines: []*v1beta1.Pipeline{pipeline}, + Tasks: tasks, + } +} + +func TestReconcileComplexPipeline(t *testing.T) { + ctx := context.Background() + names.TestingSeed() + + d := createDataFromFiles(t) + run := d.Runs[0] + + testAssets, _ := getController(t, d) + + if err := testAssets.Controller.Reconciler.Reconcile(ctx, getRunName(run)); err != nil { + t.Fatalf("couldn't reconcile run %v", err) + } + + run, err := testAssets.Clients.Pipeline.TektonV1alpha1().Runs(run.Namespace).Get(ctx, run.Name, metav1.GetOptions{}) + if err != nil { + t.Fatalf("Error getting reconciled run from fake client: %s", err) + } + + expectedTaskRun := test.MustParseTaskRun(t, fromFile(t, "testdata/expected-taskrun.yaml")) + createdTaskRun := getCreatedTaskRun(testAssets.Clients) + + if createdTaskRun == nil { + t.Fatalf("A TaskRun should have been created but was not") + } + + if d := cmp.Diff(expectedTaskRun.ObjectMeta, createdTaskRun.ObjectMeta, + // empty lists are defaulted differently between the yaml parsing and reconciling + cmpopts.EquateEmpty()); d != "" { + t.Errorf("TaskRun metadata was different from expected: %s", diff.PrintWantGot(d)) + } + // string is the default type for params; the version loaded from yaml won't have this set explicitly + ignoreString := cmpopts.IgnoreFields(v1beta1.ParamSpec{}, "Type") + if d := cmp.Diff(expectedTaskRun.Spec, createdTaskRun.Spec, ignoreString); d != "" { + t.Errorf("TaskRun spec was different from expected: %s", diff.PrintWantGot(d)) + } + condition := run.Status.GetCondition(apis.ConditionSucceeded) + if condition.Status != corev1.ConditionUnknown { + t.Errorf("exepcted run to be marked executing but condition was %v", condition) + } +} + +func TestReconcileUnsupported(t *testing.T) { + run := ` +metadata: + name: run-with-pipeline + namespace: foo +spec: + ref: + apiVersion: tekton.dev/v1alpha1 + kind: PipelineToTaskRun + name: pipeline +` + testcases := []struct { + name string + expectedErrText []string + pipeline *v1beta1.Pipeline + run *v1alpha1.Run + }{{ + name: "pipeline results - TODO (community#447)", + expectedErrText: []string{"results"}, + pipeline: test.MustParsePipeline(t, ` +metadata: + name: pipeline + namespace: foo +spec: + tasks: + - name: make-result + taskSpec: + steps: + - image: ubuntu + results: + - name: amazing + results: + - name: amazing-result + value: $(tasks.make-result.results.amazing) +`), + run: test.MustParseRun(t, run), + }, { + name: "array params - TODO (community#447)", + expectedErrText: []string{"array"}, + pipeline: test.MustParsePipeline(t, ` +metadata: + name: pipeline + namespace: foo +spec: + tasks: + - name: make-result + taskSpec: + params: + - name: foo + type: array +`), + run: test.MustParseRun(t, run), + }, { + name: "workspaces with subpaths in run binding - TODO(community#447)", + expectedErrText: []string{"spec.workspaces.subpath"}, + pipeline: test.MustParsePipeline(t, ` +metadata: + name: pipeline + namespace: foo +spec: + tasks: + - name: use-workspace + taskSpec: + steps: + - image: ubuntu + workspaces: + - name: task-workspace + workspaces: + - name: task-workspace + workspace: pipeline-workspace + workspaces: + - name: pipeline-workspace +`), + run: test.MustParseRun(t, run+` + workspaces: + - name: pipeline-workspace + persistentVolumeClaim: + claimName: pvc + subPath: some/subdir +`), + }, { + name: "workspaces with subpaths pipelinetasks - TODO(community#447)", + expectedErrText: []string{"subpath"}, + pipeline: test.MustParsePipeline(t, ` +metadata: + name: pipeline + namespace: foo +spec: + tasks: + - name: use-workspace + taskSpec: + steps: + - image: ubuntu + workspaces: + - name: task-workspace + workspaces: + - name: task-workspace + workspace: pipeline-workspace + subPath: some/subdir + workspaces: + - name: pipeline-workspace +`), + run: test.MustParseRun(t, run+` + workspaces: + - name: pipeline-workspace + persistentVolumeClaim: + claimName: pvc +`), + }, { + name: "workspaces with mountpaths - TODO(community#447)", + expectedErrText: []string{"mountPath"}, + pipeline: test.MustParsePipeline(t, ` +metadata: + name: pipeline + namespace: foo +spec: + tasks: + - name: use-workspace + taskSpec: + steps: + - image: ubuntu + workspaces: + - name: task-workspace + mountPath: /foo/bar/ + workspaces: + - name: task-workspace + workspace: pipeline-workspace + workspaces: + - name: pipeline-workspace +`), + run: test.MustParseRun(t, run+` + workspaces: + - name: pipeline-workspace + persistentVolumeClaim: + claimName: pvc +`), + }, { + name: "workspaces with readonly - TODO(community#447)", + expectedErrText: []string{"readOnly"}, + pipeline: test.MustParsePipeline(t, ` +metadata: + name: pipeline + namespace: foo +spec: + tasks: + - name: use-workspace + taskSpec: + steps: + - image: ubuntu + workspaces: + - name: task-workspace + readOnly: true + workspaces: + - name: task-workspace + workspace: pipeline-workspace + workspaces: + - name: pipeline-workspace +`), + run: test.MustParseRun(t, run+` + workspaces: + - name: pipeline-workspace + persistentVolumeClaim: + claimName: pvc +`), + }, { + name: "isolated workspaces - TODO(community#447)", + expectedErrText: []string{"isolated"}, + pipeline: test.MustParsePipeline(t, ` +metadata: + name: pipeline + namespace: foo +spec: + tasks: + - name: use-workspace + taskSpec: + steps: + - image: ubuntu + workspaces: + - name: task-workspace + workspaces: + - name: task-workspace + workspaces: + - name: task-workspace + workspace: pipeline-workspace + workspaces: + - name: pipeline-workspace +`), + run: test.MustParseRun(t, run+` + workspaces: + - name: pipeline-workspace + persistentVolumeClaim: + claimName: pvc +`), + }, { + name: "optional workspaces - TODO(community#447)", + expectedErrText: []string{"optional"}, + pipeline: test.MustParsePipeline(t, ` +metadata: + name: pipeline + namespace: foo +spec: + tasks: + - name: use-workspace + taskSpec: + steps: + - image: ubuntu + workspaces: + - name: task-workspace + optional: true + workspaces: + - name: task-workspace + workspace: pipeline-workspace + workspaces: + - name: pipeline-workspace +`), + run: test.MustParseRun(t, run), + }, { + name: "embedded tasks with labels and annotations - TODO(community#447)", + expectedErrText: []string{"label", "annotation"}, + pipeline: test.MustParsePipeline(t, ` +metadata: + name: pipeline + namespace: foo +spec: + tasks: + - name: some-task + taskSpec: + metadata: + labels: + some-key: some-value + annotations: + description: this embedded task uses labels and annotations + steps: + - image: ubuntu +`), + run: test.MustParseRun(t, run), + }, { + name: "results between tasks", + expectedErrText: []string{"result"}, + pipeline: test.MustParsePipeline(t, ` +metadata: + name: pipeline + namespace: foo +spec: + tasks: + - name: make-result + taskSpec: + steps: + - image: ubuntu + results: + - name: amazing + - name: use-result + params: + - name: foo + value: $(tasks.make-result.results.amazing) + taskSpec: + params: + - name: foo + steps: + - image: ubuntu +`), + run: test.MustParseRun(t, run), + }, { + name: "task with sidecar", + expectedErrText: []string{"sidecar"}, + pipeline: test.MustParsePipeline(t, ` +metadata: + name: pipeline + namespace: foo +spec: + tasks: + - name: use-sidecar + taskSpec: + steps: + - image: ubuntu + sidecars: + - image: ubuntu +`), + run: test.MustParseRun(t, run), + }, { + name: "tasks as bundles", + expectedErrText: []string{"bundle"}, + pipeline: test.MustParsePipeline(t, ` +metadata: + name: pipeline + namespace: foo +spec: + tasks: + - name: use-bundle + taskRef: + name: echo-task + bundle: docker.com/myrepo/mycatalog +`), + run: test.MustParseRun(t, run), + }, { + name: "pipeline task timeouts", + expectedErrText: []string{"timeout"}, + pipeline: test.MustParsePipeline(t, ` +metadata: + name: pipeline + namespace: foo +spec: + tasks: + - name: some-task + timeout: "0h1m30s" + taskSpec: + steps: + - image: ubuntu +`), + run: test.MustParseRun(t, run), + }, { + name: "retries", + expectedErrText: []string{"retries"}, + pipeline: test.MustParsePipeline(t, ` +metadata: + name: pipeline + namespace: foo +spec: + tasks: + - name: some-task + retries: 1 + taskSpec: + steps: + - image: ubuntu +`), + run: test.MustParseRun(t, run), + }, { + name: "when expressions - new approach required to support", + expectedErrText: []string{"when"}, + pipeline: test.MustParsePipeline(t, ` +metadata: + name: pipeline + namespace: foo +spec: + tasks: + - name: some-task + when: + - input: "foo" + operator: in + values: ["bar"] + taskSpec: + steps: + - image: ubuntu +`), + run: test.MustParseRun(t, run), + }, { + name: "finally tasks - new approach required to support", + expectedErrText: []string{"finally"}, + pipeline: test.MustParsePipeline(t, ` +metadata: + name: pipeline + namespace: foo +spec: + tasks: + - name: some-task + taskSpec: + steps: + - image: ubuntu + finally: + - name: some-finally-task + taskSpec: + steps: + - image: ubuntu +`), + run: test.MustParseRun(t, run), + }, { + name: "parallel tasks (two, starting immediately) - new approach required to support", + expectedErrText: []string{"parallel"}, + pipeline: test.MustParsePipeline(t, ` +metadata: + name: pipeline + namespace: foo +spec: + tasks: + - name: a-parallel-task + taskSpec: + steps: + - image: ubuntu + - name: another-parallel-task + taskSpec: + steps: + - image: ubuntu +`), + run: test.MustParseRun(t, run), + }, { + name: "parallel tasks (branch after first task) - new approach required to support", + expectedErrText: []string{"parallel"}, + pipeline: test.MustParsePipeline(t, ` +metadata: + name: pipeline + namespace: foo +spec: + tasks: + - name: first-task + taskSpec: + steps: + - image: ubuntu + - name: a-parallel-task + runAfter: [first-task] + taskSpec: + steps: + - image: ubuntu + - name: another-parallel-task + runAfter: [first-task] + taskSpec: + steps: + - image: ubuntu +`), + run: test.MustParseRun(t, run), + }, { + name: "custom tasks - new approach required to support", + expectedErrText: []string{"custom task"}, + pipeline: test.MustParsePipeline(t, ` +metadata: + name: pipeline + namespace: foo +spec: + tasks: + - name: use-custom-task + taskRef: + apiVersion: tekton.dev/v1alpha1 + kind: SomeCustomTask + name: some-custom-task +`), + run: test.MustParseRun(t, run), + }, { + name: "conditions - unlikely to support", + expectedErrText: []string{"condition"}, + pipeline: test.MustParsePipeline(t, ` +metadata: + name: pipeline + namespace: foo +spec: + tasks: + - name: some-task + conditions: + - conditionRef: some-condition + params: + - name: foo + value: bar + taskSpec: + steps: + - image: ubuntu +`), + run: test.MustParseRun(t, run), + }, { + name: "pipelineresources - unlikely to support", + expectedErrText: []string{"pipelineresources"}, + pipeline: test.MustParsePipeline(t, ` +metadata: + name: pipeline + namespace: foo +spec: + resources: + - name: source-repo + type: git + optional: true + tasks: + - name: some-task + resources: + inputs: + - name: some-source + resource: source-repo + taskSpec: + resources: + inputs: + - name: some-source + type: git + steps: + - image: ubuntu +`), + run: test.MustParseRun(t, run), + }, { + name: "volumes and volume mounts - unlikely to support", + pipeline: test.MustParsePipeline(t, ` +metadata: + name: pipeline + namespace: foo +spec: + tasks: + - name: use-volume + taskSpec: + steps: + - image: ubuntu + volumeMounts: + - name: my-volume-mount + mountPath: /foo/bar/baz + volumes: + - name: my-volume-mount + empty-dir: {} +`), + run: test.MustParseRun(t, run), + }, { + name: "missing name", + expectedErrText: []string{"name"}, + pipeline: p, + run: test.MustParseRun(t, ` +metadata: + name: run-with-pipeline + namespace: foo +spec: + ref: + apiVersion: tekton.dev/v1alpha1 + kind: PipelineToTaskRun +`), + }} + for _, tc := range testcases { + t.Run(tc.name, func(t *testing.T) { + ctx := context.Background() + names.TestingSeed() + + d := test.Data{ + Runs: []*v1alpha1.Run{tc.run}, + Pipelines: []*v1beta1.Pipeline{tc.pipeline}, + } + + testAssets, _ := getController(t, d) + + err := testAssets.Controller.Reconciler.Reconcile(ctx, getRunName(tc.run)) + if err == nil { + t.Errorf("expected permanenent error for invalid error (i.e. indication not to requeue) but got none") + } else { + if !controller.IsPermanentError(err) { + t.Errorf("invalid run should return permanent error but instead got %v", err) + } + } + + run, err := testAssets.Clients.Pipeline.TektonV1alpha1().Runs(tc.run.Namespace).Get(ctx, tc.run.Name, metav1.GetOptions{}) + if err != nil { + t.Fatalf("Error getting reconciled run from fake client: %s", err) + } + condition := run.Status.GetCondition(apis.ConditionSucceeded) + if condition.Status != corev1.ConditionFalse { + t.Errorf("exepcted invalid run to be marked failed but condition was %v", condition) + } + + for _, text := range tc.expectedErrText { + if !strings.Contains(condition.Message, text) { + t.Errorf("excepected failure message to container %q but was %q", text, condition.Message) + } + } + + }) + } +} diff --git a/pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/steps.go b/pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/steps.go new file mode 100644 index 000000000..9882b9b79 --- /dev/null +++ b/pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/steps.go @@ -0,0 +1,201 @@ +/* +Copyright 2021 The Tekton Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pipelinetotaskrun + +import ( + "fmt" + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" + "github.com/tektoncd/pipeline/pkg/names" + "github.com/tektoncd/pipeline/pkg/reconciler/pipelinerun/resources" + resources2 "github.com/tektoncd/pipeline/pkg/reconciler/taskrun/resources" + "github.com/tektoncd/pipeline/pkg/substitution" +) + +// PipelineTaskInfo holds all of the info needed to run a pipeline task +type PipelineTaskInfo struct { + // Name is the name of the pipeline Task + Name string + + // TaskDeclaredParams are the parameters that the referenced Task spec declared + TaskDeclaredParams []v1beta1.ParamSpec + + // ProvidedParamValues are the parameter values that were provided in the pipeline task + ProvidedParamValues []v1beta1.Param + + // Steps are the steps the Task declared + Steps []v1beta1.Step + + // Results are the results the Task declared + Results []v1beta1.TaskResult +} + +// NewPipelineTaskInfo will construct an object that will hold all the info needed to run the pipeline task +func NewPipelineTaskInfo(pTask v1beta1.PipelineTask, taskSpecs map[string]*v1beta1.TaskSpec) (PipelineTaskInfo, error) { + taskSpec, ok := taskSpecs[pTask.Name] + if !ok { + return PipelineTaskInfo{}, fmt.Errorf("expected taskspec wasn't present in map for %q", pTask.Name) + } + return PipelineTaskInfo{ + Name: pTask.Name, + TaskDeclaredParams: taskSpec.Params, + ProvidedParamValues: pTask.Params, + Steps: taskSpec.Steps, + Results: taskSpec.Results, + }, nil +} + +func namespaceName(namespace, name string) string { + return fmt.Sprintf("%s-%s", namespace, name) +} + +func getStepName(ptaskName, stepName string) string { + // leave unnamed steps unnamed + if stepName != "" { + // namespace the step ames to avoid collisions + stepName = namespaceName(ptaskName, stepName) + // make sure the newly generated name won't result in an invalid task spec + stepName = names.SimpleNameGenerator.RestrictLength(stepName) + } + return stepName +} + +// applyPipelineLevelParams will do variable replacement for all params in pTasks which are using Pipeline level +// params as their values. +func applyPipelineLevelParams(pTasks []v1beta1.PipelineTask, runSpecParams []v1beta1.Param) []v1beta1.PipelineTask { + // we're taking advantage of the parameter variable replacement libs in Tekton Pipelines, which expect to apply + // replacement onto entire Pipeline Specs from PipelineRuns + tempPipelineSpec := &v1beta1.PipelineSpec{Tasks: pTasks} + tempPipelineRun := &v1beta1.PipelineRun{Spec: v1beta1.PipelineRunSpec{Params: runSpecParams}} + + // replace the value with the pipeline param resolved value + tempPipelineSpec = resources.ApplyParameters(tempPipelineSpec, tempPipelineRun) + return tempPipelineSpec.Tasks +} + +// NamespaceParams will return a new PipelineTaskInfo in which the names of all the declared params and +// provided values are updated such that the param name is prefaced by the name of the pipeline task. All uses of the +// params will be updated in the steps as well. +func (pti PipelineTaskInfo) NamespaceParams() PipelineTaskInfo { + updatedPti := PipelineTaskInfo{ + Name: pti.Name, + Results: pti.Results, + } + + // namespace the params by renaming them + for _, p := range pti.TaskDeclaredParams { + pName := namespaceName(pti.Name, p.Name) + updatedPti.TaskDeclaredParams = append(updatedPti.TaskDeclaredParams, v1beta1.ParamSpec{ + Name: pName, + Type: p.Type, + Description: p.Description, + Default: p.Default, + }) + } + + // get the values for each renamed param + for _, p := range pti.ProvidedParamValues { + pName := namespaceName(pti.Name, p.Name) + updatedPti.ProvidedParamValues = append(updatedPti.ProvidedParamValues, v1beta1.Param{ + Name: pName, + Value: p.Value, + }) + } + + // create a mapping of the replacements that can be used to update the steps + replacements := map[string]string{} + for _, p := range pti.TaskDeclaredParams { + pName := namespaceName(pti.Name, p.Name) + // this is the format that ApplyReplacements expects the replacements to arrive in; it infers the surrounding + // dollar sign and brackets + existing := fmt.Sprintf("params.%s", p.Name) + // we'll replace the resulting wrapped existing param reference with the variable replacement syntax for + // our renamed version + renamed := fmt.Sprintf("$(params.%s)", pName) + replacements[existing] = renamed + } + + for i := range updatedPti.ProvidedParamValues { + updatedPti.ProvidedParamValues[i].Value.StringVal = substitution.ApplyReplacements(updatedPti.ProvidedParamValues[i].Value.StringVal, replacements) + } + + updatedTaskSpec := resources2.ApplyReplacements(&v1beta1.TaskSpec{Steps: pti.Steps}, replacements, nil) + updatedPti.Steps = updatedTaskSpec.Steps + return updatedPti +} + +// NamespaceSteps will return a new PipelineTaskInfo in which the names of all steps are updated so that they are +// prefaced by the name of the pipeline task. +func (pti PipelineTaskInfo) NamespaceSteps() PipelineTaskInfo { + updatedPti := PipelineTaskInfo{ + Name: pti.Name, + TaskDeclaredParams: pti.TaskDeclaredParams, + ProvidedParamValues: pti.ProvidedParamValues, + Results: pti.Results, + } + for _, step := range pti.Steps { + updatedStep := step.DeepCopy() + updatedStep.Name = getStepName(pti.Name, updatedStep.Name) + updatedPti.Steps = append(updatedPti.Steps, *updatedStep) + } + return updatedPti +} + +// RenameWorkspaces will return a new PipelineTask info in which all references to the keys in newMapping +// are updated to the values. +func (pti PipelineTaskInfo) RenameWorkspaces(newMapping map[string]string) PipelineTaskInfo { + updatedPti := PipelineTaskInfo{ + Name: pti.Name, + Results: pti.Results, + } + + // create a mapping of the replacements that can be used to update the steps + replacements := map[string]string{} + for oldName, newName := range newMapping { + // we need to explicitly replace every known workspace variable + for _, variable := range []string{"path", "bound", "claim", "volume"} { + // this is the format that ApplyReplacements expects the replacements to arrive in; it infers the surrounding + // dollar sign and brackets + existing := fmt.Sprintf("workspaces.%s.%s", oldName, variable) + // we'll replace the resulting wrapped existing param reference with the variable replacement syntax for + // our renamed version + renamed := fmt.Sprintf("$(workspaces.%s.%s)", newName, variable) + replacements[existing] = renamed + } + } + + for _, p := range pti.ProvidedParamValues { + updatedParam := v1beta1.Param{ + Name: p.Name, + Value: v1beta1.ArrayOrString{ + Type: p.Value.Type, + // not yet supporting array types + StringVal: substitution.ApplyReplacements(p.Value.StringVal, replacements), + }, + } + updatedPti.ProvidedParamValues = append(updatedPti.ProvidedParamValues, updatedParam) + } + + updatedTaskSpec := resources2.ApplyReplacements( + &v1beta1.TaskSpec{ + Params: pti.TaskDeclaredParams, + Steps: pti.Steps, + }, replacements, nil) + updatedPti.TaskDeclaredParams = updatedTaskSpec.Params + updatedPti.Steps = updatedTaskSpec.Steps + + return updatedPti +} diff --git a/pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/steps_test.go b/pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/steps_test.go new file mode 100644 index 000000000..81698e4d4 --- /dev/null +++ b/pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/steps_test.go @@ -0,0 +1,446 @@ +package pipelinetotaskrun + +import ( + "github.com/google/go-cmp/cmp" + "github.com/tektoncd/experimental/pipeline-to-taskrun/test" + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" + "github.com/tektoncd/pipeline/test/diff" + "testing" +) + +func parsePipelineTaskInfo(t *testing.T, name, taskDeclaredParams, providedParamValues, steps, results string) PipelineTaskInfo { + declaredTask := test.MustParseTask(t, ` +spec: + params: +`+taskDeclaredParams) + providedP := test.MustParsePipeline(t, ` +spec: + tasks: + - params: +`+providedParamValues) + stepsTask := test.MustParseTask(t, ` +spec: + steps: +`+steps) + resultsTask := test.MustParseTask(t, ` +spec: + results: +`+results) + return PipelineTaskInfo{ + Name: name, + TaskDeclaredParams: declaredTask.Spec.Params, + ProvidedParamValues: providedP.Spec.Tasks[0].Params, + Steps: stepsTask.Spec.Steps, + Results: resultsTask.Spec.Results, + } +} + +func TestNewPipelineTaskInfo(t *testing.T) { + for _, tc := range []struct { + Name string + Pipeline *v1beta1.Pipeline + Task *v1beta1.Task + Expected PipelineTaskInfo + }{{ + Name: "complete example", + Pipeline: test.MustParsePipeline(t, ` +spec: + tasks: + - name: run-tests + params: + - name: package + value: $(params.package) +`), + Task: test.MustParseTask(t, ` +spec: + params: + - name: package + description: "some package" + - name: something + default: "" + steps: + - name: clone + image: some-git-image + script: | + + #!/usr/bin/env bash + set -xe + /ko-app/git-init \ + -url "$(params.package)" \ + -revision "$(params.something)" + + - name: some-other-step-really-long-gonna-get-truncated-so-very-long + image: someimage + results: + - name: commit + description: "The precise commit SHA" +`), + Expected: parsePipelineTaskInfo(t, "run-tests", ` + - name: package + description: "some package" + - name: something + default: "" +`, ` + - name: package + value: $(params.package) +`, ` + - name: clone + image: some-git-image + script: | + + #!/usr/bin/env bash + set -xe + /ko-app/git-init \ + -url "$(params.package)" \ + -revision "$(params.something)" + + - name: some-other-step-really-long-gonna-get-truncated-so-very-long + image: someimage +`, ` + - name: commit + description: "The precise commit SHA" +`), + }, { + Name: "no params, results, or script", + Pipeline: test.MustParsePipeline(t, ` +spec: + tasks: + - name: run-tests +`), + Task: test.MustParseTask(t, ` +spec: + params: + steps: + - name: clone + image: ubuntu +`), + Expected: parsePipelineTaskInfo(t, "run-tests", "", "", ` + - name: clone + image: ubuntu +`, ""), + }} { + t.Run(tc.Name, func(t *testing.T) { + taskSpecs := map[string]*v1beta1.TaskSpec{ + tc.Pipeline.Spec.Tasks[0].Name: &tc.Task.Spec, + } + pti, err := NewPipelineTaskInfo(tc.Pipeline.Spec.Tasks[0], taskSpecs) + if err != nil { + t.Fatalf("Didn't expect error but got %v", err) + } + if d := cmp.Diff(tc.Expected, pti); d != "" { + t.Errorf("Didn't get expected object. Diff: %s", diff.PrintWantGot(d)) + } + }) + } +} + +func TestApplyPipelineLevelParams(t *testing.T) { + run := test.MustParseRun(t, ` +spec: + params: + - name: git-url + value: https://github.com/tektoncd/chains + - name: package + value: github.com/tektoncd/chains/pkg + - name: packages + value: ./pkg/... + - name: gcs-location + value: gs://christies-empty-bucket +`) + var pTasks []v1beta1.PipelineTask + p := test.MustParsePipeline(t, ` +spec: + tasks: + - name: grab-source + params: + - name: url + value: $(params.git-url) + - name: run-tests + params: + - name: package + value: $(params.package) + - name: packages + value: $(params.packages) > $(workspaces.source.path)/test-results + - name: upload-results + params: + - name: path + value: test-results + - name: location + value: $(params.gcs-location) +`) + for _, pt := range p.Spec.Tasks { + pTasks = append(pTasks, pt) + } + expectedP := test.MustParsePipeline(t, ` +spec: + tasks: + - name: grab-source + params: + - name: url + value: https://github.com/tektoncd/chains + - name: run-tests + params: + - name: package + value: github.com/tektoncd/chains/pkg + - name: packages + value: ./pkg/... > $(workspaces.source.path)/test-results + - name: upload-results + params: + - name: path + value: test-results + - name: location + value: gs://christies-empty-bucket +`) + modifiedTasks := applyPipelineLevelParams(pTasks, run.Spec.Params) + if d := cmp.Diff(expectedP.Spec.Tasks, modifiedTasks); d != "" { + t.Errorf("Resulting taskrun spec didn't match expectations (-want, +got): %s", d) + } +} + +func TestNamespaceParams(t *testing.T) { + for _, tc := range []struct { + Name string + PipelineTaskInfo PipelineTaskInfo + Expected PipelineTaskInfo + }{{ + Name: "grab-source and refer to params within params", + PipelineTaskInfo: parsePipelineTaskInfo(t, "grab-source", ` + - name: url + description: "git url to clone" + - name: revision + description: "git revision to check out" + default: "" +`, ` + - name: url + value: https://github.com/tektoncd/chains $(params.url) +`, ` + - name: clone + image: some-git-image + script: | + #!/usr/bin/env bash + set -xe + /ko-app/git-init \ + -url "$(params.url)" \ + -revision "$(params.revision)" + - name: some-other-step-really-long-gonna-get-truncated-so-very-long + image: someimage +`, ` + - name: commit + description: "The precise commit SHA that was fetched by this Task" +`), + Expected: parsePipelineTaskInfo(t, "grab-source", ` + - name: grab-source-url + description: "git url to clone" + - name: grab-source-revision + description: "git revision to check out" + default: "" +`, ` + - name: grab-source-url + value: https://github.com/tektoncd/chains $(params.grab-source-url) +`, ` + - name: clone + image: some-git-image + script: | + #!/usr/bin/env bash + set -xe + /ko-app/git-init \ + -url "$(params.grab-source-url)" \ + -revision "$(params.grab-source-revision)" + - name: some-other-step-really-long-gonna-get-truncated-so-very-long + image: someimage +`, ` + - name: commit + description: "The precise commit SHA that was fetched by this Task" +`), + }, { + Name: "run-tests", + PipelineTaskInfo: parsePipelineTaskInfo(t, "run-tests", ` + - name: package + description: "package (and its children) under test" + - name: packages + description: "packages to test (default: ./...)" + default: "./..." + - name: context + description: "path to the directory to use as context." + default: "." +`, ` + - name: package + value: github.com/tektoncd/chains/pkg + - name: packages + value: ./pkg/... > $(workspaces.source.path)/test-results +`, ` + - name: unit-test + image: "docker.io/library/golang" + env: + - name: CONTEXT + value: $(params.context) + script: | + SRC_PATH="$GOPATH/src/$(params.package)/$(params.context)" + mkdir -p $SRC_PATH + cp -R "$(workspaces.source.path)"/"$(params.context)"/* $SRC_PATH + cd $SRC_PATH +`, ""), + Expected: parsePipelineTaskInfo(t, "run-tests", ` + - name: run-tests-package + description: "package (and its children) under test" + - name: run-tests-packages + description: "packages to test (default: ./...)" + default: "./..." + - name: run-tests-context + description: "path to the directory to use as context." + default: "." +`, ` + - name: run-tests-package + value: "github.com/tektoncd/chains/pkg" + - name: run-tests-packages + value: "./pkg/... > $(workspaces.source.path)/test-results" +`, ` + - name: unit-test + image: "docker.io/library/golang" + env: + - name: CONTEXT + value: $(params.run-tests-context) + script: | + SRC_PATH="$GOPATH/src/$(params.run-tests-package)/$(params.run-tests-context)" + mkdir -p $SRC_PATH + cp -R "$(workspaces.source.path)"/"$(params.run-tests-context)"/* $SRC_PATH + cd $SRC_PATH +`, ""), + }, { + Name: "upload-results", + PipelineTaskInfo: parsePipelineTaskInfo(t, "upload-results", ` + - name: path + description: "The path to files or directories relative to the source workspace that you'd like to upload." + - name: location + description: "The address (including \"gs://\") where you'd like to upload files to." + - name: serviceAccountPath + description: "The path inside the credentials workspace to the GOOGLE_APPLICATION_CREDENTIALS key file." + default: "service_account.json" +`, ` + - name: path + value: test-results + - name: location + value: gs://christies-empty-bucket +`, ` + - name: upload + image: "gcr.io/google.com/cloudsdktool/cloud-sdk:310.0.0" + script: | + #!/usr/bin/env bash + set -xe + CRED_PATH="$(workspaces.credentials.path)/$(params.serviceAccountPath)" + SOURCE="$(workspaces.source.path)/$(params.path)" +`, ""), + Expected: parsePipelineTaskInfo(t, "upload-results", ` + - name: upload-results-path + description: "The path to files or directories relative to the source workspace that you'd like to upload." + - name: upload-results-location + description: "The address (including \"gs://\") where you'd like to upload files to." + - name: upload-results-serviceAccountPath + description: "The path inside the credentials workspace to the GOOGLE_APPLICATION_CREDENTIALS key file." + default: service_account.json +`, ` + - name: upload-results-path + value: "test-results" + - name: upload-results-location + value: "gs://christies-empty-bucket" +`, ` + - name: upload + image: "gcr.io/google.com/cloudsdktool/cloud-sdk:310.0.0" + script: | + #!/usr/bin/env bash + set -xe + CRED_PATH="$(workspaces.credentials.path)/$(params.upload-results-serviceAccountPath)" + SOURCE="$(workspaces.source.path)/$(params.upload-results-path)" +`, ""), + }} { + t.Run(tc.Name, func(t *testing.T) { + updatedPti := tc.PipelineTaskInfo.NamespaceParams() + if d := cmp.Diff(tc.Expected, updatedPti); d != "" { + t.Errorf("didn't get expected updated info. Diff: %s", diff.PrintWantGot(d)) + } + }) + } +} + +func TestNamespaceSteps(t *testing.T) { + pti := parsePipelineTaskInfo(t, "grab-source", ` + - name: grab-source-url + description: "git url to clone" +`, ` + - name: grab-source-url + value: "https://github.com/tektoncd/chains" +`, ` + - name: clone + image: some-git-image + script: | + echo $(workspaces.foobar.bound) + - image: ubuntu +`, ` + - name: commit + description: "The precise commit SHA that was fetched by this Task" +`) + expected := parsePipelineTaskInfo(t, "grab-source", ` + - name: grab-source-url + description: "git url to clone" +`, ` + - name: grab-source-url + value: "https://github.com/tektoncd/chains" +`, ` + - name: grab-source-clone + image: some-git-image + script: | + echo $(workspaces.foobar.bound) + - image: ubuntu +`, ` + - name: commit + description: "The precise commit SHA that was fetched by this Task" +`) + updatedPti := pti.NamespaceSteps() + if d := cmp.Diff(expected, updatedPti); d != "" { + t.Errorf("didn't get expected updated info. Diff: %s", diff.PrintWantGot(d)) + } +} + +func TestRenameWorkspaces(t *testing.T) { + pti := parsePipelineTaskInfo(t, "grab-source", ` + - name: grab-source-url + description: "git url to clone" +`, ` + - name: grab-source-url + value: "https://github.com/tektoncd/chains $(workspaces.foobar.path)" +`, ` + - name: grab-source-clone + image: some-git-image + script: | + echo $(workspaces.foobar.bound) + echo $(workspaces.foobar.claim) + echo $(workspaces.foobar.volume) + cd $(workspaces.foobar.path) +`, ` + - name: commit + description: "The precise commit SHA that was fetched by this Task" +`) + expected := parsePipelineTaskInfo(t, "grab-source", ` + - name: grab-source-url + description: "git url to clone" +`, ` + - name: grab-source-url + value: "https://github.com/tektoncd/chains $(workspaces.the-ultimate-volume.path)" +`, ` + - name: grab-source-clone + image: some-git-image + script: | + echo $(workspaces.the-ultimate-volume.bound) + echo $(workspaces.the-ultimate-volume.claim) + echo $(workspaces.the-ultimate-volume.volume) + cd $(workspaces.the-ultimate-volume.path) +`, ` + - name: commit + description: "The precise commit SHA that was fetched by this Task" +`) + newMapping := map[string]string{"foobar": "the-ultimate-volume"} + updatedPti := pti.RenameWorkspaces(newMapping) + if d := cmp.Diff(expected, updatedPti); d != "" { + t.Errorf("didn't get expected updated info. Diff: %s", diff.PrintWantGot(d)) + } +} diff --git a/pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/taskrun.go b/pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/taskrun.go new file mode 100644 index 000000000..f4cfadea8 --- /dev/null +++ b/pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/taskrun.go @@ -0,0 +1,59 @@ +package pipelinetotaskrun + +import ( + "fmt" + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" +) + +func getMergedTaskRun(run *v1alpha1.Run, pSpec *v1beta1.PipelineSpec, taskSpecs map[string]*v1beta1.TaskSpec) (*v1beta1.TaskRun, error) { + sequence, err := putTasksInOrder(pSpec.Tasks) + if err != nil { + return nil, fmt.Errorf("couldn't find valid order for tasks: %v", err) + } + + // we'll be declaring and mapping one workspace per provided workspace and eliminating the indirection added by the + // workspaces declared by the Task. This will make sure that is volume claim templates are used, only one volume + // will be created for each. + newWorkspaceMapping := getNewWorkspaceMapping(sequence) + + // replace all param values with pipeline level params so we can ignore them from now on + sequenceWithAppliedParams := applyPipelineLevelParams(sequence, run.Spec.Params) + + tr := &v1beta1.TaskRun{ + ObjectMeta: getObjectMeta(run), + Spec: v1beta1.TaskRunSpec{ + ServiceAccountName: run.Spec.ServiceAccountName, + TaskSpec: &v1beta1.TaskSpec{}, + Workspaces: run.Spec.Workspaces, + }, + } + + for _, w := range pSpec.Workspaces { + // mapping only the supported workspace declaration fields + tr.Spec.TaskSpec.Workspaces = append(tr.Spec.TaskSpec.Workspaces, v1beta1.WorkspaceDeclaration{ + Name: w.Name, + Description: w.Description, + }) + } + + for _, pTask := range sequenceWithAppliedParams { + pti, err := NewPipelineTaskInfo(pTask, taskSpecs) + if err != nil { + return nil, fmt.Errorf("couldn't construct object to hold pipeline task info for %s: %v", pTask.Name, err) + } + + pti = pti.NamespaceParams() + pti = pti.NamespaceSteps() + pti = pti.RenameWorkspaces(newWorkspaceMapping[pTask.Name]) + + tr.Spec.Params = append(tr.Spec.Params, pti.ProvidedParamValues...) + tr.Spec.TaskSpec.Params = append(tr.Spec.TaskSpec.Params, pti.TaskDeclaredParams...) + tr.Spec.TaskSpec.Steps = append(tr.Spec.TaskSpec.Steps, pti.Steps...) + // we don't support mapping results but we need to declare them in order for steps that write + // results to be able to write to the dirs they expect + tr.Spec.TaskSpec.Results = append(tr.Spec.TaskSpec.Results, pti.Results...) + } + + return tr, nil +} diff --git a/pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/testdata/expected-taskrun.yaml b/pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/testdata/expected-taskrun.yaml new file mode 100644 index 000000000..414ce851c --- /dev/null +++ b/pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/testdata/expected-taskrun.yaml @@ -0,0 +1,242 @@ +apiVersion: tekton.dev/v1beta1 +kind: TaskRun +metadata: + name: some-run + namespace: some-ns + labels: + tekton.dev/run: some-run + ownerReferences: + - apiVersion: tekton.dev/v1alpha1 + blockOwnerDeletion: true + controller: true + kind: Run + name: some-run +spec: + params: + - name: grab-source-url + value: https://github.com/tektoncd/chains + - name: run-tests-package + value: github.com/tektoncd/chains/pkg + - name: run-tests-packages + value: ./pkg/... > $(workspaces.where-it-all-happens.path)/test-results + - name: upload-results-path + value: test-results + - name: upload-results-location + value: gs://christies-empty-bucket + serviceAccountName: default + taskSpec: + params: + - description: git url to clone + name: grab-source-url + type: string + - default: "" + description: git revision to checkout (branch, tag, sha, ref…) + name: grab-source-revision + type: string + - default: "" + description: (optional) git refspec to fetch before checking out revision + name: grab-source-refspec + type: string + - default: "true" + description: defines if the resource should initialize and fetch the submodules + name: grab-source-submodules + type: string + - default: "1" + description: performs a shallow clone where only the most recent commit(s) will + be fetched + name: grab-source-depth + type: string + - default: "true" + description: defines if http.sslVerify should be set to true or false in the + global git config + name: grab-source-sslVerify + type: string + - default: "" + description: subdirectory inside the "output" workspace to clone the git repo + into + name: grab-source-subdirectory + type: string + - default: "" + description: defines which directories patterns to match or exclude when performing + a sparse checkout + name: grab-source-sparseCheckoutDirectories + type: string + - default: "true" + description: clean out the contents of the repo's destination directory (if + it already exists) before trying to clone the repo there + name: grab-source-deleteExisting + type: string + - default: "" + description: git HTTP proxy server for non-SSL requests + name: grab-source-httpProxy + type: string + - default: "" + description: git HTTPS proxy server for SSL requests + name: grab-source-httpsProxy + type: string + - default: "" + description: git no proxy - opt out of proxying HTTP/HTTPS requests + name: grab-source-noProxy + type: string + - default: "true" + description: log the commands used during execution + name: grab-source-verbose + type: string + - default: gcr.io/tekton-releases/github.com/tektoncd/pipeline/cmd/git-init:v0.21.0 + description: the image used where the git-init binary is + name: grab-source-gitInitImage + type: string + - description: package (and its children) under test + name: run-tests-package + type: string + - default: ./... + description: 'packages to test (default: ./...)' + name: run-tests-packages + type: string + - default: . + description: path to the directory to use as context. + name: run-tests-context + type: string + - default: latest + description: golang version to use for tests + name: run-tests-version + type: string + - default: -race -cover -v + description: flags to use for the test command + name: run-tests-flags + type: string + - default: linux + description: running program's operating system target + name: run-tests-GOOS + type: string + - default: amd64 + description: running program's architecture target + name: run-tests-GOARCH + type: string + - default: auto + description: value of module support + name: run-tests-GO111MODULE + type: string + - description: The path to files or directories relative to the source workspace + that you'd like to upload. + name: upload-results-path + type: string + - description: The address (including "gs://") where you'd like to upload files + to. + name: upload-results-location + type: string + - default: service_account.json + description: The path inside the credentials workspace to the GOOGLE_APPLICATION_CREDENTIALS + key file. + name: upload-results-serviceAccountPath + type: string + results: + - description: The precise commit SHA that was fetched by this Task + name: commit + - description: The precise URL that was fetched by this Task + name: url + steps: + - image: $(params.grab-source-gitInitImage) + name: grab-source-clone + resources: {} + # using yaml block chomping to strip newline, otherwise trailing newlines are present + # when the script block is in the middle of the file and absent when at the end of the file + script: |- + #!/bin/sh + set -eu -o pipefail + if [[ "$(params.grab-source-verbose)" == "true" ]] ; then + set -x + fi + CHECKOUT_DIR="$(workspaces.where-it-all-happens.path)/$(params.grab-source-subdirectory)" + cleandir() { + # Delete any existing contents of the repo directory if it exists. + # + # We don't just "rm -rf $CHECKOUT_DIR" because $CHECKOUT_DIR might be "/" + # or the root of a mounted volume. + if [[ -d "$CHECKOUT_DIR" ]] ; then + # Delete non-hidden files and directories + rm -rf "$CHECKOUT_DIR"/* + # Delete files and directories starting with . but excluding .. + rm -rf "$CHECKOUT_DIR"/.[!.]* + # Delete files and directories starting with .. plus any other character + rm -rf "$CHECKOUT_DIR"/..?* + fi + } + if [[ "$(params.grab-source-deleteExisting)" == "true" ]] ; then + cleandir + fi + test -z "$(params.grab-source-httpProxy)" || export HTTP_PROXY=$(params.grab-source-httpProxy) + test -z "$(params.grab-source-httpsProxy)" || export HTTPS_PROXY=$(params.grab-source-httpsProxy) + test -z "$(params.grab-source-noProxy)" || export NO_PROXY=$(params.grab-source-noProxy) + /ko-app/git-init \ + -url "$(params.grab-source-url)" \ + -revision "$(params.grab-source-revision)" \ + -refspec "$(params.grab-source-refspec)" \ + -path "$CHECKOUT_DIR" \ + -sslVerify="$(params.grab-source-sslVerify)" \ + -submodules="$(params.grab-source-submodules)" \ + -depth "$(params.grab-source-depth)" \ + -sparseCheckoutDirectories "$(params.grab-source-sparseCheckoutDirectories)" + cd "$CHECKOUT_DIR" + RESULT_SHA="$(git rev-parse HEAD)" + EXIT_CODE="$?" + if [ "$EXIT_CODE" != 0 ] ; then + exit $EXIT_CODE + fi + # ensure we don't add a trailing newline to the result + echo -n "$RESULT_SHA" > $(results.commit.path) + echo -n "$(params.grab-source-url)" > $(results.url.path) + - env: + - name: GOOS + value: $(params.run-tests-GOOS) + - name: GOARCH + value: $(params.run-tests-GOARCH) + - name: GO111MODULE + value: $(params.run-tests-GO111MODULE) + image: docker.io/library/golang:$(params.run-tests-version) + name: run-tests-unit-test + resources: {} + # using yaml block chomping to strip newline, otherwise trailing newlines are present + # when the script block is in the middle of the file and absent when at the end of the file + script: |- + SRC_PATH="$GOPATH/src/$(params.run-tests-package)/$(params.run-tests-context)" + mkdir -p $SRC_PATH + cp -R "$(workspaces.where-it-all-happens.path)"/"$(params.run-tests-context)"/* $SRC_PATH + cd $SRC_PATH + go test $(params.run-tests-flags) $(params.run-tests-packages) + - image: gcr.io/google.com/cloudsdktool/cloud-sdk:310.0.0@sha256:cb03669fcdb9191d55a6200f2911fff3baec0b8c39b156d95b68aabe975ac506 + name: upload-results-upload + resources: {} + # using yaml block chomping to strip newline, otherwise trailing newlines are present + # when the script block is in the middle of the file and absent when at the end of the file + script: |- + #!/usr/bin/env bash + set -xe + + CRED_PATH="$(workspaces.gcs-creds.path)/$(params.upload-results-serviceAccountPath)" + SOURCE="$(workspaces.where-it-all-happens.path)/$(params.upload-results-path)" + + if [[ -f "$CRED_PATH" ]]; then + GOOGLE_APPLICATION_CREDENTIALS="$CRED_PATH" + fi + + if [[ "${GOOGLE_APPLICATION_CREDENTIALS}" != "" ]]; then + echo GOOGLE_APPLICATION_CREDENTIALS is set, activating Service Account... + gcloud auth activate-service-account --key-file=${GOOGLE_APPLICATION_CREDENTIALS} + fi + + if [[ -d "$SOURCE" ]]; then + gsutil -m rsync -d -r "$SOURCE" "$(params.upload-results-location)" + else + gsutil cp "$SOURCE" "$(params.upload-results-location)" + fi + workspaces: + - name: where-it-all-happens + - name: gcs-creds + workspaces: + - name: where-it-all-happens + persistentVolumeClaim: + claimName: pvc + - name: gcs-creds + secret: + secretName: mikey diff --git a/pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/testdata/gcs-upload.yaml b/pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/testdata/gcs-upload.yaml new file mode 100644 index 000000000..b46533778 --- /dev/null +++ b/pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/testdata/gcs-upload.yaml @@ -0,0 +1,59 @@ +# https://github.com/tektoncd/catalog/blob/main/task/gcs-upload/0.1/gcs-upload.yaml +apiVersion: tekton.dev/v1beta1 +kind: Task +metadata: + name: gcs-upload + labels: + app.kubernetes.io/version: "0.1" + annotations: + tekton.dev/pipelines.minVersion: "0.12.1" + tekton.dev/tags: cloud, gcs + tekton.dev/displayName: "Upload to GCS" +spec: + description: >- + A Task that uploads a GCS bucket. + + This task uploads files or directories from a Workspace to a GCS bucket. + + workspaces: + - name: credentials + description: A secret with a service account key to use as GOOGLE_APPLICATION_CREDENTIALS. + - name: source + description: A workspace where files will be uploaded from. + params: + - name: path + description: The path to files or directories relative to the source workspace that you'd like to upload. + type: string + - name: location + description: The address (including "gs://") where you'd like to upload files to. + type: string + - name: serviceAccountPath + description: The path inside the credentials workspace to the GOOGLE_APPLICATION_CREDENTIALS key file. + type: string + default: service_account.json + steps: + - name: upload + image: gcr.io/google.com/cloudsdktool/cloud-sdk:310.0.0@sha256:cb03669fcdb9191d55a6200f2911fff3baec0b8c39b156d95b68aabe975ac506 #tag: 310.0.0 + # using yaml block chomping to strip newline, otherwise trailing newlines are present + # when the script block is in the middle of the file and absent when at the end of the file + script: |- + #!/usr/bin/env bash + set -xe + + CRED_PATH="$(workspaces.credentials.path)/$(params.serviceAccountPath)" + SOURCE="$(workspaces.source.path)/$(params.path)" + + if [[ -f "$CRED_PATH" ]]; then + GOOGLE_APPLICATION_CREDENTIALS="$CRED_PATH" + fi + + if [[ "${GOOGLE_APPLICATION_CREDENTIALS}" != "" ]]; then + echo GOOGLE_APPLICATION_CREDENTIALS is set, activating Service Account... + gcloud auth activate-service-account --key-file=${GOOGLE_APPLICATION_CREDENTIALS} + fi + + if [[ -d "$SOURCE" ]]; then + gsutil -m rsync -d -r "$SOURCE" "$(params.location)" + else + gsutil cp "$SOURCE" "$(params.location)" + fi \ No newline at end of file diff --git a/pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/testdata/git-clone.yaml b/pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/testdata/git-clone.yaml new file mode 100644 index 000000000..63ceef34e --- /dev/null +++ b/pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/testdata/git-clone.yaml @@ -0,0 +1,134 @@ +# https://github.com/tektoncd/catalog/blob/main/task/git-clone/0.3/git-clone.yaml +apiVersion: tekton.dev/v1beta1 +kind: Task +metadata: + name: git-clone + labels: + app.kubernetes.io/version: "0.3" + annotations: + tekton.dev/pipelines.minVersion: "0.21.0" + tekton.dev/tags: git + tekton.dev/displayName: "git clone" +spec: + description: >- + These Tasks are Git tasks to work with repositories used by other tasks + in your Pipeline. + The git-clone Task will clone a repo from the provided url into the + output Workspace. By default the repo will be cloned into the root of + your Workspace. You can clone into a subdirectory by setting this Task's + subdirectory param. This Task also supports sparse checkouts. To perform + a sparse checkout, pass a list of comma separated directory patterns to + this Task's sparseCheckoutDirectories param. + workspaces: + - name: output + description: The git repo will be cloned onto the volume backing this workspace + params: + - name: url + description: git url to clone + type: string + - name: revision + description: git revision to checkout (branch, tag, sha, ref…) + type: string + default: "" + - name: refspec + description: (optional) git refspec to fetch before checking out revision + default: "" + - name: submodules + description: defines if the resource should initialize and fetch the submodules + type: string + default: "true" + - name: depth + description: performs a shallow clone where only the most recent commit(s) will be fetched + type: string + default: "1" + - name: sslVerify + description: defines if http.sslVerify should be set to true or false in the global git config + type: string + default: "true" + - name: subdirectory + description: subdirectory inside the "output" workspace to clone the git repo into + type: string + default: "" + - name: sparseCheckoutDirectories + description: defines which directories patterns to match or exclude when performing a sparse checkout + type: string + default: "" + - name: deleteExisting + description: clean out the contents of the repo's destination directory (if it already exists) before trying to clone the repo there + type: string + default: "true" + - name: httpProxy + description: git HTTP proxy server for non-SSL requests + type: string + default: "" + - name: httpsProxy + description: git HTTPS proxy server for SSL requests + type: string + default: "" + - name: noProxy + description: git no proxy - opt out of proxying HTTP/HTTPS requests + type: string + default: "" + - name: verbose + description: log the commands used during execution + type: string + default: "true" + - name: gitInitImage + description: the image used where the git-init binary is + type: string + default: "gcr.io/tekton-releases/github.com/tektoncd/pipeline/cmd/git-init:v0.21.0" + results: + - name: commit + description: The precise commit SHA that was fetched by this Task + - name: url + description: The precise URL that was fetched by this Task + steps: + - name: clone + image: $(params.gitInitImage) + # using yaml block chomping to strip newline, otherwise trailing newlines are present + # when the script block is in the middle of the file and absent when at the end of the file + script: |- + #!/bin/sh + set -eu -o pipefail + if [[ "$(params.verbose)" == "true" ]] ; then + set -x + fi + CHECKOUT_DIR="$(workspaces.output.path)/$(params.subdirectory)" + cleandir() { + # Delete any existing contents of the repo directory if it exists. + # + # We don't just "rm -rf $CHECKOUT_DIR" because $CHECKOUT_DIR might be "/" + # or the root of a mounted volume. + if [[ -d "$CHECKOUT_DIR" ]] ; then + # Delete non-hidden files and directories + rm -rf "$CHECKOUT_DIR"/* + # Delete files and directories starting with . but excluding .. + rm -rf "$CHECKOUT_DIR"/.[!.]* + # Delete files and directories starting with .. plus any other character + rm -rf "$CHECKOUT_DIR"/..?* + fi + } + if [[ "$(params.deleteExisting)" == "true" ]] ; then + cleandir + fi + test -z "$(params.httpProxy)" || export HTTP_PROXY=$(params.httpProxy) + test -z "$(params.httpsProxy)" || export HTTPS_PROXY=$(params.httpsProxy) + test -z "$(params.noProxy)" || export NO_PROXY=$(params.noProxy) + /ko-app/git-init \ + -url "$(params.url)" \ + -revision "$(params.revision)" \ + -refspec "$(params.refspec)" \ + -path "$CHECKOUT_DIR" \ + -sslVerify="$(params.sslVerify)" \ + -submodules="$(params.submodules)" \ + -depth "$(params.depth)" \ + -sparseCheckoutDirectories "$(params.sparseCheckoutDirectories)" + cd "$CHECKOUT_DIR" + RESULT_SHA="$(git rev-parse HEAD)" + EXIT_CODE="$?" + if [ "$EXIT_CODE" != 0 ] ; then + exit $EXIT_CODE + fi + # ensure we don't add a trailing newline to the result + echo -n "$RESULT_SHA" > $(results.commit.path) + echo -n "$(params.url)" > $(results.url.path) \ No newline at end of file diff --git a/pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/testdata/go-test.yaml b/pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/testdata/go-test.yaml new file mode 100644 index 000000000..7b5e2dd93 --- /dev/null +++ b/pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/testdata/go-test.yaml @@ -0,0 +1,59 @@ +# https://github.com/tektoncd/catalog/blob/main/task/golang-test/0.1/golang-test.yaml +apiVersion: tekton.dev/v1beta1 +kind: Task +metadata: + name: golang-test + labels: + app.kubernetes.io/version: "0.1" + annotations: + tekton.dev/pipelines.minVersion: "0.12.1" + tekton.dev/tags: test + tekton.dev/displayName: "golang test" +spec: + description: >- + This Task is Golang task to test Go projects. + + params: + - name: package + description: package (and its children) under test + - name: packages + description: "packages to test (default: ./...)" + default: "./..." + - name: context + description: path to the directory to use as context. + default: "." + - name: version + description: golang version to use for tests + default: "latest" + - name: flags + description: flags to use for the test command + default: -race -cover -v + - name: GOOS + description: "running program's operating system target" + default: linux + - name: GOARCH + description: "running program's architecture target" + default: amd64 + - name: GO111MODULE + description: "value of module support" + default: auto + workspaces: + - name: source + steps: + - name: unit-test + image: docker.io/library/golang:$(params.version) + # using yaml block chomping to strip newline, otherwise trailing newlines are present + # when the script block is in the middle of the file and absent when at the end of the file + script: |- + SRC_PATH="$GOPATH/src/$(params.package)/$(params.context)" + mkdir -p $SRC_PATH + cp -R "$(workspaces.source.path)"/"$(params.context)"/* $SRC_PATH + cd $SRC_PATH + go test $(params.flags) $(params.packages) + env: + - name: GOOS + value: "$(params.GOOS)" + - name: GOARCH + value: "$(params.GOARCH)" + - name: GO111MODULE + value: "$(params.GO111MODULE)" \ No newline at end of file diff --git a/pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/validate.go b/pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/validate.go new file mode 100644 index 000000000..df62e0acd --- /dev/null +++ b/pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/validate.go @@ -0,0 +1,137 @@ +/* +Copyright 2021 The Tekton Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pipelinetotaskrun + +import ( + "fmt" + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" + "knative.dev/pkg/apis" +) + +func validateRun(run *v1alpha1.Run) (errs *apis.FieldError) { + if run.Spec.Ref.Name == "" { + errs = errs.Also(apis.ErrMissingField("name")) + } + for _, w := range run.Spec.Workspaces { + if w.SubPath != "" { + errs = errs.Also(apis.ErrDisallowedFields("spec.workspaces.subpath")) + } + } + return errs +} + +func validatePipelineTask(pTask *v1beta1.PipelineTask) error { + if pTask.Timeout != nil { + return fmt.Errorf("task level timeouts are not yet supported; declared a timeout %v", pTask.Timeout) + } + if pTask.Retries != 0 { + return fmt.Errorf("task level retries are not yet supported; declared a %d retries", pTask.Retries) + } + if len(pTask.WhenExpressions) > 0 { + return fmt.Errorf("when expressions are not supported") + } + if len(pTask.Conditions) > 0 { + return fmt.Errorf("conditions are not supported") + } + if pTask.TaskRef != nil && pTask.TaskRef.Kind != "" && pTask.TaskRef.Kind != "Task" { + return fmt.Errorf("custom tasks are not supported") + } + if pTask.TaskRef == nil { + if err := validateEmbeddedTaskSpec(pTask.TaskSpec); err != nil { + return fmt.Errorf("embedded task spec for %s is invalid: %v", pTask.Name, err) + } + } + for _, w := range pTask.Workspaces { + if w.SubPath != "" { + return fmt.Errorf("subpaths for workspaces are not yet supported using subpath %s with workspace %s", w.SubPath, w.Name) + } + } + return nil +} + +func validateEmbeddedTaskSpec(embeddedSpec *v1beta1.EmbeddedTask) error { + if len(embeddedSpec.Metadata.Labels) > 0 || len(embeddedSpec.Metadata.Annotations) > 0 { + return fmt.Errorf("annotations and labels for embedded task specs are not yet supported") + } + return nil +} + +func validateTaskSpec(taskSpec *v1beta1.TaskSpec) error { + if taskSpec.StepTemplate != nil { + return fmt.Errorf("step templates are not supported") + } + if taskSpec.Sidecars != nil { + return fmt.Errorf("sidecars are not supported") + } + if taskSpec.Resources != nil { + return fmt.Errorf("pipelineresources are not supported") + } + if len(taskSpec.Volumes) > 0 { + return fmt.Errorf("volumes are not supported") + } + for _, step := range taskSpec.Steps { + if len(step.VolumeMounts) > 0 { + return fmt.Errorf("volume mounts are not supported") + } + if len(step.Workspaces) > 0 { + return fmt.Errorf("isolated workspaces are not supported but %s is trying to use them", step.Name) + } + } + for _, w := range taskSpec.Workspaces { + if w.MountPath != "" { + return fmt.Errorf("mountPaths are not supported but trying to mount %s to %s", w.Name, w.MountPath) + } + if w.ReadOnly { + return fmt.Errorf("readOnly workspaces are not supported but %s is readOnly", w.Name) + } + if w.Optional { + return fmt.Errorf("optional workspaces are not supported but %s is optional", w.Name) + } + } + for _, p := range taskSpec.Params { + if p.Type == v1beta1.ParamTypeArray { + return fmt.Errorf("array params are not yet supported but %s is a param of type array", p.Name) + } + } + return nil +} + +func validatePipelineSpec(pSpec *v1beta1.PipelineSpec) error { + if len(pSpec.Finally) > 0 { + return fmt.Errorf("finally tasks are not supported") + } + + if len(pSpec.Results) > 0 { + return fmt.Errorf("mapping of pipeline level results not supported") + } + for _, pTask := range pSpec.Tasks { + if err := validatePipelineTask(&pTask); err != nil { + return fmt.Errorf("pipeline task %s is invalid: %v", pTask.Name, err) + } + } + return nil +} + +func validateTaskSpecs(taskSpecs map[string]*v1beta1.TaskSpec) error { + for _, taskSpec := range taskSpecs { + if err := validateTaskSpec(taskSpec); err != nil { + return fmt.Errorf("task spec is invalid: %v", err) + } + } + return nil +} diff --git a/pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/workspaces.go b/pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/workspaces.go new file mode 100644 index 000000000..1ecffb8e0 --- /dev/null +++ b/pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/workspaces.go @@ -0,0 +1,39 @@ +/* +Copyright 2021 The Tekton Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pipelinetotaskrun + +import ( + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" +) + +type PipelineTaskToWorkspaces map[string]map[string]string + +// getNewWorkspaceMapping will create an object that maps from the mapped workspaces in each pipeline task in pTasks to +// the pipeline level workspace that is actually used. It returns a map where they keys are pipeline task names, and +// the values are dictionaries that map each of the task's declared workspaces to the actual workspaces used. +func getNewWorkspaceMapping(pTasks []v1beta1.PipelineTask) PipelineTaskToWorkspaces { + mapping := PipelineTaskToWorkspaces{} + + for _, pTask := range pTasks { + mapping[pTask.Name] = map[string]string{} + for _, wsBinding := range pTask.Workspaces { + mapping[pTask.Name][wsBinding.Name] = wsBinding.Workspace + } + } + + return mapping +} diff --git a/pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/workspaces_test.go b/pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/workspaces_test.go new file mode 100644 index 000000000..817b96e3a --- /dev/null +++ b/pipeline-to-taskrun/pkg/reconciler/pipelinetotaskrun/workspaces_test.go @@ -0,0 +1,93 @@ +/* +Copyright 2021 The Tekton Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pipelinetotaskrun + +import ( + "github.com/google/go-cmp/cmp" + "github.com/tektoncd/experimental/pipeline-to-taskrun/test" + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" + "github.com/tektoncd/pipeline/test/diff" + "testing" +) + +func TestGetNewWorkspaceMapping(t *testing.T) { + p := test.MustParsePipeline(t, ` +spec: + tasks: + - name: grab-source + workspaces: + - name: output + workspace: where-it-all-happens + - name: run-tests + workspaces: + - name: source + workspace: where-it-all-happens + - name: upload-results + workspaces: + - name: source + workspace: where-it-all-happens + - name: credentials + workspace: gcs-creds +`) + var pTasks []v1beta1.PipelineTask + for _, ptask := range p.Spec.Tasks { + pTasks = append(pTasks, ptask) + } + expectedMapping := PipelineTaskToWorkspaces{ + "grab-source": { + "output": "where-it-all-happens", + }, + "run-tests": { + "source": "where-it-all-happens", + }, + "upload-results": { + "source": "where-it-all-happens", + "credentials": "gcs-creds", + }, + } + + mapping := getNewWorkspaceMapping(pTasks) + + if d := cmp.Diff(expectedMapping, mapping); d != "" { + t.Errorf("Did not get expected workspace mapping: %v", diff.PrintWantGot(d)) + } +} + +func TestGetNewWorkspaceMappingNoWorkspaces(t *testing.T) { + p := test.MustParsePipeline(t, ` +spec: + tasks: + - name: grab-source + - name: run-tests + - name: upload-results +`) + var pTasks []v1beta1.PipelineTask + for _, ptask := range p.Spec.Tasks { + pTasks = append(pTasks, ptask) + } + expectedMapping := PipelineTaskToWorkspaces{ + "grab-source": {}, + "run-tests": {}, + "upload-results": {}, + } + + mapping := getNewWorkspaceMapping(pTasks) + + if d := cmp.Diff(expectedMapping, mapping); d != "" { + t.Errorf("Did not get expected workspace mapping: %v", diff.PrintWantGot(d)) + } +} diff --git a/pipeline-to-taskrun/test/README.md b/pipeline-to-taskrun/test/README.md new file mode 100644 index 000000000..326e3098d --- /dev/null +++ b/pipeline-to-taskrun/test/README.md @@ -0,0 +1,4 @@ +# Test libs + +The contents of this folder were copied as-is from +https://github.com/tektoncd/experimental/tree/main/pipelines-in-pipelines/test \ No newline at end of file diff --git a/pipeline-to-taskrun/test/controller.go b/pipeline-to-taskrun/test/controller.go new file mode 100644 index 000000000..c61b6f73a --- /dev/null +++ b/pipeline-to-taskrun/test/controller.go @@ -0,0 +1,309 @@ +/* +Copyright 2021 The Tekton Authors +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. +*/ + +// Copied from https://github.com/tektoncd/experimental/blob/main/pipelines-in-pipelines/test/controller.go + +package test + +import ( + "context" + "fmt" + fakepipelineclient "github.com/tektoncd/pipeline/pkg/client/injection/client/fake" + fakeconditioninformer "github.com/tektoncd/pipeline/pkg/client/injection/informers/pipeline/v1alpha1/condition/fake" + fakeruninformer "github.com/tektoncd/pipeline/pkg/client/injection/informers/pipeline/v1alpha1/run/fake" + fakeclustertaskinformer "github.com/tektoncd/pipeline/pkg/client/injection/informers/pipeline/v1beta1/clustertask/fake" + fakepipelineinformer "github.com/tektoncd/pipeline/pkg/client/injection/informers/pipeline/v1beta1/pipeline/fake" + fakepipelineruninformer "github.com/tektoncd/pipeline/pkg/client/injection/informers/pipeline/v1beta1/pipelinerun/fake" + faketaskinformer "github.com/tektoncd/pipeline/pkg/client/injection/informers/pipeline/v1beta1/task/fake" + faketaskruninformer "github.com/tektoncd/pipeline/pkg/client/injection/informers/pipeline/v1beta1/taskrun/fake" + fakeresourceclient "github.com/tektoncd/pipeline/pkg/client/resource/injection/client/fake" + fakeresourceinformer "github.com/tektoncd/pipeline/pkg/client/resource/injection/informers/resource/v1alpha1/pipelineresource/fake" + apierrs "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + ktesting "k8s.io/client-go/testing" + "k8s.io/client-go/tools/cache" + fakekubeclient "knative.dev/pkg/client/injection/kube/client/fake" + fakeconfigmapinformer "knative.dev/pkg/client/injection/kube/informers/core/v1/configmap/fake" + fakepodinformer "knative.dev/pkg/client/injection/kube/informers/core/v1/pod/fake" + fakeserviceaccountinformer "knative.dev/pkg/client/injection/kube/informers/core/v1/serviceaccount/fake" + "sync/atomic" + "testing" + + // Link in the fakes so they get injected into injection.Fake + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" + fakepipelineclientset "github.com/tektoncd/pipeline/pkg/client/clientset/versioned/fake" + informersv1alpha1 "github.com/tektoncd/pipeline/pkg/client/informers/externalversions/pipeline/v1alpha1" + informersv1beta1 "github.com/tektoncd/pipeline/pkg/client/informers/externalversions/pipeline/v1beta1" + fakeresourceclientset "github.com/tektoncd/pipeline/pkg/client/resource/clientset/versioned/fake" + resourceinformersv1alpha1 "github.com/tektoncd/pipeline/pkg/client/resource/informers/externalversions/resource/v1alpha1" + cloudeventclient "github.com/tektoncd/pipeline/pkg/reconciler/events/cloudevent" + "go.uber.org/zap" + corev1 "k8s.io/api/core/v1" + coreinformers "k8s.io/client-go/informers/core/v1" + fakekubeclientset "k8s.io/client-go/kubernetes/fake" + "k8s.io/client-go/tools/record" + "knative.dev/pkg/controller" +) + +// Data represents the desired state of the system (i.e. existing resources) to seed controllers +// with. +type Data struct { + PipelineRuns []*v1beta1.PipelineRun + Pipelines []*v1beta1.Pipeline + TaskRuns []*v1beta1.TaskRun + Tasks []*v1beta1.Task + ClusterTasks []*v1beta1.ClusterTask + PipelineResources []*v1alpha1.PipelineResource + Conditions []*v1alpha1.Condition + Runs []*v1alpha1.Run + Pods []*corev1.Pod + Namespaces []*corev1.Namespace + ConfigMaps []*corev1.ConfigMap + ServiceAccounts []*corev1.ServiceAccount +} + +// Clients holds references to clients which are useful for reconciler tests. +type Clients struct { + Pipeline *fakepipelineclientset.Clientset + Resource *fakeresourceclientset.Clientset + Kube *fakekubeclientset.Clientset + CloudEvents cloudeventclient.CEClient +} + +// Informers holds references to informers which are useful for reconciler tests. +type Informers struct { + PipelineRun informersv1beta1.PipelineRunInformer + Pipeline informersv1beta1.PipelineInformer + TaskRun informersv1beta1.TaskRunInformer + Run informersv1alpha1.RunInformer + Task informersv1beta1.TaskInformer + ClusterTask informersv1beta1.ClusterTaskInformer + PipelineResource resourceinformersv1alpha1.PipelineResourceInformer + Condition informersv1alpha1.ConditionInformer + Pod coreinformers.PodInformer + ConfigMap coreinformers.ConfigMapInformer + ServiceAccount coreinformers.ServiceAccountInformer +} + +// Assets holds references to the controller, logs, clients, and informers. +type Assets struct { + Logger *zap.SugaredLogger + Controller *controller.Impl + Clients Clients + Informers Informers + Recorder *record.FakeRecorder + Ctx context.Context +} + +func AddToInformer(t *testing.T, store cache.Store) func(ktesting.Action) (bool, runtime.Object, error) { + return func(action ktesting.Action) (bool, runtime.Object, error) { + switch a := action.(type) { + case ktesting.CreateActionImpl: + if err := store.Add(a.GetObject()); err != nil { + t.Fatal(err) + } + + case ktesting.UpdateActionImpl: + objMeta, err := meta.Accessor(a.GetObject()) + if err != nil { + return true, nil, err + } + + // Look up the old copy of this resource and perform the optimistic concurrency check. + old, exists, err := store.GetByKey(objMeta.GetNamespace() + "/" + objMeta.GetName()) + if err != nil { + return true, nil, err + } else if !exists { + // Let the client return the error. + return false, nil, nil + } + oldMeta, err := meta.Accessor(old) + if err != nil { + return true, nil, err + } + // If the resource version is mismatched, then fail with a conflict. + if oldMeta.GetResourceVersion() != objMeta.GetResourceVersion() { + return true, nil, apierrs.NewConflict( + a.Resource.GroupResource(), objMeta.GetName(), + fmt.Errorf("resourceVersion mismatch, got: %v, wanted: %v", + objMeta.GetResourceVersion(), oldMeta.GetResourceVersion())) + } + + // Update the store with the new object when it's fine. + if err := store.Update(a.GetObject()); err != nil { + t.Fatal(err) + } + } + return false, nil, nil + } +} + +// SeedTestData returns Clients and Informers populated with the +// given Data. +// nolint: golint +func SeedTestData(t *testing.T, ctx context.Context, d Data) (Clients, Informers) { + c := Clients{ + Kube: fakekubeclient.Get(ctx), + Pipeline: fakepipelineclient.Get(ctx), + Resource: fakeresourceclient.Get(ctx), + CloudEvents: cloudeventclient.Get(ctx), + } + // Every time a resource is modified, change the metadata.resourceVersion. + PrependResourceVersionReactor(&c.Pipeline.Fake) + + i := Informers{ + PipelineRun: fakepipelineruninformer.Get(ctx), + Pipeline: fakepipelineinformer.Get(ctx), + TaskRun: faketaskruninformer.Get(ctx), + Run: fakeruninformer.Get(ctx), + Task: faketaskinformer.Get(ctx), + ClusterTask: fakeclustertaskinformer.Get(ctx), + PipelineResource: fakeresourceinformer.Get(ctx), + Condition: fakeconditioninformer.Get(ctx), + Pod: fakepodinformer.Get(ctx), + ConfigMap: fakeconfigmapinformer.Get(ctx), + ServiceAccount: fakeserviceaccountinformer.Get(ctx), + } + + // Attach reactors that add resource mutations to the appropriate + // informer index, and simulate optimistic concurrency failures when + // the resource version is mismatched. + c.Pipeline.PrependReactor("*", "pipelineruns", AddToInformer(t, i.PipelineRun.Informer().GetIndexer())) + for _, pr := range d.PipelineRuns { + pr := pr.DeepCopy() // Avoid assumptions that the informer's copy is modified. + if _, err := c.Pipeline.TektonV1beta1().PipelineRuns(pr.Namespace).Create(ctx, pr, metav1.CreateOptions{}); err != nil { + t.Fatal(err) + } + } + c.Pipeline.PrependReactor("*", "pipelines", AddToInformer(t, i.Pipeline.Informer().GetIndexer())) + for _, p := range d.Pipelines { + p := p.DeepCopy() // Avoid assumptions that the informer's copy is modified. + if _, err := c.Pipeline.TektonV1beta1().Pipelines(p.Namespace).Create(ctx, p, metav1.CreateOptions{}); err != nil { + t.Fatal(err) + } + } + c.Pipeline.PrependReactor("*", "taskruns", AddToInformer(t, i.TaskRun.Informer().GetIndexer())) + for _, tr := range d.TaskRuns { + tr := tr.DeepCopy() // Avoid assumptions that the informer's copy is modified. + if _, err := c.Pipeline.TektonV1beta1().TaskRuns(tr.Namespace).Create(ctx, tr, metav1.CreateOptions{}); err != nil { + t.Fatal(err) + } + } + c.Pipeline.PrependReactor("*", "tasks", AddToInformer(t, i.Task.Informer().GetIndexer())) + for _, ta := range d.Tasks { + ta := ta.DeepCopy() // Avoid assumptions that the informer's copy is modified. + if _, err := c.Pipeline.TektonV1beta1().Tasks(ta.Namespace).Create(ctx, ta, metav1.CreateOptions{}); err != nil { + t.Fatal(err) + } + } + c.Pipeline.PrependReactor("*", "clustertasks", AddToInformer(t, i.ClusterTask.Informer().GetIndexer())) + for _, ct := range d.ClusterTasks { + ct := ct.DeepCopy() // Avoid assumptions that the informer's copy is modified. + if _, err := c.Pipeline.TektonV1beta1().ClusterTasks().Create(ctx, ct, metav1.CreateOptions{}); err != nil { + t.Fatal(err) + } + } + c.Resource.PrependReactor("*", "pipelineresources", AddToInformer(t, i.PipelineResource.Informer().GetIndexer())) + for _, r := range d.PipelineResources { + r := r.DeepCopy() // Avoid assumptions that the informer's copy is modified. + if _, err := c.Resource.TektonV1alpha1().PipelineResources(r.Namespace).Create(ctx, r, metav1.CreateOptions{}); err != nil { + t.Fatal(err) + } + } + c.Pipeline.PrependReactor("*", "conditions", AddToInformer(t, i.Condition.Informer().GetIndexer())) + for _, cond := range d.Conditions { + cond := cond.DeepCopy() // Avoid assumptions that the informer's copy is modified. + if _, err := c.Pipeline.TektonV1alpha1().Conditions(cond.Namespace).Create(ctx, cond, metav1.CreateOptions{}); err != nil { + t.Fatal(err) + } + } + c.Pipeline.PrependReactor("*", "runs", AddToInformer(t, i.Run.Informer().GetIndexer())) + for _, run := range d.Runs { + run := run.DeepCopy() // Avoid assumptions that the informer's copy is modified. + if _, err := c.Pipeline.TektonV1alpha1().Runs(run.Namespace).Create(ctx, run, metav1.CreateOptions{}); err != nil { + t.Fatal(err) + } + } + c.Kube.PrependReactor("*", "pods", AddToInformer(t, i.Pod.Informer().GetIndexer())) + for _, p := range d.Pods { + p := p.DeepCopy() // Avoid assumptions that the informer's copy is modified. + if _, err := c.Kube.CoreV1().Pods(p.Namespace).Create(ctx, p, metav1.CreateOptions{}); err != nil { + t.Fatal(err) + } + } + for _, n := range d.Namespaces { + n := n.DeepCopy() // Avoid assumptions that the informer's copy is modified. + if _, err := c.Kube.CoreV1().Namespaces().Create(ctx, n, metav1.CreateOptions{}); err != nil { + t.Fatal(err) + } + } + c.Kube.PrependReactor("*", "configmaps", AddToInformer(t, i.ConfigMap.Informer().GetIndexer())) + for _, cm := range d.ConfigMaps { + cm := cm.DeepCopy() // Avoid assumptions that the informer's copy is modified. + if _, err := c.Kube.CoreV1().ConfigMaps(cm.Namespace).Create(ctx, cm, metav1.CreateOptions{}); err != nil { + t.Fatal(err) + } + } + c.Kube.PrependReactor("*", "serviceaccounts", AddToInformer(t, i.ServiceAccount.Informer().GetIndexer())) + for _, sa := range d.ServiceAccounts { + sa := sa.DeepCopy() // Avoid assumptions that the informer's copy is modified. + if _, err := c.Kube.CoreV1().ServiceAccounts(sa.Namespace).Create(ctx, sa, metav1.CreateOptions{}); err != nil { + t.Fatal(err) + } + } + c.Pipeline.ClearActions() + c.Kube.ClearActions() + return c, i +} + +type ResourceVersionReactor struct { + count int64 +} + +func (r *ResourceVersionReactor) Handles(action ktesting.Action) bool { + body := func(o runtime.Object) bool { + objMeta, err := meta.Accessor(o) + if err != nil { + return false + } + val := atomic.AddInt64(&r.count, 1) + objMeta.SetResourceVersion(fmt.Sprintf("%05d", val)) + return false + } + + switch o := action.(type) { + case ktesting.CreateActionImpl: + return body(o.GetObject()) + case ktesting.UpdateActionImpl: + return body(o.GetObject()) + default: + return false + } +} + +// React is noop-function +func (r *ResourceVersionReactor) React(action ktesting.Action) (handled bool, ret runtime.Object, err error) { + return false, nil, nil +} + +var _ ktesting.Reactor = (*ResourceVersionReactor)(nil) + +// PrependResourceVersionReactor will instrument a client-go testing Fake +// with a reactor that simulates resourceVersion changes on mutations. +// This does not work with patches. +func PrependResourceVersionReactor(f *ktesting.Fake) { + f.ReactionChain = append([]ktesting.Reactor{&ResourceVersionReactor{}}, f.ReactionChain...) +} diff --git a/pipeline-to-taskrun/test/presubmit-tests.sh b/pipeline-to-taskrun/test/presubmit-tests.sh new file mode 100755 index 000000000..a9db3f8bc --- /dev/null +++ b/pipeline-to-taskrun/test/presubmit-tests.sh @@ -0,0 +1,66 @@ +#!/usr/bin/env bash + +# Copyright 2021 The Tekton Authors +# +# 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. + +# This script runs the presubmit tests; it is started by prow for each PR. +# For convenience, it can also be executed manually. +# Running the script without parameters, or with the --all-tests +# flag, causes all tests to be executed, in the right order. +# Use the flags --build-tests, --unit-tests and --integration-tests +# to run a specific set of tests. + +# Markdown linting failures don't show up properly in Gubernator resulting +# in a net-negative contributor experience. +export DISABLE_MD_LINTING=1 +export TEST_FOLDER=$(pwd) +export GO111MODULE=on + +source $(dirname $0)/../../vendor/github.com/tektoncd/plumbing/scripts/presubmit-tests.sh + +function pre_build_tests() { + pushd ${TEST_FOLDER} +} + +function pre_unit_tests() { + pushd ${TEST_FOLDER} +} + +function pre_integration_tests() { + pushd ${TEST_FOLDER} +} + +function post_build_tests() { + popd +} + +function post_unit_tests() { + popd +} + +function post_integration_tests() { + popd +} + +# June 28th 2019: work around https://github.com/tektoncd/plumbing/issues/44 +function unit_tests() { + local failed=0 + echo "Using overridden unit_tests" + go test -v -race ./... || failed=1 + echo "unit_tests returning $@" + return ${failed} +} + +# We use the default build, unit and integration test runners. +main $@ diff --git a/pipeline-to-taskrun/test/yaml.go b/pipeline-to-taskrun/test/yaml.go new file mode 100644 index 000000000..6c2074154 --- /dev/null +++ b/pipeline-to-taskrun/test/yaml.go @@ -0,0 +1,76 @@ +/* +Copyright 2021 The Tekton Authors +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. +*/ + +// copied from https://github.com/tektoncd/pipeline/blob/main/test/yaml.go + +package test + +import ( + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + "testing" + + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" + "github.com/tektoncd/pipeline/pkg/client/clientset/versioned/scheme" + "k8s.io/apimachinery/pkg/runtime" +) + +func mustParseYAML(t *testing.T, yaml string, i runtime.Object) { + if _, _, err := scheme.Codecs.UniversalDeserializer().Decode([]byte(yaml), nil, i); err != nil { + t.Fatalf("mustParseYAML (%s): %v", yaml, err) + } +} + +func MustParseTaskRun(t *testing.T, yaml string) *v1beta1.TaskRun { + var tr v1beta1.TaskRun + yaml = `apiVersion: tekton.dev/v1beta1 +kind: TaskRun +` + yaml + mustParseYAML(t, yaml, &tr) + return &tr +} + +func MustParseTask(t *testing.T, yaml string) *v1beta1.Task { + var task v1beta1.Task + yaml = `apiVersion: tekton.dev/v1beta1 +kind: Task +` + yaml + mustParseYAML(t, yaml, &task) + return &task +} + +func MustParsePipelineRun(t *testing.T, yaml string) *v1beta1.PipelineRun { + var pr v1beta1.PipelineRun + yaml = `apiVersion: tekton.dev/v1beta1 +kind: PipelineRun +` + yaml + mustParseYAML(t, yaml, &pr) + return &pr +} + +func MustParsePipeline(t *testing.T, yaml string) *v1beta1.Pipeline { + var pipeline v1beta1.Pipeline + yaml = `apiVersion: tekton.dev/v1beta1 +kind: Pipeline +` + yaml + mustParseYAML(t, yaml, &pipeline) + return &pipeline +} + +func MustParseRun(t *testing.T, yaml string) *v1alpha1.Run { + var run v1alpha1.Run + yaml = `apiVersion: tekton.dev/v1alpha1 +kind: Run +` + yaml + mustParseYAML(t, yaml, &run) + return &run +}