diff --git a/cmd/imagedigestexporter/main.go b/cmd/imagedigestexporter/main.go index c0fd7472f81..1d8b20490ee 100644 --- a/cmd/imagedigestexporter/main.go +++ b/cmd/imagedigestexporter/main.go @@ -25,6 +25,7 @@ import ( "github.com/google/go-containerregistry/pkg/v1/layout" v1alpha1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + "github.com/tektoncd/pipeline/pkg/apis/resource/v1alpha1/image" ) var ( @@ -46,7 +47,7 @@ func main() { _ = logger.Sync() }() - imageResources := []*v1alpha1.ImageResource{} + imageResources := []*image.Resource{} if err := json.Unmarshal([]byte(*images), &imageResources); err != nil { logger.Fatalf("Error reading images array: %v", err) } diff --git a/cmd/kubeconfigwriter/main.go b/cmd/kubeconfigwriter/main.go index e24d55dcd42..915186bff41 100644 --- a/cmd/kubeconfigwriter/main.go +++ b/cmd/kubeconfigwriter/main.go @@ -23,13 +23,12 @@ import ( "os" "strings" + "github.com/tektoncd/pipeline/pkg/apis/resource/v1alpha1/cluster" + "github.com/tektoncd/pipeline/pkg/logging" "go.uber.org/zap" + _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" "k8s.io/client-go/tools/clientcmd" clientcmdapi "k8s.io/client-go/tools/clientcmd/api" - - v1alpha1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" - "github.com/tektoncd/pipeline/pkg/logging" - _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" ) var ( @@ -44,7 +43,7 @@ func main() { _ = logger.Sync() }() - cr := v1alpha1.ClusterResource{} + cr := cluster.Resource{} err := json.Unmarshal([]byte(*clusterConfig), &cr) if err != nil { logger.Fatalf("Error reading cluster config: %v", err) @@ -52,7 +51,7 @@ func main() { createKubeconfigFile(&cr, logger) } -func createKubeconfigFile(resource *v1alpha1.ClusterResource, logger *zap.SugaredLogger) { +func createKubeconfigFile(resource *cluster.Resource, logger *zap.SugaredLogger) { cluster := &clientcmdapi.Cluster{ Server: resource.URL, InsecureSkipTLSVerify: resource.Insecure, diff --git a/hack/update-codegen.sh b/hack/update-codegen.sh index b160e267a52..1069d6b06bb 100755 --- a/hack/update-codegen.sh +++ b/hack/update-codegen.sh @@ -49,7 +49,12 @@ ${GOPATH}/bin/deepcopy-gen \ ${GOPATH}/bin/deepcopy-gen \ -O zz_generated.deepcopy \ --go-header-file ${REPO_ROOT_DIR}/hack/boilerplate/boilerplate.go.txt \ - -i github.com/tektoncd/pipeline/pkg/apis/pipeline/pod +-i github.com/tektoncd/pipeline/pkg/apis/pipeline/pod + +${GOPATH}/bin/deepcopy-gen \ + -O zz_generated.deepcopy \ + --go-header-file ${REPO_ROOT_DIR}/hack/boilerplate/boilerplate.go.txt \ +-i github.com/tektoncd/pipeline/pkg/apis/resource/v1alpha1/storage # Knative Injection # This generates the knative injection packages for the resource package (v1alpha1). diff --git a/pkg/apis/pipeline/v1alpha1/resource_types.go b/pkg/apis/pipeline/v1alpha1/resource_types.go index 18acf5b4864..a725022c103 100644 --- a/pkg/apis/pipeline/v1alpha1/resource_types.go +++ b/pkg/apis/pipeline/v1alpha1/resource_types.go @@ -20,7 +20,6 @@ import ( "fmt" "github.com/google/go-cmp/cmp" - "github.com/tektoncd/pipeline/pkg/apis/pipeline" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha2" ) @@ -108,24 +107,3 @@ type PipelineResourceResult = v1alpha2.PipelineResourceResult // ResultType used to find out whether a PipelineResourceResult is from a task result or not type ResultType = v1alpha2.ResultType - -// ResourceFromType returns an instance of the correct PipelineResource object type which can be -// used to add input and output containers as well as volumes to a TaskRun's pod in order to realize -// a PipelineResource in a pod. -func ResourceFromType(r *PipelineResource, images pipeline.Images) (PipelineResourceInterface, error) { - switch r.Spec.Type { - case PipelineResourceTypeGit: - return NewGitResource(images.GitImage, r) - case PipelineResourceTypeImage: - return NewImageResource(r) - case PipelineResourceTypeCluster: - return NewClusterResource(images.KubeconfigWriterImage, r) - case PipelineResourceTypeStorage: - return NewStorageResource(images, r) - case PipelineResourceTypePullRequest: - return NewPullRequestResource(images.PRImage, r) - case PipelineResourceTypeCloudEvent: - return NewCloudEventResource(r) - } - return nil, fmt.Errorf("%s is an invalid or unimplemented PipelineResource", r.Spec.Type) -} diff --git a/pkg/apis/pipeline/v1alpha1/storage_resource.go b/pkg/apis/pipeline/v1alpha1/storage_resource.go index 11fe6be2fba..82f550111cc 100644 --- a/pkg/apis/pipeline/v1alpha1/storage_resource.go +++ b/pkg/apis/pipeline/v1alpha1/storage_resource.go @@ -1,5 +1,5 @@ /* -Copyright 2019 The Tekton Authors +Copyright 2019-2020 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. @@ -17,16 +17,9 @@ limitations under the License. package v1alpha1 import ( - "fmt" - "strings" - - "github.com/tektoncd/pipeline/pkg/apis/pipeline" resource "github.com/tektoncd/pipeline/pkg/apis/resource/v1alpha1" - corev1 "k8s.io/api/core/v1" ) -type PipelineResourceStorageType string - const ( // PipelineResourceTypeGCS is the subtype for the GCSResources, which is backed by a GCS blob/directory. PipelineResourceTypeGCS PipelineResourceType = resource.PipelineResourceTypeGCS @@ -35,62 +28,3 @@ const ( // with additional functionality that was added to be compatible with knative build. PipelineResourceTypeBuildGCS PipelineResourceType = resource.PipelineResourceTypeBuildGCS ) - -// PipelineStorageResourceInterface is the interface for subtypes of the storage type. -// It adds a function to the PipelineResourceInterface for retrieving secrets that are usually -// needed for storage PipelineResources. -type PipelineStorageResourceInterface interface { - PipelineResourceInterface - GetSecretParams() []SecretParam -} - -// NewStorageResource returns an instance of the requested storage subtype, which can be used -// to add input and output steps and volumes to an executing pod. -func NewStorageResource(images pipeline.Images, r *PipelineResource) (PipelineStorageResourceInterface, error) { - if r.Spec.Type != PipelineResourceTypeStorage { - return nil, fmt.Errorf("StoreResource: Cannot create a storage resource from a %s Pipeline Resource", r.Spec.Type) - } - - for _, param := range r.Spec.Params { - if strings.EqualFold(param.Name, "type") { - switch { - case strings.EqualFold(param.Value, string(PipelineResourceTypeGCS)): - return NewGCSResource(images, r) - case strings.EqualFold(param.Value, string(PipelineResourceTypeBuildGCS)): - return NewBuildGCSResource(images, r) - default: - return nil, fmt.Errorf("%s is an invalid or unimplemented PipelineStorageResource", param.Value) - } - } - } - return nil, fmt.Errorf("StoreResource: Cannot create a storage resource without type %s in spec", r.Name) -} - -func getStorageVolumeSpec(s PipelineStorageResourceInterface, spec TaskSpec) []corev1.Volume { - var storageVol []corev1.Volume - mountedSecrets := map[string]string{} - - for _, volume := range spec.Volumes { - mountedSecrets[volume.Name] = "" - } - - // Map holds list of secrets that are mounted as volumes - for _, secretParam := range s.GetSecretParams() { - volName := fmt.Sprintf("volume-%s-%s", s.GetName(), secretParam.SecretName) - - gcsSecretVolume := corev1.Volume{ - Name: volName, - VolumeSource: corev1.VolumeSource{ - Secret: &corev1.SecretVolumeSource{ - SecretName: secretParam.SecretName, - }, - }, - } - - if _, ok := mountedSecrets[volName]; !ok { - storageVol = append(storageVol, gcsSecretVolume) - mountedSecrets[volName] = "" - } - } - return storageVol -} diff --git a/pkg/apis/pipeline/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/pipeline/v1alpha1/zz_generated.deepcopy.go index 371c43d3eb0..e4075156188 100644 --- a/pkg/apis/pipeline/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/pipeline/v1alpha1/zz_generated.deepcopy.go @@ -24,69 +24,10 @@ import ( pod "github.com/tektoncd/pipeline/pkg/apis/pipeline/pod" v1alpha2 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha2" resourcev1alpha1 "github.com/tektoncd/pipeline/pkg/apis/resource/v1alpha1" - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ArtifactBucket) DeepCopyInto(out *ArtifactBucket) { - *out = *in - if in.Secrets != nil { - in, out := &in.Secrets, &out.Secrets - *out = make([]resourcev1alpha1.SecretParam, len(*in)) - copy(*out, *in) - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ArtifactBucket. -func (in *ArtifactBucket) DeepCopy() *ArtifactBucket { - if in == nil { - return nil - } - out := new(ArtifactBucket) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ArtifactPVC) DeepCopyInto(out *ArtifactPVC) { - *out = *in - if in.PersistentVolumeClaim != nil { - in, out := &in.PersistentVolumeClaim, &out.PersistentVolumeClaim - *out = new(v1.PersistentVolumeClaim) - (*in).DeepCopyInto(*out) - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ArtifactPVC. -func (in *ArtifactPVC) DeepCopy() *ArtifactPVC { - if in == nil { - return nil - } - out := new(ArtifactPVC) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *BuildGCSResource) DeepCopyInto(out *BuildGCSResource) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BuildGCSResource. -func (in *BuildGCSResource) DeepCopy() *BuildGCSResource { - if in == nil { - return nil - } - out := new(BuildGCSResource) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CannotConvertError) DeepCopyInto(out *CannotConvertError) { *out = *in @@ -103,48 +44,6 @@ func (in *CannotConvertError) DeepCopy() *CannotConvertError { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *CloudEventResource) DeepCopyInto(out *CloudEventResource) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CloudEventResource. -func (in *CloudEventResource) DeepCopy() *CloudEventResource { - if in == nil { - return nil - } - out := new(CloudEventResource) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ClusterResource) DeepCopyInto(out *ClusterResource) { - *out = *in - if in.CAData != nil { - in, out := &in.CAData, &out.CAData - *out = make([]byte, len(*in)) - copy(*out, *in) - } - if in.Secrets != nil { - in, out := &in.Secrets, &out.Secrets - *out = make([]resourcev1alpha1.SecretParam, len(*in)) - copy(*out, *in) - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterResource. -func (in *ClusterResource) DeepCopy() *ClusterResource { - if in == nil { - return nil - } - out := new(ClusterResource) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ClusterTask) DeepCopyInto(out *ClusterTask) { *out = *in @@ -314,59 +213,6 @@ func (in *ConditionSpec) DeepCopy() *ConditionSpec { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *GCSResource) DeepCopyInto(out *GCSResource) { - *out = *in - if in.Secrets != nil { - in, out := &in.Secrets, &out.Secrets - *out = make([]resourcev1alpha1.SecretParam, len(*in)) - copy(*out, *in) - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GCSResource. -func (in *GCSResource) DeepCopy() *GCSResource { - if in == nil { - return nil - } - out := new(GCSResource) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *GitResource) DeepCopyInto(out *GitResource) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GitResource. -func (in *GitResource) DeepCopy() *GitResource { - if in == nil { - return nil - } - out := new(GitResource) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ImageResource) DeepCopyInto(out *ImageResource) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImageResource. -func (in *ImageResource) DeepCopy() *ImageResource { - if in == nil { - return nil - } - out := new(ImageResource) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Inputs) DeepCopyInto(out *Inputs) { *out = *in @@ -581,7 +427,7 @@ func (in *PipelineRunSpec) DeepCopyInto(out *PipelineRunSpec) { } if in.Timeout != nil { in, out := &in.Timeout, &out.Timeout - *out = new(metav1.Duration) + *out = new(v1.Duration) **out = **in } if in.PodTemplate != nil { @@ -709,7 +555,7 @@ func (in *PipelineTask) DeepCopyInto(out *PipelineTask) { } if in.Timeout != nil { in, out := &in.Timeout, &out.Timeout - *out = new(metav1.Duration) + *out = new(v1.Duration) **out = **in } return @@ -747,27 +593,6 @@ func (in PipelineTaskList) DeepCopy() PipelineTaskList { return *out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PullRequestResource) DeepCopyInto(out *PullRequestResource) { - *out = *in - if in.Secrets != nil { - in, out := &in.Secrets, &out.Secrets - *out = make([]resourcev1alpha1.SecretParam, len(*in)) - copy(*out, *in) - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PullRequestResource. -func (in *PullRequestResource) DeepCopy() *PullRequestResource { - if in == nil { - return nil - } - out := new(PullRequestResource) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Task) DeepCopyInto(out *Task) { *out = *in @@ -996,7 +821,7 @@ func (in *TaskRunSpec) DeepCopyInto(out *TaskRunSpec) { } if in.Timeout != nil { in, out := &in.Timeout, &out.Timeout - *out = new(metav1.Duration) + *out = new(v1.Duration) **out = **in } if in.PodTemplate != nil { diff --git a/pkg/apis/resource/resource.go b/pkg/apis/resource/resource.go new file mode 100644 index 00000000000..df1fda2e546 --- /dev/null +++ b/pkg/apis/resource/resource.go @@ -0,0 +1,52 @@ +/* +Copyright 2019 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 resource + +import ( + "fmt" + + "github.com/tektoncd/pipeline/pkg/apis/pipeline" + pipelinev1alpha1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + resourcev1alpha1 "github.com/tektoncd/pipeline/pkg/apis/resource/v1alpha1" + "github.com/tektoncd/pipeline/pkg/apis/resource/v1alpha1/cloudevent" + "github.com/tektoncd/pipeline/pkg/apis/resource/v1alpha1/cluster" + "github.com/tektoncd/pipeline/pkg/apis/resource/v1alpha1/git" + "github.com/tektoncd/pipeline/pkg/apis/resource/v1alpha1/image" + "github.com/tektoncd/pipeline/pkg/apis/resource/v1alpha1/pullrequest" + "github.com/tektoncd/pipeline/pkg/apis/resource/v1alpha1/storage" +) + +// FromType returns an instance of the correct PipelineResource object type which can be +// used to add input and output containers as well as volumes to a TaskRun's pod in order to realize +// a PipelineResource in a pod. +func FromType(r *resourcev1alpha1.PipelineResource, images pipeline.Images) (pipelinev1alpha1.PipelineResourceInterface, error) { + switch r.Spec.Type { + case resourcev1alpha1.PipelineResourceTypeGit: + return git.NewResource(images.GitImage, r) + case resourcev1alpha1.PipelineResourceTypeImage: + return image.NewResource(r) + case resourcev1alpha1.PipelineResourceTypeCluster: + return cluster.NewResource(images.KubeconfigWriterImage, r) + case resourcev1alpha1.PipelineResourceTypeStorage: + return storage.NewResource(images, r) + case resourcev1alpha1.PipelineResourceTypePullRequest: + return pullrequest.NewResource(images.PRImage, r) + case resourcev1alpha1.PipelineResourceTypeCloudEvent: + return cloudevent.NewResource(r) + } + return nil, fmt.Errorf("%s is an invalid or unimplemented PipelineResource", r.Spec.Type) +} diff --git a/pkg/apis/pipeline/v1alpha1/cloud_event_resource.go b/pkg/apis/resource/v1alpha1/cloudevent/cloud_event_resource.go similarity index 55% rename from pkg/apis/pipeline/v1alpha1/cloud_event_resource.go rename to pkg/apis/resource/v1alpha1/cloudevent/cloud_event_resource.go index e83fb0de827..122e5d28bdd 100644 --- a/pkg/apis/pipeline/v1alpha1/cloud_event_resource.go +++ b/pkg/apis/resource/v1alpha1/cloudevent/cloud_event_resource.go @@ -1,5 +1,5 @@ /* -Copyright 2019 The Tekton Authors. +Copyright 2019-2020 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. @@ -14,27 +14,30 @@ See the License for the specific language governing permissions and limitations under the License. */ -package v1alpha1 +package cloudevent import ( "fmt" "strings" + + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + resource "github.com/tektoncd/pipeline/pkg/apis/resource/v1alpha1" ) -// CloudEventResource is an event sink to which events are delivered when a TaskRun has finished -type CloudEventResource struct { +// Resource is an event sink to which events are delivered when a TaskRun has finished +type Resource struct { // Name is the name used to reference to the PipelineResource Name string `json:"name"` // Type must be `PipelineResourceTypeCloudEvent` - Type PipelineResourceType `json:"type"` + Type resource.PipelineResourceType `json:"type"` // TargetURI is the URI of the sink which the cloud event is develired to TargetURI string `json:"targetURI"` } -// NewCloudEventResource creates a new CloudEvent resource to pass to a Task -func NewCloudEventResource(r *PipelineResource) (*CloudEventResource, error) { - if r.Spec.Type != PipelineResourceTypeCloudEvent { - return nil, fmt.Errorf("CloudEventResource: Cannot create a Cloud Event resource from a %s Pipeline Resource", r.Spec.Type) +// NewResource creates a new CloudEvent resource to pass to a Task +func NewResource(r *resource.PipelineResource) (*Resource, error) { + if r.Spec.Type != resource.PipelineResourceTypeCloudEvent { + return nil, fmt.Errorf("cloudevent.Resource: Cannot create a Cloud Event resource from a %s Pipeline Resource", r.Spec.Type) } var targetURI string var targetURISpecified bool @@ -49,9 +52,9 @@ func NewCloudEventResource(r *PipelineResource) (*CloudEventResource, error) { } if !targetURISpecified { - return nil, fmt.Errorf("CloudEventResource: Need URI to be specified in order to create a CloudEvent resource %s", r.Name) + return nil, fmt.Errorf("cloudevent.Resource: Need URI to be specified in order to create a CloudEvent resource %s", r.Name) } - return &CloudEventResource{ + return &Resource{ Name: r.Name, Type: r.Spec.Type, TargetURI: targetURI, @@ -59,17 +62,17 @@ func NewCloudEventResource(r *PipelineResource) (*CloudEventResource, error) { } // GetName returns the name of the resource -func (s CloudEventResource) GetName() string { +func (s Resource) GetName() string { return s.Name } // GetType returns the type of the resource, in this case "cloudEvent" -func (s CloudEventResource) GetType() PipelineResourceType { - return PipelineResourceTypeCloudEvent +func (s Resource) GetType() resource.PipelineResourceType { + return resource.PipelineResourceTypeCloudEvent } // Replacements is used for template replacement on an CloudEventResource inside of a Taskrun. -func (s *CloudEventResource) Replacements() map[string]string { +func (s *Resource) Replacements() map[string]string { return map[string]string{ "name": s.Name, "type": string(s.Type), @@ -78,11 +81,11 @@ func (s *CloudEventResource) Replacements() map[string]string { } // GetInputTaskModifier returns the TaskModifier to be used when this resource is an input. -func (s *CloudEventResource) GetInputTaskModifier(_ *TaskSpec, _ string) (TaskModifier, error) { - return &InternalTaskModifier{}, nil +func (s *Resource) GetInputTaskModifier(_ *v1alpha1.TaskSpec, _ string) (v1alpha1.TaskModifier, error) { + return &v1alpha1.InternalTaskModifier{}, nil } // GetOutputTaskModifier returns a No-op TaskModifier. -func (s *CloudEventResource) GetOutputTaskModifier(_ *TaskSpec, _ string) (TaskModifier, error) { - return &InternalTaskModifier{}, nil +func (s *Resource) GetOutputTaskModifier(_ *v1alpha1.TaskSpec, _ string) (v1alpha1.TaskModifier, error) { + return &v1alpha1.InternalTaskModifier{}, nil } diff --git a/pkg/apis/pipeline/v1alpha1/cloud_event_resource_test.go b/pkg/apis/resource/v1alpha1/cloudevent/cloud_event_resource_test.go similarity index 65% rename from pkg/apis/pipeline/v1alpha1/cloud_event_resource_test.go rename to pkg/apis/resource/v1alpha1/cloudevent/cloud_event_resource_test.go index c5ba1e2c395..16452c6141d 100644 --- a/pkg/apis/pipeline/v1alpha1/cloud_event_resource_test.go +++ b/pkg/apis/resource/v1alpha1/cloudevent/cloud_event_resource_test.go @@ -14,37 +14,38 @@ See the License for the specific language governing permissions and limitations under the License. */ -package v1alpha1_test +package cloudevent_test import ( "testing" "github.com/google/go-cmp/cmp" - "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" - + pipelinev1alpha1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + resourcev1alpha1 "github.com/tektoncd/pipeline/pkg/apis/resource/v1alpha1" + "github.com/tektoncd/pipeline/pkg/apis/resource/v1alpha1/cloudevent" tb "github.com/tektoncd/pipeline/test/builder" ) -func TestNewCloudEventResource_Invalid(t *testing.T) { +func TestNewResource_Invalid(t *testing.T) { testcases := []struct { name string - pipelineResource *v1alpha1.PipelineResource + pipelineResource *resourcev1alpha1.PipelineResource }{{ name: "create resource with no parameter", pipelineResource: tb.PipelineResource("cloud-event-resource-no-uri", "default", tb.PipelineResourceSpec( - v1alpha1.PipelineResourceTypeCloudEvent, + resourcev1alpha1.PipelineResourceTypeCloudEvent, )), }, { name: "create resource with invalid type", pipelineResource: tb.PipelineResource("git-resource", "default", tb.PipelineResourceSpec( - v1alpha1.PipelineResourceTypeGit, + resourcev1alpha1.PipelineResourceTypeGit, tb.PipelineResourceSpecParam("URL", "git://fake/repo"), tb.PipelineResourceSpecParam("Revision", "fake_rev"), )), }} for _, tc := range testcases { t.Run(tc.name, func(t *testing.T) { - _, err := v1alpha1.NewCloudEventResource(tc.pipelineResource) + _, err := cloudevent.NewResource(tc.pipelineResource) if err == nil { t.Error("Expected error creating CloudEvent resource") } @@ -52,31 +53,31 @@ func TestNewCloudEventResource_Invalid(t *testing.T) { } } -func TestNewCloudEventResource_Valid(t *testing.T) { +func TestNewResource_Valid(t *testing.T) { pr := tb.PipelineResource("cloud-event-resource-uri", "default", tb.PipelineResourceSpec( - v1alpha1.PipelineResourceTypeCloudEvent, + resourcev1alpha1.PipelineResourceTypeCloudEvent, tb.PipelineResourceSpecParam("TargetURI", "http://fake-sink"), )) - expectedCloudEventResource := &v1alpha1.CloudEventResource{ + expectedResource := &cloudevent.Resource{ Name: "cloud-event-resource-uri", TargetURI: "http://fake-sink", - Type: v1alpha1.PipelineResourceTypeCloudEvent, + Type: resourcev1alpha1.PipelineResourceTypeCloudEvent, } - r, err := v1alpha1.NewCloudEventResource(pr) + r, err := cloudevent.NewResource(pr) if err != nil { t.Fatalf("Unexpected error creating CloudEvent resource: %s", err) } - if d := cmp.Diff(expectedCloudEventResource, r); d != "" { + if d := cmp.Diff(expectedResource, r); d != "" { t.Errorf("Mismatch of CloudEvent resource: %s", d) } } func TestCloudEvent_GetReplacements(t *testing.T) { - r := &v1alpha1.CloudEventResource{ + r := &cloudevent.Resource{ Name: "cloud-event-resource", TargetURI: "http://fake-uri", - Type: v1alpha1.PipelineResourceTypeCloudEvent, + Type: resourcev1alpha1.PipelineResourceTypeCloudEvent, } expectedReplacementMap := map[string]string{ "name": "cloud-event-resource", @@ -89,31 +90,31 @@ func TestCloudEvent_GetReplacements(t *testing.T) { } func TestCloudEvent_InputContainerSpec(t *testing.T) { - r := &v1alpha1.CloudEventResource{ + r := &cloudevent.Resource{ Name: "cloud-event-resource", TargetURI: "http://fake-uri", - Type: v1alpha1.PipelineResourceTypeCloudEvent, + Type: resourcev1alpha1.PipelineResourceTypeCloudEvent, } - d, e := r.GetInputTaskModifier(&v1alpha1.TaskSpec{}, "") + d, e := r.GetInputTaskModifier(&pipelinev1alpha1.TaskSpec{}, "") if d.GetStepsToPrepend() != nil { - t.Errorf("Did not expect a download container for CloudEventResource") + t.Errorf("Did not expect a download container for Resource") } if e != nil { - t.Errorf("Did not expect an error %s when getting a download container for CloudEventResource", e) + t.Errorf("Did not expect an error %s when getting a download container for Resource", e) } } func TestCloudEvent_OutputContainerSpec(t *testing.T) { - r := &v1alpha1.CloudEventResource{ + r := &cloudevent.Resource{ Name: "cloud-event-resource", TargetURI: "http://fake-uri", - Type: v1alpha1.PipelineResourceTypeCloudEvent, + Type: resourcev1alpha1.PipelineResourceTypeCloudEvent, } - d, e := r.GetOutputTaskModifier(&v1alpha1.TaskSpec{}, "") + d, e := r.GetOutputTaskModifier(&pipelinev1alpha1.TaskSpec{}, "") if d.GetStepsToAppend() != nil { - t.Errorf("Did not expect an upload container for CloudEventResource") + t.Errorf("Did not expect an upload container for Resource") } if e != nil { - t.Errorf("Did not expect an error %s when getting an upload container for CloudEventResource", e) + t.Errorf("Did not expect an error %s when getting an upload container for Resource", e) } } diff --git a/pkg/apis/pipeline/v1alpha1/cluster_resource.go b/pkg/apis/resource/v1alpha1/cluster/cluster_resource.go similarity index 75% rename from pkg/apis/pipeline/v1alpha1/cluster_resource.go rename to pkg/apis/resource/v1alpha1/cluster/cluster_resource.go index efb6c7b4499..d9e45a07447 100644 --- a/pkg/apis/pipeline/v1alpha1/cluster_resource.go +++ b/pkg/apis/resource/v1alpha1/cluster/cluster_resource.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package v1alpha1 +package cluster import ( b64 "encoding/base64" @@ -23,15 +23,17 @@ import ( "strconv" "strings" + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + resource "github.com/tektoncd/pipeline/pkg/apis/resource/v1alpha1" "github.com/tektoncd/pipeline/pkg/names" corev1 "k8s.io/api/core/v1" ) -// ClusterResource represents a cluster configuration (kubeconfig) +// Resource represents a cluster configuration (kubeconfig) // that can be accessed by tasks in the pipeline -type ClusterResource struct { - Name string `json:"name"` - Type PipelineResourceType `json:"type"` +type Resource struct { + Name string `json:"name"` + Type resource.PipelineResourceType `json:"type"` // URL must be a host string URL string `json:"url"` Revision string `json:"revision"` @@ -49,17 +51,17 @@ type ClusterResource struct { // CAData takes precedence over CAFile CAData []byte `json:"cadata"` //Secrets holds a struct to indicate a field name and corresponding secret name to populate it - Secrets []SecretParam `json:"secrets"` + Secrets []resource.SecretParam `json:"secrets"` KubeconfigWriterImage string `json:"-"` } -// NewClusterResource create a new k8s cluster resource to pass to a pipeline task -func NewClusterResource(kubeconfigWriterImage string, r *PipelineResource) (*ClusterResource, error) { - if r.Spec.Type != PipelineResourceTypeCluster { - return nil, fmt.Errorf("ClusterResource: Cannot create a Cluster resource from a %s Pipeline Resource", r.Spec.Type) +// NewResource create a new k8s cluster resource to pass to a pipeline task +func NewResource(kubeconfigWriterImage string, r *resource.PipelineResource) (*Resource, error) { + if r.Spec.Type != resource.PipelineResourceTypeCluster { + return nil, fmt.Errorf("cluster.Resource: Cannot create a Cluster resource from a %s Pipeline Resource", r.Spec.Type) } - clusterResource := ClusterResource{ + clusterResource := Resource{ Type: r.Spec.Type, KubeconfigWriterImage: kubeconfigWriterImage, Name: r.Name, @@ -104,22 +106,22 @@ func NewClusterResource(kubeconfigWriterImage string, r *PipelineResource) (*Clu } // GetName returns the name of the resource -func (s ClusterResource) GetName() string { +func (s Resource) GetName() string { return s.Name } // GetType returns the type of the resource, in this case "cluster" -func (s ClusterResource) GetType() PipelineResourceType { - return PipelineResourceTypeCluster +func (s Resource) GetType() resource.PipelineResourceType { + return resource.PipelineResourceTypeCluster } // GetURL returns the url to be used with this resource -func (s *ClusterResource) GetURL() string { +func (s *Resource) GetURL() string { return s.URL } // Replacements is used for template replacement on a ClusterResource inside of a Taskrun. -func (s *ClusterResource) Replacements() map[string]string { +func (s *Resource) Replacements() map[string]string { return map[string]string{ "name": s.Name, "type": string(s.Type), @@ -134,18 +136,18 @@ func (s *ClusterResource) Replacements() map[string]string { } } -func (s ClusterResource) String() string { +func (s Resource) String() string { json, _ := json.Marshal(s) return string(json) } // GetOutputTaskModifier returns a No-op TaskModifier. -func (s *ClusterResource) GetOutputTaskModifier(_ *TaskSpec, _ string) (TaskModifier, error) { - return &InternalTaskModifier{}, nil +func (s *Resource) GetOutputTaskModifier(_ *v1alpha1.TaskSpec, _ string) (v1alpha1.TaskModifier, error) { + return &v1alpha1.InternalTaskModifier{}, nil } // GetInputTaskModifier returns the TaskModifier to be used when this resource is an input. -func (s *ClusterResource) GetInputTaskModifier(ts *TaskSpec, path string) (TaskModifier, error) { +func (s *Resource) GetInputTaskModifier(ts *v1alpha1.TaskSpec, path string) (v1alpha1.TaskModifier, error) { var envVars []corev1.EnvVar for _, sec := range s.Secrets { ev := corev1.EnvVar{ @@ -161,7 +163,7 @@ func (s *ClusterResource) GetInputTaskModifier(ts *TaskSpec, path string) (TaskM } envVars = append(envVars, ev) } - step := Step{Container: corev1.Container{ + step := v1alpha1.Step{Container: corev1.Container{ Name: names.SimpleNameGenerator.RestrictLengthWithRandomSuffix("kubeconfig"), Image: s.KubeconfigWriterImage, Command: []string{"/ko-app/kubeconfigwriter"}, @@ -170,7 +172,7 @@ func (s *ClusterResource) GetInputTaskModifier(ts *TaskSpec, path string) (TaskM }, Env: envVars, }} - return &InternalTaskModifier{ - StepsToPrepend: []Step{step}, + return &v1alpha1.InternalTaskModifier{ + StepsToPrepend: []v1alpha1.Step{step}, }, nil } diff --git a/pkg/apis/pipeline/v1alpha1/cluster_resource_test.go b/pkg/apis/resource/v1alpha1/cluster/cluster_resource_test.go similarity index 79% rename from pkg/apis/pipeline/v1alpha1/cluster_resource_test.go rename to pkg/apis/resource/v1alpha1/cluster/cluster_resource_test.go index 8fea1bbfd20..b504d0a3d84 100644 --- a/pkg/apis/pipeline/v1alpha1/cluster_resource_test.go +++ b/pkg/apis/resource/v1alpha1/cluster/cluster_resource_test.go @@ -14,13 +14,15 @@ See the License for the specific language governing permissions and limitations under the License. */ -package v1alpha1_test +package cluster_test import ( "testing" "github.com/google/go-cmp/cmp" - "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + pipelinev1alpha1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + resourcev1alpha1 "github.com/tektoncd/pipeline/pkg/apis/resource/v1alpha1" + "github.com/tektoncd/pipeline/pkg/apis/resource/v1alpha1/cluster" tb "github.com/tektoncd/pipeline/test/builder" "github.com/tektoncd/pipeline/test/names" corev1 "k8s.io/api/core/v1" @@ -29,19 +31,19 @@ import ( func TestNewClusterResource(t *testing.T) { for _, c := range []struct { desc string - resource *v1alpha1.PipelineResource - want *v1alpha1.ClusterResource + resource *resourcev1alpha1.PipelineResource + want *cluster.Resource }{{ desc: "basic cluster resource", resource: tb.PipelineResource("test-cluster-resource", "default", tb.PipelineResourceSpec( - v1alpha1.PipelineResourceTypeCluster, + resourcev1alpha1.PipelineResourceTypeCluster, tb.PipelineResourceSpecParam("url", "http://10.10.10.10"), tb.PipelineResourceSpecParam("cadata", "bXktY2x1c3Rlci1jZXJ0Cg"), tb.PipelineResourceSpecParam("token", "my-token"), )), - want: &v1alpha1.ClusterResource{ + want: &cluster.Resource{ Name: "test-cluster-resource", - Type: v1alpha1.PipelineResourceTypeCluster, + Type: resourcev1alpha1.PipelineResourceTypeCluster, URL: "http://10.10.10.10", CAData: []byte("my-cluster-cert"), Token: "my-token", @@ -50,15 +52,15 @@ func TestNewClusterResource(t *testing.T) { }, { desc: "resource with password instead of token", resource: tb.PipelineResource("test-cluster-resource", "default", tb.PipelineResourceSpec( - v1alpha1.PipelineResourceTypeCluster, + resourcev1alpha1.PipelineResourceTypeCluster, tb.PipelineResourceSpecParam("url", "http://10.10.10.10"), tb.PipelineResourceSpecParam("cadata", "bXktY2x1c3Rlci1jZXJ0Cg"), tb.PipelineResourceSpecParam("username", "user"), tb.PipelineResourceSpecParam("password", "pass"), )), - want: &v1alpha1.ClusterResource{ + want: &cluster.Resource{ Name: "test-cluster-resource", - Type: v1alpha1.PipelineResourceTypeCluster, + Type: resourcev1alpha1.PipelineResourceTypeCluster, URL: "http://10.10.10.10", CAData: []byte("my-cluster-cert"), Username: "user", @@ -68,13 +70,13 @@ func TestNewClusterResource(t *testing.T) { }, { desc: "set insecure flag to true when there is no cert", resource: tb.PipelineResource("test-cluster-resource", "foo", tb.PipelineResourceSpec( - v1alpha1.PipelineResourceTypeCluster, + resourcev1alpha1.PipelineResourceTypeCluster, tb.PipelineResourceSpecParam("url", "http://10.10.10.10"), tb.PipelineResourceSpecParam("token", "my-token"), )), - want: &v1alpha1.ClusterResource{ + want: &cluster.Resource{ Name: "test-cluster-resource", - Type: v1alpha1.PipelineResourceTypeCluster, + Type: resourcev1alpha1.PipelineResourceTypeCluster, URL: "http://10.10.10.10", Token: "my-token", Insecure: true, @@ -83,15 +85,15 @@ func TestNewClusterResource(t *testing.T) { }, { desc: "basic cluster resource with namespace", resource: tb.PipelineResource("test-cluster-resource", "default", tb.PipelineResourceSpec( - v1alpha1.PipelineResourceTypeCluster, + resourcev1alpha1.PipelineResourceTypeCluster, tb.PipelineResourceSpecParam("url", "http://10.10.10.10"), tb.PipelineResourceSpecParam("cadata", "bXktY2x1c3Rlci1jZXJ0Cg"), tb.PipelineResourceSpecParam("token", "my-token"), tb.PipelineResourceSpecParam("namespace", "my-namespace"), )), - want: &v1alpha1.ClusterResource{ + want: &cluster.Resource{ Name: "test-cluster-resource", - Type: v1alpha1.PipelineResourceTypeCluster, + Type: resourcev1alpha1.PipelineResourceTypeCluster, URL: "http://10.10.10.10", CAData: []byte("my-cluster-cert"), Token: "my-token", @@ -101,16 +103,16 @@ func TestNewClusterResource(t *testing.T) { }, { desc: "basic resource with secrets", resource: tb.PipelineResource("test-cluster-resource", "default", tb.PipelineResourceSpec( - v1alpha1.PipelineResourceTypeCluster, + resourcev1alpha1.PipelineResourceTypeCluster, tb.PipelineResourceSpecParam("url", "http://10.10.10.10"), tb.PipelineResourceSpecSecretParam("cadata", "secret1", "cadatakey"), tb.PipelineResourceSpecSecretParam("token", "secret1", "tokenkey"), )), - want: &v1alpha1.ClusterResource{ + want: &cluster.Resource{ Name: "test-cluster-resource", - Type: v1alpha1.PipelineResourceTypeCluster, + Type: resourcev1alpha1.PipelineResourceTypeCluster, URL: "http://10.10.10.10", - Secrets: []v1alpha1.SecretParam{{ + Secrets: []resourcev1alpha1.SecretParam{{ FieldName: "cadata", SecretKey: "cadatakey", SecretName: "secret1", @@ -123,7 +125,7 @@ func TestNewClusterResource(t *testing.T) { }, }} { t.Run(c.desc, func(t *testing.T) { - got, err := v1alpha1.NewClusterResource("override-with-kubeconfig-writer:latest", c.resource) + got, err := cluster.NewResource("override-with-kubeconfig-writer:latest", c.resource) if err != nil { t.Errorf("Test: %q; TestNewClusterResource() error = %v", c.desc, err) } @@ -136,11 +138,11 @@ func TestNewClusterResource(t *testing.T) { func TestClusterResource_GetInputTaskModifier(t *testing.T) { names.TestingSeed() - clusterResource := &v1alpha1.ClusterResource{ + clusterResource := &cluster.Resource{ Name: "test-cluster-resource", - Type: v1alpha1.PipelineResourceTypeCluster, + Type: resourcev1alpha1.PipelineResourceTypeCluster, URL: "http://10.10.10.10", - Secrets: []v1alpha1.SecretParam{{ + Secrets: []resourcev1alpha1.SecretParam{{ FieldName: "cadata", SecretKey: "cadatakey", SecretName: "secret1", @@ -148,8 +150,8 @@ func TestClusterResource_GetInputTaskModifier(t *testing.T) { KubeconfigWriterImage: "override-with-kubeconfig-writer:latest", } - ts := v1alpha1.TaskSpec{} - wantSteps := []v1alpha1.Step{{Container: corev1.Container{ + ts := pipelinev1alpha1.TaskSpec{} + wantSteps := []pipelinev1alpha1.Step{{Container: corev1.Container{ Name: "kubeconfig-9l9zj", Image: "override-with-kubeconfig-writer:latest", Command: []string{"/ko-app/kubeconfigwriter"}, diff --git a/pkg/apis/pipeline/v1alpha1/git_resource.go b/pkg/apis/resource/v1alpha1/git/git_resource.go similarity index 72% rename from pkg/apis/pipeline/v1alpha1/git_resource.go rename to pkg/apis/resource/v1alpha1/git/git_resource.go index cb72283e947..79d61e07abc 100644 --- a/pkg/apis/pipeline/v1alpha1/git_resource.go +++ b/pkg/apis/resource/v1alpha1/git/git_resource.go @@ -1,5 +1,5 @@ /* -Copyright 2019 The Tekton Authors +Copyright 2019-2020 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. @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package v1alpha1 +package git import ( "fmt" @@ -22,6 +22,8 @@ import ( "strings" "github.com/tektoncd/pipeline/pkg/apis/pipeline" + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + resource "github.com/tektoncd/pipeline/pkg/apis/resource/v1alpha1" "github.com/tektoncd/pipeline/pkg/names" corev1 "k8s.io/api/core/v1" ) @@ -30,12 +32,12 @@ var ( gitSource = "git-source" ) -// GitResource is an endpoint from which to get data which is required +// Resource is an endpoint from which to get data which is required // by a Build/Task for context (e.g. a repo from which to build an image). -type GitResource struct { - Name string `json:"name"` - Type PipelineResourceType `json:"type"` - URL string `json:"url"` +type Resource struct { + Name string `json:"name"` + Type resource.PipelineResourceType `json:"type"` + URL string `json:"url"` // Git revision (branch, tag, commit SHA or ref) to clone. See // https://git-scm.com/docs/gitrevisions#_specifying_revisions for more // information. @@ -47,12 +49,12 @@ type GitResource struct { GitImage string `json:"-"` } -// NewGitResource creates a new git resource to pass to a Task -func NewGitResource(gitImage string, r *PipelineResource) (*GitResource, error) { - if r.Spec.Type != PipelineResourceTypeGit { - return nil, fmt.Errorf("GitResource: Cannot create a Git resource from a %s Pipeline Resource", r.Spec.Type) +// NewResource creates a new git resource to pass to a Task +func NewResource(gitImage string, r *resource.PipelineResource) (*Resource, error) { + if r.Spec.Type != resource.PipelineResourceTypeGit { + return nil, fmt.Errorf("git.Resource: Cannot create a Git resource from a %s Pipeline Resource", r.Spec.Type) } - gitResource := GitResource{ + gitResource := Resource{ Name: r.Name, Type: r.Spec.Type, GitImage: gitImage, @@ -101,22 +103,22 @@ func toUint(s string, d uint) uint { } // GetName returns the name of the resource -func (s GitResource) GetName() string { +func (s Resource) GetName() string { return s.Name } // GetType returns the type of the resource, in this case "Git" -func (s GitResource) GetType() PipelineResourceType { - return PipelineResourceTypeGit +func (s Resource) GetType() resource.PipelineResourceType { + return resource.PipelineResourceTypeGit } // GetURL returns the url to be used with this resource -func (s *GitResource) GetURL() string { +func (s *Resource) GetURL() string { return s.URL } // Replacements is used for template replacement on a GitResource inside of a Taskrun. -func (s *GitResource) Replacements() map[string]string { +func (s *Resource) Replacements() map[string]string { return map[string]string{ "name": s.Name, "type": string(s.Type), @@ -128,7 +130,7 @@ func (s *GitResource) Replacements() map[string]string { } // GetInputTaskModifier returns the TaskModifier to be used when this resource is an input. -func (s *GitResource) GetInputTaskModifier(_ *TaskSpec, path string) (TaskModifier, error) { +func (s *Resource) GetInputTaskModifier(_ *v1alpha1.TaskSpec, path string) (v1alpha1.TaskModifier, error) { args := []string{ "-url", s.URL, "-revision", s.Revision, @@ -145,7 +147,7 @@ func (s *GitResource) GetInputTaskModifier(_ *TaskSpec, path string) (TaskModifi args = append(args, "-sslVerify=false") } - step := Step{ + step := v1alpha1.Step{ Container: corev1.Container{ Name: names.SimpleNameGenerator.RestrictLengthWithRandomSuffix(gitSource + "-" + s.Name), Image: s.GitImage, @@ -160,12 +162,12 @@ func (s *GitResource) GetInputTaskModifier(_ *TaskSpec, path string) (TaskModifi }, } - return &InternalTaskModifier{ - StepsToPrepend: []Step{step}, + return &v1alpha1.InternalTaskModifier{ + StepsToPrepend: []v1alpha1.Step{step}, }, nil } // GetOutputTaskModifier returns a No-op TaskModifier. -func (s *GitResource) GetOutputTaskModifier(_ *TaskSpec, _ string) (TaskModifier, error) { - return &InternalTaskModifier{}, nil +func (s *Resource) GetOutputTaskModifier(_ *v1alpha1.TaskSpec, _ string) (v1alpha1.TaskModifier, error) { + return &v1alpha1.InternalTaskModifier{}, nil } diff --git a/pkg/apis/pipeline/v1alpha1/git_resource_test.go b/pkg/apis/resource/v1alpha1/git/git_resource_test.go similarity index 77% rename from pkg/apis/pipeline/v1alpha1/git_resource_test.go rename to pkg/apis/resource/v1alpha1/git/git_resource_test.go index 96c6c5769f2..5a7cad8cd19 100644 --- a/pkg/apis/pipeline/v1alpha1/git_resource_test.go +++ b/pkg/apis/resource/v1alpha1/git/git_resource_test.go @@ -1,5 +1,5 @@ /* -Copyright 2019 The Tekton Authors. +Copyright 2019-2020 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. @@ -14,20 +14,22 @@ See the License for the specific language governing permissions and limitations under the License. */ -package v1alpha1_test +package git_test import ( "testing" "github.com/google/go-cmp/cmp" - "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + pipelinev1alpha1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + resourcev1alpha1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + "github.com/tektoncd/pipeline/pkg/apis/resource/v1alpha1/git" tb "github.com/tektoncd/pipeline/test/builder" "github.com/tektoncd/pipeline/test/names" corev1 "k8s.io/api/core/v1" ) func TestNewGitResource_Invalid(t *testing.T) { - if _, err := v1alpha1.NewGitResource("override-with-git:latest", tb.PipelineResource("git-resource", "default", tb.PipelineResourceSpec(v1alpha1.PipelineResourceTypeGCS))); err == nil { + if _, err := git.NewResource("override-with-git:latest", tb.PipelineResource("git-resource", "default", tb.PipelineResourceSpec(resourcev1alpha1.PipelineResourceTypeGCS))); err == nil { t.Error("Expected error creating Git resource") } } @@ -35,19 +37,19 @@ func TestNewGitResource_Invalid(t *testing.T) { func TestNewGitResource_Valid(t *testing.T) { for _, tc := range []struct { desc string - pipelineResource *v1alpha1.PipelineResource - want *v1alpha1.GitResource + pipelineResource *resourcev1alpha1.PipelineResource + want *git.Resource }{{ desc: "With Revision", pipelineResource: tb.PipelineResource("git-resource", "default", - tb.PipelineResourceSpec(v1alpha1.PipelineResourceTypeGit, + tb.PipelineResourceSpec(resourcev1alpha1.PipelineResourceTypeGit, tb.PipelineResourceSpecParam("URL", "git@github.com:test/test.git"), tb.PipelineResourceSpecParam("Revision", "test"), ), ), - want: &v1alpha1.GitResource{ + want: &git.Resource{ Name: "git-resource", - Type: v1alpha1.PipelineResourceTypeGit, + Type: resourcev1alpha1.PipelineResourceTypeGit, URL: "git@github.com:test/test.git", Revision: "test", GitImage: "override-with-git:latest", @@ -58,13 +60,13 @@ func TestNewGitResource_Valid(t *testing.T) { }, { desc: "Without Revision", pipelineResource: tb.PipelineResource("git-resource", "default", - tb.PipelineResourceSpec(v1alpha1.PipelineResourceTypeGit, + tb.PipelineResourceSpec(resourcev1alpha1.PipelineResourceTypeGit, tb.PipelineResourceSpecParam("URL", "git@github.com:test/test.git"), ), ), - want: &v1alpha1.GitResource{ + want: &git.Resource{ Name: "git-resource", - Type: v1alpha1.PipelineResourceTypeGit, + Type: resourcev1alpha1.PipelineResourceTypeGit, URL: "git@github.com:test/test.git", Revision: "master", GitImage: "override-with-git:latest", @@ -75,14 +77,14 @@ func TestNewGitResource_Valid(t *testing.T) { }, { desc: "With Submodules", pipelineResource: tb.PipelineResource("git-resource", "default", - tb.PipelineResourceSpec(v1alpha1.PipelineResourceTypeGit, + tb.PipelineResourceSpec(resourcev1alpha1.PipelineResourceTypeGit, tb.PipelineResourceSpecParam("URL", "git@github.com:test/test.git"), tb.PipelineResourceSpecParam("Revision", "test"), ), ), - want: &v1alpha1.GitResource{ + want: &git.Resource{ Name: "git-resource", - Type: v1alpha1.PipelineResourceTypeGit, + Type: resourcev1alpha1.PipelineResourceTypeGit, URL: "git@github.com:test/test.git", Revision: "test", GitImage: "override-with-git:latest", @@ -93,15 +95,15 @@ func TestNewGitResource_Valid(t *testing.T) { }, { desc: "Without Submodules", pipelineResource: tb.PipelineResource("git-resource", "default", - tb.PipelineResourceSpec(v1alpha1.PipelineResourceTypeGit, + tb.PipelineResourceSpec(resourcev1alpha1.PipelineResourceTypeGit, tb.PipelineResourceSpecParam("URL", "git@github.com:test/test.git"), tb.PipelineResourceSpecParam("Revision", "test"), tb.PipelineResourceSpecParam("Submodules", "false"), ), ), - want: &v1alpha1.GitResource{ + want: &git.Resource{ Name: "git-resource", - Type: v1alpha1.PipelineResourceTypeGit, + Type: resourcev1alpha1.PipelineResourceTypeGit, URL: "git@github.com:test/test.git", Revision: "test", GitImage: "override-with-git:latest", @@ -112,15 +114,15 @@ func TestNewGitResource_Valid(t *testing.T) { }, { desc: "With positive depth", pipelineResource: tb.PipelineResource("git-resource", "default", - tb.PipelineResourceSpec(v1alpha1.PipelineResourceTypeGit, + tb.PipelineResourceSpec(resourcev1alpha1.PipelineResourceTypeGit, tb.PipelineResourceSpecParam("URL", "git@github.com:test/test.git"), tb.PipelineResourceSpecParam("Revision", "test"), tb.PipelineResourceSpecParam("Depth", "8"), ), ), - want: &v1alpha1.GitResource{ + want: &git.Resource{ Name: "git-resource", - Type: v1alpha1.PipelineResourceTypeGit, + Type: resourcev1alpha1.PipelineResourceTypeGit, URL: "git@github.com:test/test.git", Revision: "test", GitImage: "override-with-git:latest", @@ -131,15 +133,15 @@ func TestNewGitResource_Valid(t *testing.T) { }, { desc: "With zero depth", pipelineResource: tb.PipelineResource("git-resource", "default", - tb.PipelineResourceSpec(v1alpha1.PipelineResourceTypeGit, + tb.PipelineResourceSpec(resourcev1alpha1.PipelineResourceTypeGit, tb.PipelineResourceSpecParam("URL", "git@github.com:test/test.git"), tb.PipelineResourceSpecParam("Revision", "test"), tb.PipelineResourceSpecParam("Depth", "0"), ), ), - want: &v1alpha1.GitResource{ + want: &git.Resource{ Name: "git-resource", - Type: v1alpha1.PipelineResourceTypeGit, + Type: resourcev1alpha1.PipelineResourceTypeGit, URL: "git@github.com:test/test.git", Revision: "test", GitImage: "override-with-git:latest", @@ -150,16 +152,16 @@ func TestNewGitResource_Valid(t *testing.T) { }, { desc: "Without SSLVerify", pipelineResource: tb.PipelineResource("git-resource", "default", - tb.PipelineResourceSpec(v1alpha1.PipelineResourceTypeGit, + tb.PipelineResourceSpec(resourcev1alpha1.PipelineResourceTypeGit, tb.PipelineResourceSpecParam("URL", "git@github.com:test/test.git"), tb.PipelineResourceSpecParam("Revision", "test"), tb.PipelineResourceSpecParam("Depth", "0"), tb.PipelineResourceSpecParam("SSLVerify", "false"), ), ), - want: &v1alpha1.GitResource{ + want: &git.Resource{ Name: "git-resource", - Type: v1alpha1.PipelineResourceTypeGit, + Type: resourcev1alpha1.PipelineResourceTypeGit, URL: "git@github.com:test/test.git", Revision: "test", GitImage: "override-with-git:latest", @@ -169,7 +171,7 @@ func TestNewGitResource_Valid(t *testing.T) { }, }} { t.Run(tc.desc, func(t *testing.T) { - got, err := v1alpha1.NewGitResource("override-with-git:latest", tc.pipelineResource) + got, err := git.NewResource("override-with-git:latest", tc.pipelineResource) if err != nil { t.Fatalf("Unexpected error creating Git resource: %s", err) } @@ -182,9 +184,9 @@ func TestNewGitResource_Valid(t *testing.T) { } func TestGitResource_Replacements(t *testing.T) { - r := &v1alpha1.GitResource{ + r := &git.Resource{ Name: "git-resource", - Type: v1alpha1.PipelineResourceTypeGit, + Type: resourcev1alpha1.PipelineResourceTypeGit, URL: "git@github.com:test/test.git", Revision: "master", Depth: 16, @@ -193,7 +195,7 @@ func TestGitResource_Replacements(t *testing.T) { want := map[string]string{ "name": "git-resource", - "type": string(v1alpha1.PipelineResourceTypeGit), + "type": string(resourcev1alpha1.PipelineResourceTypeGit), "url": "git@github.com:test/test.git", "revision": "master", "depth": "16", @@ -212,13 +214,13 @@ func TestGitResource_GetDownloadTaskModifier(t *testing.T) { for _, tc := range []struct { desc string - gitResource *v1alpha1.GitResource + gitResource *git.Resource want corev1.Container }{{ desc: "With basic values", - gitResource: &v1alpha1.GitResource{ + gitResource: &git.Resource{ Name: "git-resource", - Type: v1alpha1.PipelineResourceTypeGit, + Type: resourcev1alpha1.PipelineResourceTypeGit, URL: "git@github.com:test/test.git", Revision: "master", GitImage: "override-with-git:latest", @@ -243,9 +245,9 @@ func TestGitResource_GetDownloadTaskModifier(t *testing.T) { }, }, { desc: "Without submodules", - gitResource: &v1alpha1.GitResource{ + gitResource: &git.Resource{ Name: "git-resource", - Type: v1alpha1.PipelineResourceTypeGit, + Type: resourcev1alpha1.PipelineResourceTypeGit, URL: "git@github.com:test/test.git", Revision: "master", GitImage: "override-with-git:latest", @@ -271,9 +273,9 @@ func TestGitResource_GetDownloadTaskModifier(t *testing.T) { }, }, { desc: "With more depth", - gitResource: &v1alpha1.GitResource{ + gitResource: &git.Resource{ Name: "git-resource", - Type: v1alpha1.PipelineResourceTypeGit, + Type: resourcev1alpha1.PipelineResourceTypeGit, URL: "git@github.com:test/test.git", Revision: "master", GitImage: "override-with-git:latest", @@ -300,9 +302,9 @@ func TestGitResource_GetDownloadTaskModifier(t *testing.T) { }, }, { desc: "Without sslVerify", - gitResource: &v1alpha1.GitResource{ + gitResource: &git.Resource{ Name: "git-resource", - Type: v1alpha1.PipelineResourceTypeGit, + Type: resourcev1alpha1.PipelineResourceTypeGit, URL: "git@github.com:test/test.git", Revision: "master", GitImage: "override-with-git:latest", @@ -329,13 +331,13 @@ func TestGitResource_GetDownloadTaskModifier(t *testing.T) { }, }} { t.Run(tc.desc, func(t *testing.T) { - ts := v1alpha1.TaskSpec{} + ts := pipelinev1alpha1.TaskSpec{} modifier, err := tc.gitResource.GetInputTaskModifier(&ts, "/test/test") if err != nil { t.Fatalf("Unexpected error getting GetDownloadTaskModifier: %s", err) } - if diff := cmp.Diff([]v1alpha1.Step{{Container: tc.want}}, modifier.GetStepsToPrepend()); diff != "" { + if diff := cmp.Diff([]pipelinev1alpha1.Step{{Container: tc.want}}, modifier.GetStepsToPrepend()); diff != "" { t.Errorf("Mismatch of GitResource DownloadContainerSpec: %s", diff) } }) diff --git a/pkg/apis/pipeline/v1alpha1/image_resource.go b/pkg/apis/resource/v1alpha1/image/image_resource.go similarity index 53% rename from pkg/apis/pipeline/v1alpha1/image_resource.go rename to pkg/apis/resource/v1alpha1/image/image_resource.go index 61ac2e76dcf..fe4a6db42ff 100644 --- a/pkg/apis/pipeline/v1alpha1/image_resource.go +++ b/pkg/apis/resource/v1alpha1/image/image_resource.go @@ -1,5 +1,5 @@ /* -Copyright 2019 The Tekton Authors +Copyright 2019-2020 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. @@ -14,22 +14,34 @@ See the License for the specific language governing permissions and limitations under the License. */ -package v1alpha1 +package image import ( "encoding/json" "fmt" "strings" + + pipelinev1alpha1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + resourcev1alpha1 "github.com/tektoncd/pipeline/pkg/apis/resource/v1alpha1" ) -// NewImageResource creates a new ImageResource from a PipelineResource. -func NewImageResource(r *PipelineResource) (*ImageResource, error) { - if r.Spec.Type != PipelineResourceTypeImage { +// Resource defines an endpoint where artifacts can be stored, such as images. +type Resource struct { + Name string `json:"name"` + Type resourcev1alpha1.PipelineResourceType `json:"type"` + URL string `json:"url"` + Digest string `json:"digest"` + OutputImageDir string +} + +// NewResource creates a new ImageResource from a PipelineResourcev1alpha1. +func NewResource(r *resourcev1alpha1.PipelineResource) (*Resource, error) { + if r.Spec.Type != resourcev1alpha1.PipelineResourceTypeImage { return nil, fmt.Errorf("ImageResource: Cannot create an Image resource from a %s Pipeline Resource", r.Spec.Type) } - ir := &ImageResource{ + ir := &Resource{ Name: r.Name, - Type: PipelineResourceTypeImage, + Type: resourcev1alpha1.PipelineResourceTypeImage, } for _, param := range r.Spec.Params { @@ -44,27 +56,18 @@ func NewImageResource(r *PipelineResource) (*ImageResource, error) { return ir, nil } -// ImageResource defines an endpoint where artifacts can be stored, such as images. -type ImageResource struct { - Name string `json:"name"` - Type PipelineResourceType `json:"type"` - URL string `json:"url"` - Digest string `json:"digest"` - OutputImageDir string -} - // GetName returns the name of the resource -func (s ImageResource) GetName() string { +func (s Resource) GetName() string { return s.Name } // GetType returns the type of the resource, in this case "image" -func (s ImageResource) GetType() PipelineResourceType { - return PipelineResourceTypeImage +func (s Resource) GetType() resourcev1alpha1.PipelineResourceType { + return resourcev1alpha1.PipelineResourceTypeImage } // Replacements is used for template replacement on an ImageResource inside of a Taskrun. -func (s *ImageResource) Replacements() map[string]string { +func (s *Resource) Replacements() map[string]string { return map[string]string{ "name": s.Name, "type": string(s.Type), @@ -74,16 +77,16 @@ func (s *ImageResource) Replacements() map[string]string { } // GetInputTaskModifier returns the TaskModifier to be used when this resource is an input. -func (s *ImageResource) GetInputTaskModifier(_ *TaskSpec, _ string) (TaskModifier, error) { - return &InternalTaskModifier{}, nil +func (s *Resource) GetInputTaskModifier(_ *pipelinev1alpha1.TaskSpec, _ string) (pipelinev1alpha1.TaskModifier, error) { + return &pipelinev1alpha1.InternalTaskModifier{}, nil } // GetOutputTaskModifier returns a No-op TaskModifier. -func (s *ImageResource) GetOutputTaskModifier(_ *TaskSpec, _ string) (TaskModifier, error) { - return &InternalTaskModifier{}, nil +func (s *Resource) GetOutputTaskModifier(_ *pipelinev1alpha1.TaskSpec, _ string) (pipelinev1alpha1.TaskModifier, error) { + return &pipelinev1alpha1.InternalTaskModifier{}, nil } -func (s ImageResource) String() string { +func (s Resource) String() string { // the String() func implements the Stringer interface, and therefore // cannot return an error // if the Marshal func gives an error, the returned string will be empty diff --git a/pkg/apis/pipeline/v1alpha1/image_resource_test.go b/pkg/apis/resource/v1alpha1/image/image_resource_test.go similarity index 87% rename from pkg/apis/pipeline/v1alpha1/image_resource_test.go rename to pkg/apis/resource/v1alpha1/image/image_resource_test.go index 3611e922ebc..c7b43978449 100644 --- a/pkg/apis/pipeline/v1alpha1/image_resource_test.go +++ b/pkg/apis/resource/v1alpha1/image/image_resource_test.go @@ -1,5 +1,5 @@ /* -Copyright 2019 The Tekton Authors. +Copyright 2019-2020 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. @@ -14,28 +14,29 @@ See the License for the specific language governing permissions and limitations under the License. */ -package v1alpha1_test +package image_test import ( "testing" "github.com/google/go-cmp/cmp" - "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + "github.com/tektoncd/pipeline/pkg/apis/resource/v1alpha1" + "github.com/tektoncd/pipeline/pkg/apis/resource/v1alpha1/image" tb "github.com/tektoncd/pipeline/test/builder" ) func TestNewImageResource_Invalid(t *testing.T) { r := tb.PipelineResource("git-resource", "default", tb.PipelineResourceSpec(v1alpha1.PipelineResourceTypeGit)) - _, err := v1alpha1.NewImageResource(r) + _, err := image.NewResource(r) if err == nil { t.Error("Expected error creating Image resource") } } func TestNewImageResource_Valid(t *testing.T) { - want := &v1alpha1.ImageResource{ + want := &image.Resource{ Name: "image-resource", Type: v1alpha1.PipelineResourceTypeImage, URL: "https://test.com/test/test", @@ -52,7 +53,7 @@ func TestNewImageResource_Valid(t *testing.T) { ), ) - got, err := v1alpha1.NewImageResource(r) + got, err := image.NewResource(r) if err != nil { t.Fatalf("Unexpected error creating Image resource: %s", err) } @@ -63,7 +64,7 @@ func TestNewImageResource_Valid(t *testing.T) { } func TestImageResource_Replacements(t *testing.T) { - ir := &v1alpha1.ImageResource{ + ir := &image.Resource{ Name: "image-resource", Type: v1alpha1.PipelineResourceTypeImage, URL: "https://test.com/test/test", diff --git a/pkg/apis/pipeline/v1alpha1/pull_request_resource.go b/pkg/apis/resource/v1alpha1/pullrequest/pull_request_resource.go similarity index 73% rename from pkg/apis/pipeline/v1alpha1/pull_request_resource.go rename to pkg/apis/resource/v1alpha1/pullrequest/pull_request_resource.go index bf0025809ab..4691778801c 100644 --- a/pkg/apis/pipeline/v1alpha1/pull_request_resource.go +++ b/pkg/apis/resource/v1alpha1/pullrequest/pull_request_resource.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package v1alpha1 +package pullrequest import ( "fmt" @@ -22,6 +22,8 @@ import ( "strings" "github.com/tektoncd/pipeline/pkg/apis/pipeline" + pipelinev1alpha1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + resourcev1alpha1 "github.com/tektoncd/pipeline/pkg/apis/resource/v1alpha1" "github.com/tektoncd/pipeline/pkg/names" corev1 "k8s.io/api/core/v1" ) @@ -33,11 +35,11 @@ const ( authTokenEnv = "AUTH_TOKEN" ) -// PullRequestResource is an endpoint from which to get data which is required +// Resource is an endpoint from which to get data which is required // by a Build/Task for context. -type PullRequestResource struct { - Name string `json:"name"` - Type PipelineResourceType `json:"type"` +type Resource struct { + Name string `json:"name"` + Type resourcev1alpha1.PipelineResourceType `json:"type"` // URL pointing to the pull request. // Example: https://github.com/owner/repo/pulls/1 @@ -45,18 +47,18 @@ type PullRequestResource struct { // SCM provider (github or gitlab today). This will be guessed from URL if not set. Provider string `json:"provider"` // Secrets holds a struct to indicate a field name and corresponding secret name to populate it. - Secrets []SecretParam `json:"secrets"` + Secrets []resourcev1alpha1.SecretParam `json:"secrets"` PRImage string `json:"-"` InsecureSkipTLSVerify bool `json:"insecure-skip-tls-verify"` } -// NewPullRequestResource create a new git resource to pass to a Task -func NewPullRequestResource(prImage string, r *PipelineResource) (*PullRequestResource, error) { - if r.Spec.Type != PipelineResourceTypePullRequest { +// NewResource create a new git resource to pass to a Task +func NewResource(prImage string, r *resourcev1alpha1.PipelineResource) (*Resource, error) { + if r.Spec.Type != resourcev1alpha1.PipelineResourceTypePullRequest { return nil, fmt.Errorf("cannot create a PR resource from a %s Pipeline Resource", r.Spec.Type) } - prResource := PullRequestResource{ + prResource := Resource{ Name: r.Name, Type: r.Spec.Type, Secrets: r.Spec.SecretParams, @@ -82,22 +84,22 @@ func NewPullRequestResource(prImage string, r *PipelineResource) (*PullRequestRe } // GetName returns the name of the resource -func (s PullRequestResource) GetName() string { +func (s Resource) GetName() string { return s.Name } // GetType returns the type of the resource, in this case "Git" -func (s PullRequestResource) GetType() PipelineResourceType { - return PipelineResourceTypePullRequest +func (s Resource) GetType() resourcev1alpha1.PipelineResourceType { + return resourcev1alpha1.PipelineResourceTypePullRequest } // GetURL returns the url to be used with this resource -func (s *PullRequestResource) GetURL() string { +func (s *Resource) GetURL() string { return s.URL } // Replacements is used for template replacement on a PullRequestResource inside of a Taskrun. -func (s *PullRequestResource) Replacements() map[string]string { +func (s *Resource) Replacements() map[string]string { return map[string]string{ "name": s.Name, "type": string(s.Type), @@ -108,20 +110,20 @@ func (s *PullRequestResource) Replacements() map[string]string { } // GetInputTaskModifier returns the TaskModifier to be used when this resource is an input. -func (s *PullRequestResource) GetInputTaskModifier(ts *TaskSpec, sourcePath string) (TaskModifier, error) { - return &InternalTaskModifier{ +func (s *Resource) GetInputTaskModifier(ts *pipelinev1alpha1.TaskSpec, sourcePath string) (pipelinev1alpha1.TaskModifier, error) { + return &pipelinev1alpha1.InternalTaskModifier{ StepsToPrepend: s.getSteps("download", sourcePath), }, nil } // GetOutputTaskModifier returns a No-op TaskModifier. -func (s *PullRequestResource) GetOutputTaskModifier(ts *TaskSpec, sourcePath string) (TaskModifier, error) { - return &InternalTaskModifier{ +func (s *Resource) GetOutputTaskModifier(ts *pipelinev1alpha1.TaskSpec, sourcePath string) (pipelinev1alpha1.TaskModifier, error) { + return &pipelinev1alpha1.InternalTaskModifier{ StepsToAppend: s.getSteps("upload", sourcePath), }, nil } -func (s *PullRequestResource) getSteps(mode string, sourcePath string) []Step { +func (s *Resource) getSteps(mode string, sourcePath string) []pipelinev1alpha1.Step { args := []string{"-url", s.URL, "-path", sourcePath, "-mode", mode} if s.Provider != "" { args = append(args, []string{"-provider", s.Provider}...) @@ -148,7 +150,7 @@ func (s *PullRequestResource) getSteps(mode string, sourcePath string) []Step { } } - return []Step{{Container: corev1.Container{ + return []pipelinev1alpha1.Step{{Container: corev1.Container{ Name: names.SimpleNameGenerator.RestrictLengthWithRandomSuffix(prSource + "-" + s.Name), Image: s.PRImage, Command: []string{"/ko-app/pullrequest-init"}, diff --git a/pkg/apis/pipeline/v1alpha1/pull_request_resource_test.go b/pkg/apis/resource/v1alpha1/pullrequest/pull_request_resource_test.go similarity index 80% rename from pkg/apis/pipeline/v1alpha1/pull_request_resource_test.go rename to pkg/apis/resource/v1alpha1/pullrequest/pull_request_resource_test.go index a2dee9e62bd..18f10a36ce2 100644 --- a/pkg/apis/pipeline/v1alpha1/pull_request_resource_test.go +++ b/pkg/apis/resource/v1alpha1/pullrequest/pull_request_resource_test.go @@ -14,14 +14,16 @@ See the License for the specific language governing permissions and limitations under the License. */ -package v1alpha1_test +package pullrequest_test import ( "testing" "github.com/google/go-cmp/cmp" "github.com/tektoncd/pipeline/pkg/apis/pipeline" - "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + pipelinev1alpha1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + resourcev1alpha1 "github.com/tektoncd/pipeline/pkg/apis/resource/v1alpha1" + "github.com/tektoncd/pipeline/pkg/apis/resource/v1alpha1/pullrequest" tb "github.com/tektoncd/pipeline/test/builder" "github.com/tektoncd/pipeline/test/names" corev1 "k8s.io/api/core/v1" @@ -30,19 +32,19 @@ import ( func TestPullRequest_NewResource(t *testing.T) { url := "https://github.com/tektoncd/pipeline/pulls/1" pr := tb.PipelineResource("foo", "default", tb.PipelineResourceSpec( - v1alpha1.PipelineResourceTypePullRequest, + resourcev1alpha1.PipelineResourceTypePullRequest, tb.PipelineResourceSpecParam("url", url), tb.PipelineResourceSpecParam("provider", "github"), tb.PipelineResourceSpecSecretParam("authToken", "test-secret-key", "test-secret-name"), )) - got, err := v1alpha1.NewPullRequestResource("override-with-pr:latest", pr) + got, err := pullrequest.NewResource("override-with-pr:latest", pr) if err != nil { t.Fatalf("Error creating storage resource: %s", err.Error()) } - want := &v1alpha1.PullRequestResource{ + want := &pullrequest.Resource{ Name: pr.Name, - Type: v1alpha1.PipelineResourceTypePullRequest, + Type: resourcev1alpha1.PipelineResourceTypePullRequest, URL: url, Provider: "github", Secrets: pr.Spec.SecretParams, @@ -55,28 +57,28 @@ func TestPullRequest_NewResource(t *testing.T) { } func TestPullRequest_NewResource_error(t *testing.T) { - pr := tb.PipelineResource("foo", "default", tb.PipelineResourceSpec(v1alpha1.PipelineResourceTypeGit)) - if _, err := v1alpha1.NewPullRequestResource("override-with-pr:latest", pr); err == nil { + pr := tb.PipelineResource("foo", "default", tb.PipelineResourceSpec(resourcev1alpha1.PipelineResourceTypeGit)) + if _, err := pullrequest.NewResource("override-with-pr:latest", pr); err == nil { t.Error("NewPullRequestResource() want error, got nil") } } type testcase struct { - in *v1alpha1.PullRequestResource - out []v1alpha1.Step + in *pullrequest.Resource + out []pipelinev1alpha1.Step } const workspace = "/workspace" func containerTestCases(mode string) []testcase { return []testcase{{ - in: &v1alpha1.PullRequestResource{ + in: &pullrequest.Resource{ Name: "nocreds", URL: "https://example.com", PRImage: "override-with-pr:latest", InsecureSkipTLSVerify: false, }, - out: []v1alpha1.Step{{Container: corev1.Container{ + out: []pipelinev1alpha1.Step{{Container: corev1.Container{ Name: "pr-source-nocreds-9l9zj", Image: "override-with-pr:latest", WorkingDir: pipeline.WorkspaceDir, @@ -85,11 +87,11 @@ func containerTestCases(mode string) []testcase { Env: []corev1.EnvVar{}, }}}, }, { - in: &v1alpha1.PullRequestResource{ + in: &pullrequest.Resource{ Name: "creds", URL: "https://example.com", InsecureSkipTLSVerify: false, - Secrets: []v1alpha1.SecretParam{{ + Secrets: []resourcev1alpha1.SecretParam{{ FieldName: "authToken", SecretName: "github-creds", SecretKey: "token", @@ -97,7 +99,7 @@ func containerTestCases(mode string) []testcase { PRImage: "override-with-pr:latest", Provider: "github", }, - out: []v1alpha1.Step{{Container: corev1.Container{ + out: []pipelinev1alpha1.Step{{Container: corev1.Container{ Name: "pr-source-creds-mz4c7", Image: "override-with-pr:latest", WorkingDir: pipeline.WorkspaceDir, @@ -116,13 +118,13 @@ func containerTestCases(mode string) []testcase { }}, }}}, }, { - in: &v1alpha1.PullRequestResource{ + in: &pullrequest.Resource{ Name: "nocreds", URL: "https://example.com", PRImage: "override-with-pr:latest", InsecureSkipTLSVerify: true, }, - out: []v1alpha1.Step{{Container: corev1.Container{ + out: []pipelinev1alpha1.Step{{Container: corev1.Container{ Name: "pr-source-nocreds-mssqb", Image: "override-with-pr:latest", WorkingDir: pipeline.WorkspaceDir, @@ -138,7 +140,7 @@ func TestPullRequest_GetDownloadSteps(t *testing.T) { for _, tc := range containerTestCases("download") { t.Run(tc.in.GetName(), func(t *testing.T) { - ts := v1alpha1.TaskSpec{} + ts := pipelinev1alpha1.TaskSpec{} got, err := tc.in.GetInputTaskModifier(&ts, workspace) if err != nil { t.Fatal(err) @@ -155,7 +157,7 @@ func TestPullRequest_GetOutputSteps(t *testing.T) { for _, tc := range containerTestCases("upload") { t.Run(tc.in.GetName(), func(t *testing.T) { - ts := v1alpha1.TaskSpec{} + ts := pipelinev1alpha1.TaskSpec{} got, err := tc.in.GetOutputTaskModifier(&ts, workspace) if err != nil { t.Fatal(err) diff --git a/pkg/apis/pipeline/v1alpha1/artifact_bucket.go b/pkg/apis/resource/v1alpha1/storage/artifact_bucket.go similarity index 86% rename from pkg/apis/pipeline/v1alpha1/artifact_bucket.go rename to pkg/apis/resource/v1alpha1/storage/artifact_bucket.go index 5fb89fab629..ef3b2bd36f0 100644 --- a/pkg/apis/pipeline/v1alpha1/artifact_bucket.go +++ b/pkg/apis/resource/v1alpha1/storage/artifact_bucket.go @@ -1,5 +1,5 @@ /* -Copyright 2019 The Tekton Authors +Copyright 2019-2020 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. @@ -14,12 +14,14 @@ See the License for the specific language governing permissions and limitations under the License. */ -package v1alpha1 +package storage import ( "fmt" "github.com/tektoncd/pipeline/pkg/apis/pipeline" + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + resource "github.com/tektoncd/pipeline/pkg/apis/resource/v1alpha1" "github.com/tektoncd/pipeline/pkg/names" corev1 "k8s.io/api/core/v1" ) @@ -31,10 +33,11 @@ const secretVolumeMountPath = "/var/bucketsecret" // ArtifactBucket contains the Storage bucket configuration defined in the // Bucket config map. +// +k8s:deepcopy-gen=true type ArtifactBucket struct { Name string Location string - Secrets []SecretParam + Secrets []resource.SecretParam ShellImage string GsutilImage string @@ -46,15 +49,15 @@ func (b *ArtifactBucket) GetType() string { } // StorageBasePath returns the path to be used to store artifacts in a pipelinerun temporary storage -func (b *ArtifactBucket) StorageBasePath(pr *PipelineRun) string { +func (b *ArtifactBucket) StorageBasePath(pr *v1alpha1.PipelineRun) string { return fmt.Sprintf("%s-%s-bucket", pr.Name, pr.Namespace) } // GetCopyFromStorageToSteps returns a container used to download artifacts from temporary storage -func (b *ArtifactBucket) GetCopyFromStorageToSteps(name, sourcePath, destinationPath string) []Step { +func (b *ArtifactBucket) GetCopyFromStorageToSteps(name, sourcePath, destinationPath string) []v1alpha1.Step { envVars, secretVolumeMount := getSecretEnvVarsAndVolumeMounts("bucket", secretVolumeMountPath, b.Secrets) - return []Step{{Container: corev1.Container{ + return []v1alpha1.Step{{Container: corev1.Container{ Name: names.SimpleNameGenerator.RestrictLengthWithRandomSuffix(fmt.Sprintf("artifact-dest-mkdir-%s", name)), Image: b.ShellImage, Command: []string{"mkdir", "-p", destinationPath}, @@ -69,10 +72,10 @@ func (b *ArtifactBucket) GetCopyFromStorageToSteps(name, sourcePath, destination } // GetCopyToStorageFromSteps returns a container used to upload artifacts for temporary storage -func (b *ArtifactBucket) GetCopyToStorageFromSteps(name, sourcePath, destinationPath string) []Step { +func (b *ArtifactBucket) GetCopyToStorageFromSteps(name, sourcePath, destinationPath string) []v1alpha1.Step { envVars, secretVolumeMount := getSecretEnvVarsAndVolumeMounts("bucket", secretVolumeMountPath, b.Secrets) - return []Step{{Container: corev1.Container{ + return []v1alpha1.Step{{Container: corev1.Container{ Name: names.SimpleNameGenerator.RestrictLengthWithRandomSuffix(fmt.Sprintf("artifact-copy-to-%s", name)), Image: b.GsutilImage, Command: []string{"gsutil"}, diff --git a/pkg/apis/pipeline/v1alpha1/artifact_bucket_test.go b/pkg/apis/resource/v1alpha1/storage/artifact_bucket_test.go similarity index 96% rename from pkg/apis/pipeline/v1alpha1/artifact_bucket_test.go rename to pkg/apis/resource/v1alpha1/storage/artifact_bucket_test.go index e248206ebe2..3c1a836225c 100644 --- a/pkg/apis/pipeline/v1alpha1/artifact_bucket_test.go +++ b/pkg/apis/resource/v1alpha1/storage/artifact_bucket_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package v1alpha1_test +package storage_test import ( "fmt" @@ -22,6 +22,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + "github.com/tektoncd/pipeline/pkg/apis/resource/v1alpha1/storage" "github.com/tektoncd/pipeline/test/names" corev1 "k8s.io/api/core/v1" ) @@ -33,7 +34,7 @@ const ( var ( expectedVolumeName = fmt.Sprintf("volume-bucket-%s", secretName) - bucket = v1alpha1.ArtifactBucket{ + bucket = storage.ArtifactBucket{ Location: "gs://fake-bucket", Secrets: []v1alpha1.SecretParam{{ FieldName: "GOOGLE_APPLICATION_CREDENTIALS", diff --git a/pkg/apis/pipeline/v1alpha1/artifact_pvc.go b/pkg/apis/resource/v1alpha1/storage/artifact_pvc.go similarity index 76% rename from pkg/apis/pipeline/v1alpha1/artifact_pvc.go rename to pkg/apis/resource/v1alpha1/storage/artifact_pvc.go index d73e26369ba..ca6ee3e6e70 100644 --- a/pkg/apis/pipeline/v1alpha1/artifact_pvc.go +++ b/pkg/apis/resource/v1alpha1/storage/artifact_pvc.go @@ -1,5 +1,5 @@ /* -Copyright 2019 The Tekton Authors +Copyright 2019-2020 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. @@ -14,13 +14,12 @@ See the License for the specific language governing permissions and limitations under the License. */ -package v1alpha1 +package storage import ( "fmt" - "strings" - "github.com/tektoncd/pipeline/pkg/apis/pipeline" + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" "github.com/tektoncd/pipeline/pkg/names" corev1 "k8s.io/api/core/v1" ) @@ -30,6 +29,7 @@ var ( ) // ArtifactPVC represents the pvc created by the pipelinerun for artifacts temporary storage. +// +k8s:deepcopy-gen=true type ArtifactPVC struct { Name string PersistentVolumeClaim *corev1.PersistentVolumeClaim @@ -39,17 +39,17 @@ type ArtifactPVC struct { // GetType returns the type of the artifact storage. func (p *ArtifactPVC) GetType() string { - return pipeline.ArtifactStoragePVCType + return ArtifactStoragePVCType } // StorageBasePath returns the path to be used to store artifacts in a pipelinerun temporary storage. -func (p *ArtifactPVC) StorageBasePath(pr *PipelineRun) string { +func (p *ArtifactPVC) StorageBasePath(pr *v1alpha1.PipelineRun) string { return pvcDir } // GetCopyFromStorageToSteps returns a container used to download artifacts from temporary storage. -func (p *ArtifactPVC) GetCopyFromStorageToSteps(name, sourcePath, destinationPath string) []Step { - return []Step{{Container: corev1.Container{ +func (p *ArtifactPVC) GetCopyFromStorageToSteps(name, sourcePath, destinationPath string) []v1alpha1.Step { + return []v1alpha1.Step{{Container: corev1.Container{ Name: names.SimpleNameGenerator.RestrictLengthWithRandomSuffix(fmt.Sprintf("source-copy-%s", name)), Image: p.ShellImage, Command: []string{"cp", "-r", fmt.Sprintf("%s/.", sourcePath), destinationPath}, @@ -57,8 +57,8 @@ func (p *ArtifactPVC) GetCopyFromStorageToSteps(name, sourcePath, destinationPat } // GetCopyToStorageFromSteps returns a container used to upload artifacts for temporary storage. -func (p *ArtifactPVC) GetCopyToStorageFromSteps(name, sourcePath, destinationPath string) []Step { - return []Step{{Container: corev1.Container{ +func (p *ArtifactPVC) GetCopyToStorageFromSteps(name, sourcePath, destinationPath string) []v1alpha1.Step { + return []v1alpha1.Step{{Container: corev1.Container{ Name: names.SimpleNameGenerator.RestrictLengthWithRandomSuffix(fmt.Sprintf("source-mkdir-%s", name)), Image: p.ShellImage, Command: []string{"mkdir", "-p", destinationPath}, @@ -79,16 +79,6 @@ func GetPvcMount(name string) corev1.VolumeMount { } } -// CreateDirStep returns a container step to create a dir at destinationPath. The name -// of the step will include name. -func CreateDirStep(shellImage string, name, destinationPath string) Step { - return Step{Container: corev1.Container{ - Name: names.SimpleNameGenerator.RestrictLengthWithRandomSuffix(fmt.Sprintf("create-dir-%s", strings.ToLower(name))), - Image: shellImage, - Command: []string{"mkdir", "-p", destinationPath}, - }} -} - // GetSecretsVolumes returns the list of volumes for secrets to be mounted on // pod. func (p *ArtifactPVC) GetSecretsVolumes() []corev1.Volume { return nil } diff --git a/pkg/apis/pipeline/v1alpha1/artifact_pvc_test.go b/pkg/apis/resource/v1alpha1/storage/artifact_pvc_test.go similarity index 90% rename from pkg/apis/pipeline/v1alpha1/artifact_pvc_test.go rename to pkg/apis/resource/v1alpha1/storage/artifact_pvc_test.go index 964a95bc43a..ba2c0f652f9 100644 --- a/pkg/apis/pipeline/v1alpha1/artifact_pvc_test.go +++ b/pkg/apis/resource/v1alpha1/storage/artifact_pvc_test.go @@ -1,5 +1,5 @@ /* -Copyright 2019 The Tekton Authors +Copyright 2019-2020 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. @@ -14,13 +14,14 @@ See the License for the specific language governing permissions and limitations under the License. */ -package v1alpha1_test +package storage_test import ( "testing" "github.com/google/go-cmp/cmp" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + "github.com/tektoncd/pipeline/pkg/apis/resource/v1alpha1/storage" "github.com/tektoncd/pipeline/test/names" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -29,7 +30,7 @@ import ( func TestPVCGetCopyFromContainerSpec(t *testing.T) { names.TestingSeed() - pvc := v1alpha1.ArtifactPVC{ + pvc := storage.ArtifactPVC{ Name: "pipelinerun-pvc", ShellImage: "busybox", } @@ -49,7 +50,7 @@ func TestPVCGetCopyFromContainerSpec(t *testing.T) { func TestPVCGetCopyToContainerSpec(t *testing.T) { names.TestingSeed() - pvc := v1alpha1.ArtifactPVC{ + pvc := storage.ArtifactPVC{ Name: "pipelinerun-pvc", ShellImage: "busybox", } @@ -80,7 +81,7 @@ func TestPVCGetPvcMount(t *testing.T) { Name: name, MountPath: pvcDir, } - got := v1alpha1.GetPvcMount(name) + got := storage.GetPvcMount(name) if d := cmp.Diff(got, want); d != "" { t.Errorf("Diff:\n%s", d) } @@ -94,14 +95,14 @@ func TestPVCGetMakeStep(t *testing.T) { Image: "busybox", Command: []string{"mkdir", "-p", "/workspace/destination"}, }} - got := v1alpha1.CreateDirStep("busybox", "workspace", "/workspace/destination") + got := storage.CreateDirStep("busybox", "workspace", "/workspace/destination") if d := cmp.Diff(got, want); d != "" { t.Errorf("Diff:\n%s", d) } } func TestStorageBasePath(t *testing.T) { - pvc := v1alpha1.ArtifactPVC{ + pvc := storage.ArtifactPVC{ Name: "pipelinerun-pvc", } pipelinerun := &v1alpha1.PipelineRun{ diff --git a/pkg/apis/pipeline/v1alpha1/build_gcs_resource.go b/pkg/apis/resource/v1alpha1/storage/build_gcs.go similarity index 83% rename from pkg/apis/pipeline/v1alpha1/build_gcs_resource.go rename to pkg/apis/resource/v1alpha1/storage/build_gcs.go index cf42eb0f0c4..98d0bf1306b 100644 --- a/pkg/apis/pipeline/v1alpha1/build_gcs_resource.go +++ b/pkg/apis/resource/v1alpha1/storage/build_gcs.go @@ -1,5 +1,5 @@ /* -Copyright 2019 The Tekton Authors +Copyright 2019-2020 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. @@ -14,13 +14,15 @@ See the License for the specific language governing permissions and limitations under the License. */ -package v1alpha1 +package storage import ( "fmt" "strings" "github.com/tektoncd/pipeline/pkg/apis/pipeline" + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + resource "github.com/tektoncd/pipeline/pkg/apis/resource/v1alpha1" "github.com/tektoncd/pipeline/pkg/names" corev1 "k8s.io/api/core/v1" ) @@ -60,7 +62,7 @@ var validArtifactTypes = []GCSArtifactType{ // BuildGCSResource does incremental uploads for files in directory. type BuildGCSResource struct { Name string - Type PipelineResourceType + Type resource.PipelineResourceType Location string ArtifactType GCSArtifactType @@ -69,8 +71,8 @@ type BuildGCSResource struct { } // NewBuildGCSResource creates a new BuildGCS resource to pass to a Task. -func NewBuildGCSResource(images pipeline.Images, r *PipelineResource) (*BuildGCSResource, error) { - if r.Spec.Type != PipelineResourceTypeStorage { +func NewBuildGCSResource(images pipeline.Images, r *resource.PipelineResource) (*BuildGCSResource, error) { + if r.Spec.Type != resource.PipelineResourceTypeStorage { return nil, fmt.Errorf("BuildGCSResource: Cannot create a BuildGCS resource from a %s Pipeline Resource", r.Spec.Type) } if r.Spec.SecretParams != nil { @@ -110,10 +112,12 @@ func NewBuildGCSResource(images pipeline.Images, r *PipelineResource) (*BuildGCS func (s BuildGCSResource) GetName() string { return s.Name } // GetType returns the type of the resource, in this case "storage". -func (s BuildGCSResource) GetType() PipelineResourceType { return PipelineResourceTypeStorage } +func (s BuildGCSResource) GetType() resource.PipelineResourceType { + return resource.PipelineResourceTypeStorage +} // GetSecretParams returns nil because it takes no secret params. -func (s *BuildGCSResource) GetSecretParams() []SecretParam { return nil } +func (s *BuildGCSResource) GetSecretParams() []resource.SecretParam { return nil } // Replacements returns the set of available replacements for this resource. func (s *BuildGCSResource) Replacements() map[string]string { @@ -125,14 +129,14 @@ func (s *BuildGCSResource) Replacements() map[string]string { } // GetInputTaskModifier returns a TaskModifier that prepends a step to a Task to fetch the archive or manifest. -func (s *BuildGCSResource) GetInputTaskModifier(ts *TaskSpec, sourcePath string) (TaskModifier, error) { +func (s *BuildGCSResource) GetInputTaskModifier(ts *v1alpha1.TaskSpec, sourcePath string) (v1alpha1.TaskModifier, error) { args := []string{"--type", string(s.ArtifactType), "--location", s.Location} // dest_dir is the destination directory for GCS files to be copies" if sourcePath != "" { args = append(args, "--dest_dir", sourcePath) } - steps := []Step{ + steps := []v1alpha1.Step{ CreateDirStep(s.ShellImage, s.Name, sourcePath), {Container: corev1.Container{ Name: names.SimpleNameGenerator.RestrictLengthWithRandomSuffix(fmt.Sprintf("storage-fetch-%s", s.Name)), @@ -143,15 +147,15 @@ func (s *BuildGCSResource) GetInputTaskModifier(ts *TaskSpec, sourcePath string) volumes := getStorageVolumeSpec(s, *ts) - return &InternalTaskModifier{ + return &v1alpha1.InternalTaskModifier{ StepsToPrepend: steps, Volumes: volumes, }, nil } // GetOutputTaskModifier returns a No-op TaskModifier. -func (s *BuildGCSResource) GetOutputTaskModifier(ts *TaskSpec, sourcePath string) (TaskModifier, error) { - return &InternalTaskModifier{}, nil +func (s *BuildGCSResource) GetOutputTaskModifier(ts *v1alpha1.TaskSpec, sourcePath string) (v1alpha1.TaskModifier, error) { + return &v1alpha1.InternalTaskModifier{}, nil } func getArtifactType(val string) (GCSArtifactType, error) { diff --git a/pkg/apis/pipeline/v1alpha1/build_gcs_resource_test.go b/pkg/apis/resource/v1alpha1/storage/build_gcs_test.go similarity index 92% rename from pkg/apis/pipeline/v1alpha1/build_gcs_resource_test.go rename to pkg/apis/resource/v1alpha1/storage/build_gcs_test.go index 2c1815bd2e6..0c0c5fdb595 100644 --- a/pkg/apis/pipeline/v1alpha1/build_gcs_resource_test.go +++ b/pkg/apis/resource/v1alpha1/storage/build_gcs_test.go @@ -1,5 +1,5 @@ /* -Copyright 2019 The Tekton Authors +Copyright 2019-2020 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. @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package v1alpha1_test +package storage_test import ( "testing" @@ -22,6 +22,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/tektoncd/pipeline/pkg/apis/pipeline" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + "github.com/tektoncd/pipeline/pkg/apis/resource/v1alpha1/storage" tb "github.com/tektoncd/pipeline/test/builder" "github.com/tektoncd/pipeline/test/names" corev1 "k8s.io/api/core/v1" @@ -92,7 +93,7 @@ func TestBuildGCSResource_Invalid(t *testing.T) { )), }} { t.Run(tc.name, func(t *testing.T) { - _, err := v1alpha1.NewStorageResource(images, tc.pipelineResource) + _, err := storage.NewResource(images, tc.pipelineResource) if err == nil { t.Error("Expected error creating BuildGCS resource") } @@ -107,7 +108,7 @@ func TestNewBuildGCSResource_Valid(t *testing.T) { tb.PipelineResourceSpecParam("type", "build-gcs"), tb.PipelineResourceSpecParam("ArtifactType", "Manifest"), )) - expectedGCSResource := &v1alpha1.BuildGCSResource{ + expectedGCSResource := &storage.BuildGCSResource{ Name: "build-gcs-resource", Location: "gs://fake-bucket", Type: v1alpha1.PipelineResourceTypeStorage, @@ -116,7 +117,7 @@ func TestNewBuildGCSResource_Valid(t *testing.T) { BuildGCSFetcherImage: "gcr.io/cloud-builders/gcs-fetcher:latest", } - r, err := v1alpha1.NewBuildGCSResource(images, pr) + r, err := storage.NewBuildGCSResource(images, pr) if err != nil { t.Fatalf("Unexpected error creating BuildGCS resource: %s", err) } @@ -126,7 +127,7 @@ func TestNewBuildGCSResource_Valid(t *testing.T) { } func TestBuildGCS_GetReplacements(t *testing.T) { - r := &v1alpha1.BuildGCSResource{ + r := &storage.BuildGCSResource{ Name: "gcs-resource", Location: "gs://fake-bucket", Type: v1alpha1.PipelineResourceTypeBuildGCS, @@ -142,14 +143,14 @@ func TestBuildGCS_GetReplacements(t *testing.T) { } func TestBuildGCS_GetInputSteps(t *testing.T) { - for _, at := range []v1alpha1.GCSArtifactType{ - v1alpha1.GCSArchive, - v1alpha1.GCSZipArchive, - v1alpha1.GCSTarGzArchive, - v1alpha1.GCSManifest, + for _, at := range []storage.GCSArtifactType{ + storage.GCSArchive, + storage.GCSZipArchive, + storage.GCSTarGzArchive, + storage.GCSManifest, } { t.Run(string(at), func(t *testing.T) { - resource := &v1alpha1.BuildGCSResource{ + resource := &storage.BuildGCSResource{ Name: "gcs-valid", Location: "gs://some-bucket", ArtifactType: at, @@ -187,7 +188,7 @@ func TestBuildGCS_InvalidArtifactType(t *testing.T) { tb.PipelineResourceSpecParam("type", "build-gcs"), tb.PipelineResourceSpecParam("ArtifactType", "InVaLiD"), )) - if _, err := v1alpha1.NewBuildGCSResource(images, pr); err == nil { + if _, err := storage.NewBuildGCSResource(images, pr); err == nil { t.Error("NewBuildGCSResource: expected error") } } diff --git a/pkg/apis/pipeline/v1alpha1/gcs_resource.go b/pkg/apis/resource/v1alpha1/storage/gcs.go similarity index 77% rename from pkg/apis/pipeline/v1alpha1/gcs_resource.go rename to pkg/apis/resource/v1alpha1/storage/gcs.go index 1a66b30c1d9..185974f9532 100644 --- a/pkg/apis/pipeline/v1alpha1/gcs_resource.go +++ b/pkg/apis/resource/v1alpha1/storage/gcs.go @@ -1,5 +1,5 @@ /* -Copyright 2019 The Tekton Authors +Copyright 2019-2020 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. @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package v1alpha1 +package storage import ( "fmt" @@ -22,6 +22,8 @@ import ( "strings" "github.com/tektoncd/pipeline/pkg/apis/pipeline" + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + resourcev1alpha1 "github.com/tektoncd/pipeline/pkg/apis/resource/v1alpha1" "github.com/tektoncd/pipeline/pkg/names" corev1 "k8s.io/api/core/v1" ) @@ -39,20 +41,20 @@ fi // GCSResource is a GCS endpoint from which to get artifacts which is required // by a Build/Task for context (e.g. a archive from which to build an image). type GCSResource struct { - Name string `json:"name"` - Type PipelineResourceType `json:"type"` - Location string `json:"location"` - TypeDir bool `json:"typeDir"` + Name string `json:"name"` + Type resourcev1alpha1.PipelineResourceType `json:"type"` + Location string `json:"location"` + TypeDir bool `json:"typeDir"` //Secret holds a struct to indicate a field name and corresponding secret name to populate it - Secrets []SecretParam `json:"secrets"` + Secrets []resourcev1alpha1.SecretParam `json:"secrets"` ShellImage string `json:"-"` GsutilImage string `json:"-"` } // NewGCSResource creates a new GCS resource to pass to a Task -func NewGCSResource(images pipeline.Images, r *PipelineResource) (*GCSResource, error) { - if r.Spec.Type != PipelineResourceTypeStorage { +func NewGCSResource(images pipeline.Images, r *resourcev1alpha1.PipelineResource) (*GCSResource, error) { + if r.Spec.Type != resourcev1alpha1.PipelineResourceTypeStorage { return nil, fmt.Errorf("GCSResource: Cannot create a GCS resource from a %s Pipeline Resource", r.Spec.Type) } var location string @@ -90,12 +92,12 @@ func (s GCSResource) GetName() string { } // GetType returns the type of the resource, in this case "storage" -func (s GCSResource) GetType() PipelineResourceType { - return PipelineResourceTypeStorage +func (s GCSResource) GetType() resourcev1alpha1.PipelineResourceType { + return resourcev1alpha1.PipelineResourceTypeStorage } // GetSecretParams returns the resource secret params -func (s *GCSResource) GetSecretParams() []SecretParam { return s.Secrets } +func (s *GCSResource) GetSecretParams() []resourcev1alpha1.SecretParam { return s.Secrets } // Replacements is used for template replacement on an GCSResource inside of a Taskrun. func (s *GCSResource) Replacements() map[string]string { @@ -107,7 +109,7 @@ func (s *GCSResource) Replacements() map[string]string { } // GetOutputTaskModifier returns the TaskModifier to be used when this resource is an output. -func (s *GCSResource) GetOutputTaskModifier(ts *TaskSpec, path string) (TaskModifier, error) { +func (s *GCSResource) GetOutputTaskModifier(ts *v1alpha1.TaskSpec, path string) (v1alpha1.TaskModifier, error) { var args []string if s.TypeDir { args = []string{"rsync", "-d", "-r", path, s.Location} @@ -117,7 +119,7 @@ func (s *GCSResource) GetOutputTaskModifier(ts *TaskSpec, path string) (TaskModi envVars, secretVolumeMount := getSecretEnvVarsAndVolumeMounts(s.Name, gcsSecretVolumeMountPath, s.Secrets) - step := Step{Container: corev1.Container{ + step := v1alpha1.Step{Container: corev1.Container{ Name: names.SimpleNameGenerator.RestrictLengthWithRandomSuffix(fmt.Sprintf("upload-%s", s.Name)), Image: s.GsutilImage, Command: []string{"gsutil"}, @@ -128,14 +130,14 @@ func (s *GCSResource) GetOutputTaskModifier(ts *TaskSpec, path string) (TaskModi volumes := getStorageVolumeSpec(s, *ts) - return &InternalTaskModifier{ - StepsToAppend: []Step{step}, + return &v1alpha1.InternalTaskModifier{ + StepsToAppend: []v1alpha1.Step{step}, Volumes: volumes, }, nil } // GetInputTaskModifier returns the TaskModifier to be used when this resource is an input. -func (s *GCSResource) GetInputTaskModifier(ts *TaskSpec, path string) (TaskModifier, error) { +func (s *GCSResource) GetInputTaskModifier(ts *v1alpha1.TaskSpec, path string) (v1alpha1.TaskModifier, error) { if path == "" { return nil, fmt.Errorf("GCSResource: Expect Destination Directory param to be set %s", s.Name) } @@ -147,7 +149,7 @@ func (s *GCSResource) GetInputTaskModifier(ts *TaskSpec, path string) (TaskModif } envVars, secretVolumeMount := getSecretEnvVarsAndVolumeMounts(s.Name, gcsSecretVolumeMountPath, s.Secrets) - steps := []Step{ + steps := []v1alpha1.Step{ CreateDirStep(s.ShellImage, s.Name, path), { Script: script, @@ -162,7 +164,7 @@ func (s *GCSResource) GetInputTaskModifier(ts *TaskSpec, path string) (TaskModif volumes := getStorageVolumeSpec(s, *ts) - return &InternalTaskModifier{ + return &v1alpha1.InternalTaskModifier{ StepsToPrepend: steps, Volumes: volumes, }, nil diff --git a/pkg/apis/pipeline/v1alpha1/gcs_resource_test.go b/pkg/apis/resource/v1alpha1/storage/gcs_test.go similarity index 94% rename from pkg/apis/pipeline/v1alpha1/gcs_resource_test.go rename to pkg/apis/resource/v1alpha1/storage/gcs_test.go index d070026a880..d198f627076 100644 --- a/pkg/apis/pipeline/v1alpha1/gcs_resource_test.go +++ b/pkg/apis/resource/v1alpha1/storage/gcs_test.go @@ -14,13 +14,14 @@ See the License for the specific language governing permissions and limitations under the License. */ -package v1alpha1_test +package storage_test import ( "testing" "github.com/google/go-cmp/cmp" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + "github.com/tektoncd/pipeline/pkg/apis/resource/v1alpha1/storage" tb "github.com/tektoncd/pipeline/test/builder" "github.com/tektoncd/pipeline/test/names" corev1 "k8s.io/api/core/v1" @@ -68,7 +69,7 @@ func TestInvalidNewStorageResource(t *testing.T) { ), }} { t.Run(tc.name, func(t *testing.T) { - _, err := v1alpha1.NewStorageResource(images, tc.pipelineResource) + _, err := storage.NewResource(images, tc.pipelineResource) if err == nil { t.Error("Expected error creating GCS resource") } @@ -84,7 +85,7 @@ func TestValidNewGCSResource(t *testing.T) { tb.PipelineResourceSpecParam("dir", "anything"), tb.PipelineResourceSpecSecretParam("GOOGLE_APPLICATION_CREDENTIALS", "secretName", "secretKey"), )) - expectedGCSResource := &v1alpha1.GCSResource{ + expectedGCSResource := &storage.GCSResource{ Name: "gcs-resource", Location: "gs://fake-bucket", Type: v1alpha1.PipelineResourceTypeStorage, @@ -98,7 +99,7 @@ func TestValidNewGCSResource(t *testing.T) { GsutilImage: "google/cloud-sdk", } - gcsRes, err := v1alpha1.NewGCSResource(images, pr) + gcsRes, err := storage.NewGCSResource(images, pr) if err != nil { t.Fatalf("Unexpected error creating GCS resource: %s", err) } @@ -108,7 +109,7 @@ func TestValidNewGCSResource(t *testing.T) { } func TestGCSGetReplacements(t *testing.T) { - gcsResource := &v1alpha1.GCSResource{ + gcsResource := &storage.GCSResource{ Name: "gcs-resource", Location: "gs://fake-bucket", Type: v1alpha1.PipelineResourceTypeGCS, @@ -130,7 +131,7 @@ func TestGetParams(t *testing.T) { tb.PipelineResourceSpecParam("type", "gcs"), tb.PipelineResourceSpecSecretParam("test-field-name", "test-secret-name", "test-secret-key"), )) - gcsResource, err := v1alpha1.NewStorageResource(images, pr) + gcsResource, err := storage.NewResource(images, pr) if err != nil { t.Fatalf("Error creating storage resource: %s", err.Error()) } @@ -149,12 +150,12 @@ func TestGetInputSteps(t *testing.T) { for _, tc := range []struct { name string - gcsResource *v1alpha1.GCSResource + gcsResource *storage.GCSResource wantSteps []v1alpha1.Step wantErr bool }{{ name: "valid download protected buckets", - gcsResource: &v1alpha1.GCSResource{ + gcsResource: &storage.GCSResource{ Name: "gcs-valid", Location: "gs://some-bucket", TypeDir: true, @@ -193,7 +194,7 @@ gsutil rsync -d -r gs://some-bucket /workspace }}, }, { name: "duplicate secret mount paths", - gcsResource: &v1alpha1.GCSResource{ + gcsResource: &storage.GCSResource{ Name: "gcs-valid", Location: "gs://some-bucket", Secrets: []v1alpha1.SecretParam{{ @@ -252,12 +253,12 @@ func TestGetOutputTaskModifier(t *testing.T) { for _, tc := range []struct { name string - gcsResource *v1alpha1.GCSResource + gcsResource *storage.GCSResource wantSteps []v1alpha1.Step wantErr bool }{{ name: "valid upload to protected buckets with directory paths", - gcsResource: &v1alpha1.GCSResource{ + gcsResource: &storage.GCSResource{ Name: "gcs-valid", Location: "gs://some-bucket", TypeDir: true, @@ -281,7 +282,7 @@ func TestGetOutputTaskModifier(t *testing.T) { }}}, }, { name: "duplicate secret mount paths", - gcsResource: &v1alpha1.GCSResource{ + gcsResource: &storage.GCSResource{ Name: "gcs-valid", Location: "gs://some-bucket", Secrets: []v1alpha1.SecretParam{{ @@ -310,7 +311,7 @@ func TestGetOutputTaskModifier(t *testing.T) { }}}, }, { name: "valid upload to protected buckets with single file", - gcsResource: &v1alpha1.GCSResource{ + gcsResource: &storage.GCSResource{ Name: "gcs-valid", Location: "gs://some-bucket", TypeDir: false, diff --git a/pkg/apis/pipeline/v1alpha1/secret_volume_mount.go b/pkg/apis/resource/v1alpha1/storage/secret.go similarity index 89% rename from pkg/apis/pipeline/v1alpha1/secret_volume_mount.go rename to pkg/apis/resource/v1alpha1/storage/secret.go index 0fb2cb7400a..03ed0807274 100644 --- a/pkg/apis/pipeline/v1alpha1/secret_volume_mount.go +++ b/pkg/apis/resource/v1alpha1/storage/secret.go @@ -1,5 +1,5 @@ /* -Copyright 2019 The Tekton Authors +Copyright 2019-2020 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. @@ -14,17 +14,18 @@ See the License for the specific language governing permissions and limitations under the License. */ -package v1alpha1 +package storage import ( "fmt" "path/filepath" "strings" + resource "github.com/tektoncd/pipeline/pkg/apis/resource/v1alpha1" corev1 "k8s.io/api/core/v1" ) -func getSecretEnvVarsAndVolumeMounts(name, mountPath string, secrets []SecretParam) ([]corev1.EnvVar, []corev1.VolumeMount) { +func getSecretEnvVarsAndVolumeMounts(name, mountPath string, secrets []resource.SecretParam) ([]corev1.EnvVar, []corev1.VolumeMount) { mountPaths := make(map[string]struct{}) var ( envVars []corev1.EnvVar diff --git a/pkg/apis/resource/v1alpha1/storage/storage.go b/pkg/apis/resource/v1alpha1/storage/storage.go new file mode 100644 index 00000000000..df96d6ddd7a --- /dev/null +++ b/pkg/apis/resource/v1alpha1/storage/storage.go @@ -0,0 +1,103 @@ +/* +Copyright 2019-2020 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 storage + +import ( + "fmt" + "strings" + + "github.com/tektoncd/pipeline/pkg/apis/pipeline" + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + resource "github.com/tektoncd/pipeline/pkg/apis/resource/v1alpha1" + "github.com/tektoncd/pipeline/pkg/names" + corev1 "k8s.io/api/core/v1" +) + +const ( + // ArtifactStorageBucketType holds the name of the PipelineResource type for a bucket + ArtifactStorageBucketType = "bucket" + + // ArtifactStoragePVCType holds the name of the PipelineResource type for a pvc + ArtifactStoragePVCType = "pvc" +) + +// It adds a function to the PipelineResourceInterface for retrieving secrets that are usually +// needed for storage PipelineResources. +type PipelineStorageResourceInterface interface { + v1alpha1.PipelineResourceInterface + GetSecretParams() []v1alpha1.SecretParam +} + +// NewResource returns an instance of the requested storage subtype, which can be used +// to add input and output steps and volumes to an executing pod. +func NewResource(images pipeline.Images, r *resource.PipelineResource) (PipelineStorageResourceInterface, error) { + if r.Spec.Type != v1alpha1.PipelineResourceTypeStorage { + return nil, fmt.Errorf("StoreResource: Cannot create a storage resource from a %s Pipeline Resource", r.Spec.Type) + } + + for _, param := range r.Spec.Params { + if strings.EqualFold(param.Name, "type") { + switch { + case strings.EqualFold(param.Value, string(resource.PipelineResourceTypeGCS)): + return NewGCSResource(images, r) + case strings.EqualFold(param.Value, string(resource.PipelineResourceTypeBuildGCS)): + return NewBuildGCSResource(images, r) + default: + return nil, fmt.Errorf("%s is an invalid or unimplemented PipelineStorageResource", param.Value) + } + } + } + return nil, fmt.Errorf("StoreResource: Cannot create a storage resource without type %s in spec", r.Name) +} + +func getStorageVolumeSpec(s PipelineStorageResourceInterface, spec v1alpha1.TaskSpec) []corev1.Volume { + var storageVol []corev1.Volume + mountedSecrets := map[string]string{} + + for _, volume := range spec.Volumes { + mountedSecrets[volume.Name] = "" + } + + // Map holds list of secrets that are mounted as volumes + for _, secretParam := range s.GetSecretParams() { + volName := fmt.Sprintf("volume-%s-%s", s.GetName(), secretParam.SecretName) + + gcsSecretVolume := corev1.Volume{ + Name: volName, + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: secretParam.SecretName, + }, + }, + } + + if _, ok := mountedSecrets[volName]; !ok { + storageVol = append(storageVol, gcsSecretVolume) + mountedSecrets[volName] = "" + } + } + return storageVol +} + +// of the step will include name. +func CreateDirStep(shellImage string, name, destinationPath string) v1alpha1.Step { + return v1alpha1.Step{Container: corev1.Container{ + Name: names.SimpleNameGenerator.RestrictLengthWithRandomSuffix(fmt.Sprintf("create-dir-%s", strings.ToLower(name))), + Image: shellImage, + Command: []string{"mkdir", "-p", destinationPath}, + }} +} diff --git a/pkg/apis/resource/v1alpha1/storage/zz_generated.deepcopy.go b/pkg/apis/resource/v1alpha1/storage/zz_generated.deepcopy.go new file mode 100644 index 00000000000..e6c20078dbb --- /dev/null +++ b/pkg/apis/resource/v1alpha1/storage/zz_generated.deepcopy.go @@ -0,0 +1,68 @@ +// +build !ignore_autogenerated + +/* +Copyright 2019 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. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package storage + +import ( + v1alpha1 "github.com/tektoncd/pipeline/pkg/apis/resource/v1alpha1" + v1 "k8s.io/api/core/v1" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ArtifactBucket) DeepCopyInto(out *ArtifactBucket) { + *out = *in + if in.Secrets != nil { + in, out := &in.Secrets, &out.Secrets + *out = make([]v1alpha1.SecretParam, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ArtifactBucket. +func (in *ArtifactBucket) DeepCopy() *ArtifactBucket { + if in == nil { + return nil + } + out := new(ArtifactBucket) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ArtifactPVC) DeepCopyInto(out *ArtifactPVC) { + *out = *in + if in.PersistentVolumeClaim != nil { + in, out := &in.PersistentVolumeClaim, &out.PersistentVolumeClaim + *out = new(v1.PersistentVolumeClaim) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ArtifactPVC. +func (in *ArtifactPVC) DeepCopy() *ArtifactPVC { + if in == nil { + return nil + } + out := new(ArtifactPVC) + in.DeepCopyInto(out) + return out +} diff --git a/pkg/artifacts/artifact_storage_test.go b/pkg/artifacts/artifact_storage_test.go index ec2cc47c26c..a4e8fd6c62c 100644 --- a/pkg/artifacts/artifact_storage_test.go +++ b/pkg/artifacts/artifact_storage_test.go @@ -23,6 +23,7 @@ import ( "github.com/google/go-cmp/cmp/cmpopts" "github.com/tektoncd/pipeline/pkg/apis/pipeline" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + "github.com/tektoncd/pipeline/pkg/apis/resource/v1alpha1/storage" "github.com/tektoncd/pipeline/pkg/system" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" @@ -210,7 +211,7 @@ func TestInitializeArtifactStorageWithConfigMap(t *testing.T) { PVCSizeKey: "10Gi", }, }, - expectedArtifactStorage: &v1alpha1.ArtifactPVC{ + expectedArtifactStorage: &storage.ArtifactPVC{ Name: "pipelineruntest", PersistentVolumeClaim: GetPersistentVolumeClaim("10Gi", defaultStorageClass), ShellImage: "busybox", @@ -227,7 +228,7 @@ func TestInitializeArtifactStorageWithConfigMap(t *testing.T) { PVCStorageClassNameKey: customStorageClass, }, }, - expectedArtifactStorage: &v1alpha1.ArtifactPVC{ + expectedArtifactStorage: &storage.ArtifactPVC{ Name: "pipelineruntest", PersistentVolumeClaim: GetPersistentVolumeClaim("5Gi", &customStorageClass), ShellImage: "busybox", @@ -246,7 +247,7 @@ func TestInitializeArtifactStorageWithConfigMap(t *testing.T) { BucketServiceAccountSecretKey: "sakey", }, }, - expectedArtifactStorage: &v1alpha1.ArtifactBucket{ + expectedArtifactStorage: &storage.ArtifactBucket{ Location: "gs://fake-bucket", Secrets: []v1alpha1.SecretParam{{ FieldName: "GOOGLE_APPLICATION_CREDENTIALS", @@ -270,7 +271,7 @@ func TestInitializeArtifactStorageWithConfigMap(t *testing.T) { BucketServiceAccountSecretKey: "sakey", }, }, - expectedArtifactStorage: &v1alpha1.ArtifactPVC{ + expectedArtifactStorage: &storage.ArtifactPVC{ Name: "pipelineruntest", PersistentVolumeClaim: persistentVolumeClaim, ShellImage: "busybox", @@ -288,7 +289,7 @@ func TestInitializeArtifactStorageWithConfigMap(t *testing.T) { BucketServiceAccountSecretKey: "sakey", }, }, - expectedArtifactStorage: &v1alpha1.ArtifactPVC{ + expectedArtifactStorage: &storage.ArtifactPVC{ Name: "pipelineruntest", PersistentVolumeClaim: persistentVolumeClaim, ShellImage: "busybox", @@ -302,7 +303,7 @@ func TestInitializeArtifactStorageWithConfigMap(t *testing.T) { Name: GetBucketConfigName(), }, }, - expectedArtifactStorage: &v1alpha1.ArtifactPVC{ + expectedArtifactStorage: &storage.ArtifactPVC{ Name: "pipelineruntest", PersistentVolumeClaim: persistentVolumeClaim, ShellImage: "busybox", @@ -319,7 +320,7 @@ func TestInitializeArtifactStorageWithConfigMap(t *testing.T) { BucketLocationKey: "gs://fake-bucket", }, }, - expectedArtifactStorage: &v1alpha1.ArtifactBucket{ + expectedArtifactStorage: &storage.ArtifactBucket{ Location: "gs://fake-bucket", ShellImage: "busybox", GsutilImage: "google/cloud-sdk", @@ -339,7 +340,7 @@ func TestInitializeArtifactStorageWithConfigMap(t *testing.T) { BucketServiceAccountFieldName: "BOTO_CONFIG", }, }, - expectedArtifactStorage: &v1alpha1.ArtifactBucket{ + expectedArtifactStorage: &storage.ArtifactBucket{ Location: "s3://fake-bucket", ShellImage: "busybox", GsutilImage: "google/cloud-sdk", @@ -572,7 +573,7 @@ func TestInitializeArtifactStorageWithoutConfigMap(t *testing.T) { t.Fatalf("Somehow had error initializing artifact storage run out of fake client: %s", err) } - expectedArtifactPVC := &v1alpha1.ArtifactPVC{ + expectedArtifactPVC := &storage.ArtifactPVC{ Name: "pipelineruntest", PersistentVolumeClaim: persistentVolumeClaim, ShellImage: "busybox", @@ -608,7 +609,7 @@ func TestGetArtifactStorageWithConfigMap(t *testing.T) { BucketServiceAccountSecretKey: "sakey", }, }, - expectedArtifactStorage: &v1alpha1.ArtifactBucket{ + expectedArtifactStorage: &storage.ArtifactBucket{ Location: "gs://fake-bucket", Secrets: []v1alpha1.SecretParam{{ FieldName: "GOOGLE_APPLICATION_CREDENTIALS", @@ -631,7 +632,7 @@ func TestGetArtifactStorageWithConfigMap(t *testing.T) { BucketServiceAccountSecretKey: "sakey", }, }, - expectedArtifactStorage: &v1alpha1.ArtifactPVC{ + expectedArtifactStorage: &storage.ArtifactPVC{ Name: pipelinerun.Name, ShellImage: "busybox", }, @@ -647,7 +648,7 @@ func TestGetArtifactStorageWithConfigMap(t *testing.T) { BucketServiceAccountSecretKey: "sakey", }, }, - expectedArtifactStorage: &v1alpha1.ArtifactPVC{ + expectedArtifactStorage: &storage.ArtifactPVC{ Name: pipelinerun.Name, ShellImage: "busybox", }, @@ -659,7 +660,7 @@ func TestGetArtifactStorageWithConfigMap(t *testing.T) { Name: GetBucketConfigName(), }, }, - expectedArtifactStorage: &v1alpha1.ArtifactPVC{ + expectedArtifactStorage: &storage.ArtifactPVC{ Name: pipelinerun.Name, ShellImage: "busybox", }, @@ -687,7 +688,7 @@ func TestGetArtifactStorageWithoutConfigMap(t *testing.T) { t.Fatalf("Somehow had error initializing artifact storage run out of fake client: %s", err) } - expectedArtifactPVC := &v1alpha1.ArtifactPVC{ + expectedArtifactPVC := &storage.ArtifactPVC{ Name: "pipelineruntest", ShellImage: "busybox", } @@ -715,7 +716,7 @@ func TestGetArtifactStorageWithPVCConfigMap(t *testing.T) { PVCSizeKey: "10Gi", }, }, - expectedArtifactStorage: &v1alpha1.ArtifactPVC{ + expectedArtifactStorage: &storage.ArtifactPVC{ Name: "pipelineruntest", ShellImage: "busybox", }, diff --git a/pkg/artifacts/artifacts_storage.go b/pkg/artifacts/artifacts_storage.go index 8f7f86ef3c4..6f999c6e703 100644 --- a/pkg/artifacts/artifacts_storage.go +++ b/pkg/artifacts/artifacts_storage.go @@ -23,6 +23,7 @@ import ( "github.com/tektoncd/pipeline/pkg/apis/pipeline" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + "github.com/tektoncd/pipeline/pkg/apis/resource/v1alpha1/storage" "github.com/tektoncd/pipeline/pkg/system" "go.uber.org/zap" corev1 "k8s.io/api/core/v1" @@ -160,7 +161,7 @@ func InitializeArtifactStorage(images pipeline.Images, pr *v1alpha1.PipelineRun, if err != nil { return nil, err } - return &v1alpha1.ArtifactPVC{Name: pr.Name, PersistentVolumeClaim: pvc, ShellImage: images.ShellImage}, nil + return &storage.ArtifactPVC{Name: pr.Name, PersistentVolumeClaim: pvc, ShellImage: images.ShellImage}, nil } return NewArtifactBucketConfigFromConfigMap(images)(configMap) @@ -219,15 +220,15 @@ func GetArtifactStorage(images pipeline.Images, prName string, c kubernetes.Inte return nil, fmt.Errorf("couldn't determine if PVC was needed from config map: %w", err) } if pvc { - return &v1alpha1.ArtifactPVC{Name: prName, ShellImage: images.ShellImage}, nil + return &storage.ArtifactPVC{Name: prName, ShellImage: images.ShellImage}, nil } return NewArtifactBucketConfigFromConfigMap(images)(configMap) } // NewArtifactBucketConfigFromConfigMap creates a Bucket from the supplied ConfigMap -func NewArtifactBucketConfigFromConfigMap(images pipeline.Images) func(configMap *corev1.ConfigMap) (*v1alpha1.ArtifactBucket, error) { - return func(configMap *corev1.ConfigMap) (*v1alpha1.ArtifactBucket, error) { - c := &v1alpha1.ArtifactBucket{ +func NewArtifactBucketConfigFromConfigMap(images pipeline.Images) func(configMap *corev1.ConfigMap) (*storage.ArtifactBucket, error) { + return func(configMap *corev1.ConfigMap) (*storage.ArtifactBucket, error) { + c := &storage.ArtifactBucket{ ShellImage: images.ShellImage, GsutilImage: images.GsutilImage, } diff --git a/pkg/reconciler/pipelinerun/config/store.go b/pkg/reconciler/pipelinerun/config/store.go index 41f72b17a2b..7f46dd41e72 100644 --- a/pkg/reconciler/pipelinerun/config/store.go +++ b/pkg/reconciler/pipelinerun/config/store.go @@ -20,7 +20,7 @@ import ( "context" "github.com/tektoncd/pipeline/pkg/apis/pipeline" - "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + "github.com/tektoncd/pipeline/pkg/apis/resource/v1alpha1/storage" "github.com/tektoncd/pipeline/pkg/artifacts" "knative.dev/pkg/configmap" ) @@ -29,7 +29,7 @@ type cfgKey struct{} // +k8s:deepcopy-gen=false type Config struct { - ArtifactBucket *v1alpha1.ArtifactBucket + ArtifactBucket *storage.ArtifactBucket } func FromContext(ctx context.Context) *Config { @@ -68,7 +68,7 @@ func (s *Store) Load() *Config { ep := s.UntypedLoad(artifacts.GetBucketConfigName()) if ep == nil { return &Config{ - ArtifactBucket: &v1alpha1.ArtifactBucket{ + ArtifactBucket: &storage.ArtifactBucket{ Location: "", ShellImage: s.images.ShellImage, GsutilImage: s.images.GsutilImage, @@ -77,7 +77,7 @@ func (s *Store) Load() *Config { } return &Config{ - ArtifactBucket: ep.(*v1alpha1.ArtifactBucket).DeepCopy(), + ArtifactBucket: ep.(*storage.ArtifactBucket).DeepCopy(), } } diff --git a/pkg/reconciler/pipelinerun/resources/conditionresolution.go b/pkg/reconciler/pipelinerun/resources/conditionresolution.go index 48445928ab7..3294da25277 100644 --- a/pkg/reconciler/pipelinerun/resources/conditionresolution.go +++ b/pkg/reconciler/pipelinerun/resources/conditionresolution.go @@ -23,6 +23,8 @@ import ( "github.com/tektoncd/pipeline/pkg/apis/pipeline" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha2" + "github.com/tektoncd/pipeline/pkg/apis/resource" + resourcev1alpha1 "github.com/tektoncd/pipeline/pkg/apis/resource/v1alpha1" corev1 "k8s.io/api/core/v1" ) @@ -135,11 +137,11 @@ func convertParamTemplates(step *v1alpha1.Step, params []v1alpha1.ParamSpec) { // ApplyResources applies the substitution from values in resources which are referenced // in spec as subitems of the replacementStr. -func ApplyResourceSubstitution(step *v1alpha1.Step, resolvedResources map[string]*v1alpha1.PipelineResource, conditionResources []v1alpha1.ResourceDeclaration, images pipeline.Images) error { +func ApplyResourceSubstitution(step *v1alpha1.Step, resolvedResources map[string]*resourcev1alpha1.PipelineResource, conditionResources []v1alpha1.ResourceDeclaration, images pipeline.Images) error { replacements := make(map[string]string) for _, cr := range conditionResources { if rSpec, ok := resolvedResources[cr.Name]; ok { - r, err := v1alpha1.ResourceFromType(rSpec, images) + r, err := resource.FromType(rSpec, images) if err != nil { return fmt.Errorf("error trying to create resource: %w", err) } diff --git a/pkg/reconciler/taskrun/resources/apply_test.go b/pkg/reconciler/taskrun/resources/apply_test.go index b0e8dbf339b..5e468fd802f 100644 --- a/pkg/reconciler/taskrun/resources/apply_test.go +++ b/pkg/reconciler/taskrun/resources/apply_test.go @@ -23,6 +23,7 @@ import ( "github.com/tektoncd/pipeline/pkg/apis/pipeline" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha2" + "github.com/tektoncd/pipeline/pkg/apis/resource" "github.com/tektoncd/pipeline/pkg/reconciler/taskrun/resources" "github.com/tektoncd/pipeline/test/builder" "github.com/tektoncd/pipeline/test/names" @@ -340,7 +341,7 @@ var ( "bucket": gcsResource, } - gitResource, _ = v1alpha1.ResourceFromType(&v1alpha1.PipelineResource{ + gitResource, _ = resource.FromType(&v1alpha1.PipelineResource{ ObjectMeta: metav1.ObjectMeta{ Name: "git-resource", }, @@ -353,7 +354,7 @@ var ( }, }, images) - imageResource, _ = v1alpha1.ResourceFromType(&v1alpha1.PipelineResource{ + imageResource, _ = resource.FromType(&v1alpha1.PipelineResource{ ObjectMeta: metav1.ObjectMeta{ Name: "image-resource", }, @@ -366,7 +367,7 @@ var ( }, }, images) - gcsResource, _ = v1alpha1.ResourceFromType(&v1alpha1.PipelineResource{ + gcsResource, _ = resource.FromType(&v1alpha1.PipelineResource{ ObjectMeta: metav1.ObjectMeta{ Name: "gcs-resource", }, diff --git a/pkg/reconciler/taskrun/resources/cloudevent/cloud_event_controller.go b/pkg/reconciler/taskrun/resources/cloudevent/cloud_event_controller.go index 79b3bdc9315..e83de23b616 100644 --- a/pkg/reconciler/taskrun/resources/cloudevent/cloud_event_controller.go +++ b/pkg/reconciler/taskrun/resources/cloudevent/cloud_event_controller.go @@ -21,6 +21,8 @@ import ( "github.com/hashicorp/go-multierror" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + resource "github.com/tektoncd/pipeline/pkg/apis/resource/v1alpha1" + "github.com/tektoncd/pipeline/pkg/apis/resource/v1alpha1/cloudevent" "go.uber.org/zap" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -32,8 +34,8 @@ func InitializeCloudEvents(tr *v1alpha1.TaskRun, prs []*v1alpha1.PipelineResourc if len(tr.Status.CloudEvents) == 0 { var targets []string for _, output := range prs { - if output.Spec.Type == v1alpha1.PipelineResourceTypeCloudEvent { - cer, _ := v1alpha1.NewCloudEventResource(output) + if output.Spec.Type == resource.PipelineResourceTypeCloudEvent { + cer, _ := cloudevent.NewResource(output) targets = append(targets, cer.TargetURI) } } diff --git a/pkg/reconciler/taskrun/resources/image_exporter.go b/pkg/reconciler/taskrun/resources/image_exporter.go index bf3404ebd97..6a7784f427d 100644 --- a/pkg/reconciler/taskrun/resources/image_exporter.go +++ b/pkg/reconciler/taskrun/resources/image_exporter.go @@ -22,6 +22,7 @@ import ( "path/filepath" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + "github.com/tektoncd/pipeline/pkg/apis/resource/v1alpha1/image" "github.com/tektoncd/pipeline/pkg/names" corev1 "k8s.io/api/core/v1" ) @@ -36,7 +37,7 @@ func AddOutputImageDigestExporter( gr GetResource, ) error { - output := []*v1alpha1.ImageResource{} + output := []*image.Resource{} if len(tr.Spec.Outputs.Resources) > 0 { for _, trb := range tr.Spec.Outputs.Resources { boundResource, err := getBoundResource(trb.Name, tr.Spec.Outputs.Resources) @@ -49,7 +50,7 @@ func AddOutputImageDigestExporter( return fmt.Errorf("failed to get output pipeline Resource for taskRun %q resource %v; error: %w while adding output image digest exporter", tr.Name, boundResource, err) } if resource.Spec.Type == v1alpha1.PipelineResourceTypeImage { - imageResource, err := v1alpha1.NewImageResource(resource) + imageResource, err := image.NewResource(resource) if err != nil { return fmt.Errorf("invalid Image Resource for taskRun %q resource %v; error: %w", tr.Name, boundResource, err) } diff --git a/pkg/reconciler/taskrun/resources/input_resource_test.go b/pkg/reconciler/taskrun/resources/input_resource_test.go index ba55cc4501d..014dfaaa7ee 100644 --- a/pkg/reconciler/taskrun/resources/input_resource_test.go +++ b/pkg/reconciler/taskrun/resources/input_resource_test.go @@ -23,6 +23,7 @@ import ( "github.com/tektoncd/pipeline/pkg/apis/pipeline" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha2" + "github.com/tektoncd/pipeline/pkg/apis/resource" "github.com/tektoncd/pipeline/pkg/artifacts" "github.com/tektoncd/pipeline/pkg/logging" "github.com/tektoncd/pipeline/test/names" @@ -281,7 +282,7 @@ func setUp() { }} inputResourceInterfaces = make(map[string]v1alpha1.PipelineResourceInterface) for _, r := range rs { - ri, _ := v1alpha1.ResourceFromType(r, images) + ri, _ := resource.FromType(r, images) inputResourceInterfaces[r.Name] = ri } } @@ -1406,7 +1407,7 @@ func mockResolveTaskResources(taskRun *v1alpha1.TaskRun) map[string]v1alpha1.Pip i = inputResourceInterfaces[r.ResourceRef.Name] resolved[r.Name] = i case r.ResourceSpec != nil: - i, _ = v1alpha1.ResourceFromType(&v1alpha1.PipelineResource{ + i, _ = resource.FromType(&v1alpha1.PipelineResource{ ObjectMeta: metav1.ObjectMeta{ Name: r.Name, }, diff --git a/pkg/reconciler/taskrun/resources/input_resources.go b/pkg/reconciler/taskrun/resources/input_resources.go index 15893910317..6f139a0ed55 100644 --- a/pkg/reconciler/taskrun/resources/input_resources.go +++ b/pkg/reconciler/taskrun/resources/input_resources.go @@ -22,6 +22,7 @@ import ( "github.com/tektoncd/pipeline/pkg/apis/pipeline" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + "github.com/tektoncd/pipeline/pkg/apis/resource/v1alpha1/storage" "github.com/tektoncd/pipeline/pkg/artifacts" "go.uber.org/zap" corev1 "k8s.io/api/core/v1" @@ -97,9 +98,9 @@ func AddInputResource( if as.GetType() == pipeline.ArtifactStoragePVCType { mountPVC = true for _, s := range cpSteps { - s.VolumeMounts = []corev1.VolumeMount{v1alpha1.GetPvcMount(pvcName)} + s.VolumeMounts = []corev1.VolumeMount{storage.GetPvcMount(pvcName)} copyStepsFromPrevTasks = append(copyStepsFromPrevTasks, - v1alpha1.CreateDirStep(images.ShellImage, boundResource.Name, dPath), + storage.CreateDirStep(images.ShellImage, boundResource.Name, dPath), s) } } else { diff --git a/pkg/reconciler/taskrun/resources/output_resource.go b/pkg/reconciler/taskrun/resources/output_resource.go index d2fca9bf40e..177a0896906 100644 --- a/pkg/reconciler/taskrun/resources/output_resource.go +++ b/pkg/reconciler/taskrun/resources/output_resource.go @@ -22,6 +22,7 @@ import ( "github.com/tektoncd/pipeline/pkg/apis/pipeline" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + "github.com/tektoncd/pipeline/pkg/apis/resource/v1alpha1/storage" "github.com/tektoncd/pipeline/pkg/artifacts" "go.uber.org/zap" "k8s.io/client-go/kubernetes" @@ -88,7 +89,7 @@ func AddOutputResources( } // Add containers to mkdir each output directory. This should run before the build steps themselves. - mkdirSteps := []v1alpha1.Step{v1alpha1.CreateDirStep(images.ShellImage, boundResource.Name, sourcePath)} + mkdirSteps := []v1alpha1.Step{storage.CreateDirStep(images.ShellImage, boundResource.Name, sourcePath)} taskSpec.Steps = append(mkdirSteps, taskSpec.Steps...) if v1alpha1.AllowedOutputResources[resource.GetType()] && taskRun.HasPipelineRunOwnerReference() { diff --git a/pkg/reconciler/taskrun/resources/output_resource_test.go b/pkg/reconciler/taskrun/resources/output_resource_test.go index a56a9c090d5..1e22b80d729 100644 --- a/pkg/reconciler/taskrun/resources/output_resource_test.go +++ b/pkg/reconciler/taskrun/resources/output_resource_test.go @@ -21,6 +21,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + "github.com/tektoncd/pipeline/pkg/apis/resource" "github.com/tektoncd/pipeline/pkg/artifacts" "github.com/tektoncd/pipeline/pkg/logging" "github.com/tektoncd/pipeline/test/names" @@ -94,7 +95,7 @@ func outputResourceSetup() { outputResources = make(map[string]v1alpha1.PipelineResourceInterface) for _, r := range rs { - ri, _ := v1alpha1.ResourceFromType(r, images) + ri, _ := resource.FromType(r, images) outputResources[r.Name] = ri } } @@ -1286,7 +1287,7 @@ func resolveOutputResources(taskRun *v1alpha1.TaskRun) map[string]v1alpha1.Pipel i = outputResources[name] resolved[r.Name] = i } else if r.ResourceSpec != nil { - i, _ = v1alpha1.ResourceFromType(&v1alpha1.PipelineResource{ + i, _ = resource.FromType(&v1alpha1.PipelineResource{ ObjectMeta: metav1.ObjectMeta{ Name: r.Name, }, diff --git a/pkg/reconciler/taskrun/taskrun.go b/pkg/reconciler/taskrun/taskrun.go index fc9047c0f4b..cb347e57706 100644 --- a/pkg/reconciler/taskrun/taskrun.go +++ b/pkg/reconciler/taskrun/taskrun.go @@ -27,6 +27,7 @@ import ( "github.com/tektoncd/pipeline/pkg/apis/config" "github.com/tektoncd/pipeline/pkg/apis/pipeline" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + "github.com/tektoncd/pipeline/pkg/apis/resource" listers "github.com/tektoncd/pipeline/pkg/client/listers/pipeline/v1alpha1" resourcelisters "github.com/tektoncd/pipeline/pkg/client/resource/listers/resource/v1alpha1" "github.com/tektoncd/pipeline/pkg/contexts" @@ -587,7 +588,7 @@ func isExceededResourceQuotaError(err error) bool { func resourceImplBinding(resources map[string]*v1alpha1.PipelineResource, images pipeline.Images) (map[string]v1alpha1.PipelineResourceInterface, error) { p := make(map[string]v1alpha1.PipelineResourceInterface) for rName, r := range resources { - i, err := v1alpha1.ResourceFromType(r, images) + i, err := resource.FromType(r, images) if err != nil { return nil, fmt.Errorf("failed to create resource %s : %v with error: %w", rName, r, err) } diff --git a/third_party/github.com/hashicorp/errwrap/errwrap_test.go b/third_party/github.com/hashicorp/errwrap/errwrap_test.go new file mode 100644 index 00000000000..5ae5f8e3cde --- /dev/null +++ b/third_party/github.com/hashicorp/errwrap/errwrap_test.go @@ -0,0 +1,94 @@ +package errwrap + +import ( + "fmt" + "testing" +) + +func TestWrappedError_impl(t *testing.T) { + var _ error = new(wrappedError) +} + +func TestGetAll(t *testing.T) { + cases := []struct { + Err error + Msg string + Len int + }{ + {}, + { + fmt.Errorf("foo"), + "foo", + 1, + }, + { + fmt.Errorf("bar"), + "foo", + 0, + }, + { + Wrapf("bar", fmt.Errorf("foo")), + "foo", + 1, + }, + { + Wrapf("{{err}}", fmt.Errorf("foo")), + "foo", + 2, + }, + { + Wrapf("bar", Wrapf("baz", fmt.Errorf("foo"))), + "foo", + 1, + }, + } + + for i, tc := range cases { + actual := GetAll(tc.Err, tc.Msg) + if len(actual) != tc.Len { + t.Fatalf("%d: bad: %#v", i, actual) + } + for _, v := range actual { + if v.Error() != tc.Msg { + t.Fatalf("%d: bad: %#v", i, actual) + } + } + } +} + +func TestGetAllType(t *testing.T) { + cases := []struct { + Err error + Type interface{} + Len int + }{ + {}, + { + fmt.Errorf("foo"), + "foo", + 0, + }, + { + fmt.Errorf("bar"), + fmt.Errorf("foo"), + 1, + }, + { + Wrapf("bar", fmt.Errorf("foo")), + fmt.Errorf("baz"), + 2, + }, + { + Wrapf("bar", Wrapf("baz", fmt.Errorf("foo"))), + Wrapf("", nil), + 0, + }, + } + + for i, tc := range cases { + actual := GetAllType(tc.Err, tc.Type) + if len(actual) != tc.Len { + t.Fatalf("%d: bad: %#v", i, actual) + } + } +} diff --git a/third_party/github.com/hashicorp/go-multierror/append_test.go b/third_party/github.com/hashicorp/go-multierror/append_test.go new file mode 100644 index 00000000000..58ddafa8dde --- /dev/null +++ b/third_party/github.com/hashicorp/go-multierror/append_test.go @@ -0,0 +1,82 @@ +package multierror + +import ( + "errors" + "testing" +) + +func TestAppend_Error(t *testing.T) { + original := &Error{ + Errors: []error{errors.New("foo")}, + } + + result := Append(original, errors.New("bar")) + if len(result.Errors) != 2 { + t.Fatalf("wrong len: %d", len(result.Errors)) + } + + original = &Error{} + result = Append(original, errors.New("bar")) + if len(result.Errors) != 1 { + t.Fatalf("wrong len: %d", len(result.Errors)) + } + + // Test when a typed nil is passed + var e *Error + result = Append(e, errors.New("baz")) + if len(result.Errors) != 1 { + t.Fatalf("wrong len: %d", len(result.Errors)) + } + + // Test flattening + original = &Error{ + Errors: []error{errors.New("foo")}, + } + + result = Append(original, Append(nil, errors.New("foo"), errors.New("bar"))) + if len(result.Errors) != 3 { + t.Fatalf("wrong len: %d", len(result.Errors)) + } +} + +func TestAppend_NilError(t *testing.T) { + var err error + result := Append(err, errors.New("bar")) + if len(result.Errors) != 1 { + t.Fatalf("wrong len: %d", len(result.Errors)) + } +} + +func TestAppend_NilErrorArg(t *testing.T) { + var err error + var nilErr *Error + result := Append(err, nilErr) + if len(result.Errors) != 0 { + t.Fatalf("wrong len: %d", len(result.Errors)) + } +} + +func TestAppend_NilErrorIfaceArg(t *testing.T) { + var err error + var nilErr error + result := Append(err, nilErr) + if len(result.Errors) != 0 { + t.Fatalf("wrong len: %d", len(result.Errors)) + } +} + +func TestAppend_NonError(t *testing.T) { + original := errors.New("foo") + result := Append(original, errors.New("bar")) + if len(result.Errors) != 2 { + t.Fatalf("wrong len: %d", len(result.Errors)) + } +} + +func TestAppend_NonError_Error(t *testing.T) { + original := errors.New("foo") + result := Append(original, Append(nil, errors.New("bar"))) + if len(result.Errors) != 2 { + t.Fatalf("wrong len: %d", len(result.Errors)) + } +} diff --git a/third_party/github.com/hashicorp/go-multierror/flatten_test.go b/third_party/github.com/hashicorp/go-multierror/flatten_test.go new file mode 100644 index 00000000000..e99c4101b5b --- /dev/null +++ b/third_party/github.com/hashicorp/go-multierror/flatten_test.go @@ -0,0 +1,46 @@ +package multierror + +import ( + "errors" + "fmt" + "reflect" + "testing" +) + +func TestFlatten(t *testing.T) { + original := &Error{ + Errors: []error{ + errors.New("one"), + &Error{ + Errors: []error{ + errors.New("two"), + &Error{ + Errors: []error{ + errors.New("three"), + }, + }, + }, + }, + }, + } + + expected := `3 errors occurred: + * one + * two + * three + +` + actual := fmt.Sprintf("%s", Flatten(original)) + + if expected != actual { + t.Fatalf("expected: %s, got: %s", expected, actual) + } +} + +func TestFlatten_nonError(t *testing.T) { + err := errors.New("foo") + actual := Flatten(err) + if !reflect.DeepEqual(actual, err) { + t.Fatalf("bad: %#v", actual) + } +} diff --git a/third_party/github.com/hashicorp/go-multierror/format_test.go b/third_party/github.com/hashicorp/go-multierror/format_test.go new file mode 100644 index 00000000000..2b6da1defcd --- /dev/null +++ b/third_party/github.com/hashicorp/go-multierror/format_test.go @@ -0,0 +1,40 @@ +package multierror + +import ( + "errors" + "testing" +) + +func TestListFormatFuncSingle(t *testing.T) { + expected := `1 error occurred: + * foo + +` + + errors := []error{ + errors.New("foo"), + } + + actual := ListFormatFunc(errors) + if actual != expected { + t.Fatalf("bad: %#v", actual) + } +} + +func TestListFormatFuncMultiple(t *testing.T) { + expected := `2 errors occurred: + * foo + * bar + +` + + errors := []error{ + errors.New("foo"), + errors.New("bar"), + } + + actual := ListFormatFunc(errors) + if actual != expected { + t.Fatalf("bad: %#v", actual) + } +} diff --git a/third_party/github.com/hashicorp/go-multierror/multierror_test.go b/third_party/github.com/hashicorp/go-multierror/multierror_test.go new file mode 100644 index 00000000000..2949c3b8bc7 --- /dev/null +++ b/third_party/github.com/hashicorp/go-multierror/multierror_test.go @@ -0,0 +1,71 @@ +package multierror + +import ( + "errors" + "reflect" + "testing" +) + +func TestError_Impl(t *testing.T) { + var _ error = new(Error) +} + +func TestErrorError_custom(t *testing.T) { + errors := []error{ + errors.New("foo"), + errors.New("bar"), + } + + fn := func(es []error) string { + return "foo" + } + + multi := &Error{Errors: errors, ErrorFormat: fn} + if multi.Error() != "foo" { + t.Fatalf("bad: %s", multi.Error()) + } +} + +func TestErrorError_default(t *testing.T) { + expected := `2 errors occurred: + * foo + * bar + +` + + errors := []error{ + errors.New("foo"), + errors.New("bar"), + } + + multi := &Error{Errors: errors} + if multi.Error() != expected { + t.Fatalf("bad: %s", multi.Error()) + } +} + +func TestErrorErrorOrNil(t *testing.T) { + err := new(Error) + if err.ErrorOrNil() != nil { + t.Fatalf("bad: %#v", err.ErrorOrNil()) + } + + err.Errors = []error{errors.New("foo")} + if v := err.ErrorOrNil(); v == nil { + t.Fatal("should not be nil") + } else if !reflect.DeepEqual(v, err) { + t.Fatalf("bad: %#v", v) + } +} + +func TestErrorWrappedErrors(t *testing.T) { + errors := []error{ + errors.New("foo"), + errors.New("bar"), + } + + multi := &Error{Errors: errors} + if !reflect.DeepEqual(multi.Errors, multi.WrappedErrors()) { + t.Fatalf("bad: %s", multi.WrappedErrors()) + } +} diff --git a/third_party/github.com/hashicorp/go-multierror/prefix_test.go b/third_party/github.com/hashicorp/go-multierror/prefix_test.go new file mode 100644 index 00000000000..1d4a6f6d333 --- /dev/null +++ b/third_party/github.com/hashicorp/go-multierror/prefix_test.go @@ -0,0 +1,33 @@ +package multierror + +import ( + "errors" + "testing" +) + +func TestPrefix_Error(t *testing.T) { + original := &Error{ + Errors: []error{errors.New("foo")}, + } + + result := Prefix(original, "bar") + if result.(*Error).Errors[0].Error() != "bar foo" { + t.Fatalf("bad: %s", result) + } +} + +func TestPrefix_NilError(t *testing.T) { + var err error + result := Prefix(err, "bar") + if result != nil { + t.Fatalf("bad: %#v", result) + } +} + +func TestPrefix_NonError(t *testing.T) { + original := errors.New("foo") + result := Prefix(original, "bar") + if result.Error() != "bar foo" { + t.Fatalf("bad: %s", result) + } +} diff --git a/third_party/github.com/hashicorp/go-multierror/sort_test.go b/third_party/github.com/hashicorp/go-multierror/sort_test.go new file mode 100644 index 00000000000..7fd04e8c560 --- /dev/null +++ b/third_party/github.com/hashicorp/go-multierror/sort_test.go @@ -0,0 +1,52 @@ +package multierror + +import ( + "errors" + "reflect" + "sort" + "testing" +) + +func TestSortSingle(t *testing.T) { + errFoo := errors.New("foo") + + expected := []error{ + errFoo, + } + + err := &Error{ + Errors: []error{ + errFoo, + }, + } + + sort.Sort(err) + if !reflect.DeepEqual(err.Errors, expected) { + t.Fatalf("bad: %#v", err) + } +} + +func TestSortMultiple(t *testing.T) { + errBar := errors.New("bar") + errBaz := errors.New("baz") + errFoo := errors.New("foo") + + expected := []error{ + errBar, + errBaz, + errFoo, + } + + err := &Error{ + Errors: []error{ + errFoo, + errBar, + errBaz, + }, + } + + sort.Sort(err) + if !reflect.DeepEqual(err.Errors, expected) { + t.Fatalf("bad: %#v", err) + } +} diff --git a/third_party/github.com/hashicorp/golang-lru/2q_test.go b/third_party/github.com/hashicorp/golang-lru/2q_test.go new file mode 100644 index 00000000000..1b0f3518178 --- /dev/null +++ b/third_party/github.com/hashicorp/golang-lru/2q_test.go @@ -0,0 +1,306 @@ +package lru + +import ( + "math/rand" + "testing" +) + +func Benchmark2Q_Rand(b *testing.B) { + l, err := New2Q(8192) + if err != nil { + b.Fatalf("err: %v", err) + } + + trace := make([]int64, b.N*2) + for i := 0; i < b.N*2; i++ { + trace[i] = rand.Int63() % 32768 + } + + b.ResetTimer() + + var hit, miss int + for i := 0; i < 2*b.N; i++ { + if i%2 == 0 { + l.Add(trace[i], trace[i]) + } else { + _, ok := l.Get(trace[i]) + if ok { + hit++ + } else { + miss++ + } + } + } + b.Logf("hit: %d miss: %d ratio: %f", hit, miss, float64(hit)/float64(miss)) +} + +func Benchmark2Q_Freq(b *testing.B) { + l, err := New2Q(8192) + if err != nil { + b.Fatalf("err: %v", err) + } + + trace := make([]int64, b.N*2) + for i := 0; i < b.N*2; i++ { + if i%2 == 0 { + trace[i] = rand.Int63() % 16384 + } else { + trace[i] = rand.Int63() % 32768 + } + } + + b.ResetTimer() + + for i := 0; i < b.N; i++ { + l.Add(trace[i], trace[i]) + } + var hit, miss int + for i := 0; i < b.N; i++ { + _, ok := l.Get(trace[i]) + if ok { + hit++ + } else { + miss++ + } + } + b.Logf("hit: %d miss: %d ratio: %f", hit, miss, float64(hit)/float64(miss)) +} + +func Test2Q_RandomOps(t *testing.T) { + size := 128 + l, err := New2Q(128) + if err != nil { + t.Fatalf("err: %v", err) + } + + n := 200000 + for i := 0; i < n; i++ { + key := rand.Int63() % 512 + r := rand.Int63() + switch r % 3 { + case 0: + l.Add(key, key) + case 1: + l.Get(key) + case 2: + l.Remove(key) + } + + if l.recent.Len()+l.frequent.Len() > size { + t.Fatalf("bad: recent: %d freq: %d", + l.recent.Len(), l.frequent.Len()) + } + } +} + +func Test2Q_Get_RecentToFrequent(t *testing.T) { + l, err := New2Q(128) + if err != nil { + t.Fatalf("err: %v", err) + } + + // Touch all the entries, should be in t1 + for i := 0; i < 128; i++ { + l.Add(i, i) + } + if n := l.recent.Len(); n != 128 { + t.Fatalf("bad: %d", n) + } + if n := l.frequent.Len(); n != 0 { + t.Fatalf("bad: %d", n) + } + + // Get should upgrade to t2 + for i := 0; i < 128; i++ { + _, ok := l.Get(i) + if !ok { + t.Fatalf("missing: %d", i) + } + } + if n := l.recent.Len(); n != 0 { + t.Fatalf("bad: %d", n) + } + if n := l.frequent.Len(); n != 128 { + t.Fatalf("bad: %d", n) + } + + // Get be from t2 + for i := 0; i < 128; i++ { + _, ok := l.Get(i) + if !ok { + t.Fatalf("missing: %d", i) + } + } + if n := l.recent.Len(); n != 0 { + t.Fatalf("bad: %d", n) + } + if n := l.frequent.Len(); n != 128 { + t.Fatalf("bad: %d", n) + } +} + +func Test2Q_Add_RecentToFrequent(t *testing.T) { + l, err := New2Q(128) + if err != nil { + t.Fatalf("err: %v", err) + } + + // Add initially to recent + l.Add(1, 1) + if n := l.recent.Len(); n != 1 { + t.Fatalf("bad: %d", n) + } + if n := l.frequent.Len(); n != 0 { + t.Fatalf("bad: %d", n) + } + + // Add should upgrade to frequent + l.Add(1, 1) + if n := l.recent.Len(); n != 0 { + t.Fatalf("bad: %d", n) + } + if n := l.frequent.Len(); n != 1 { + t.Fatalf("bad: %d", n) + } + + // Add should remain in frequent + l.Add(1, 1) + if n := l.recent.Len(); n != 0 { + t.Fatalf("bad: %d", n) + } + if n := l.frequent.Len(); n != 1 { + t.Fatalf("bad: %d", n) + } +} + +func Test2Q_Add_RecentEvict(t *testing.T) { + l, err := New2Q(4) + if err != nil { + t.Fatalf("err: %v", err) + } + + // Add 1,2,3,4,5 -> Evict 1 + l.Add(1, 1) + l.Add(2, 2) + l.Add(3, 3) + l.Add(4, 4) + l.Add(5, 5) + if n := l.recent.Len(); n != 4 { + t.Fatalf("bad: %d", n) + } + if n := l.recentEvict.Len(); n != 1 { + t.Fatalf("bad: %d", n) + } + if n := l.frequent.Len(); n != 0 { + t.Fatalf("bad: %d", n) + } + + // Pull in the recently evicted + l.Add(1, 1) + if n := l.recent.Len(); n != 3 { + t.Fatalf("bad: %d", n) + } + if n := l.recentEvict.Len(); n != 1 { + t.Fatalf("bad: %d", n) + } + if n := l.frequent.Len(); n != 1 { + t.Fatalf("bad: %d", n) + } + + // Add 6, should cause another recent evict + l.Add(6, 6) + if n := l.recent.Len(); n != 3 { + t.Fatalf("bad: %d", n) + } + if n := l.recentEvict.Len(); n != 2 { + t.Fatalf("bad: %d", n) + } + if n := l.frequent.Len(); n != 1 { + t.Fatalf("bad: %d", n) + } +} + +func Test2Q(t *testing.T) { + l, err := New2Q(128) + if err != nil { + t.Fatalf("err: %v", err) + } + + for i := 0; i < 256; i++ { + l.Add(i, i) + } + if l.Len() != 128 { + t.Fatalf("bad len: %v", l.Len()) + } + + for i, k := range l.Keys() { + if v, ok := l.Get(k); !ok || v != k || v != i+128 { + t.Fatalf("bad key: %v", k) + } + } + for i := 0; i < 128; i++ { + _, ok := l.Get(i) + if ok { + t.Fatalf("should be evicted") + } + } + for i := 128; i < 256; i++ { + _, ok := l.Get(i) + if !ok { + t.Fatalf("should not be evicted") + } + } + for i := 128; i < 192; i++ { + l.Remove(i) + _, ok := l.Get(i) + if ok { + t.Fatalf("should be deleted") + } + } + + l.Purge() + if l.Len() != 0 { + t.Fatalf("bad len: %v", l.Len()) + } + if _, ok := l.Get(200); ok { + t.Fatalf("should contain nothing") + } +} + +// Test that Contains doesn't update recent-ness +func Test2Q_Contains(t *testing.T) { + l, err := New2Q(2) + if err != nil { + t.Fatalf("err: %v", err) + } + + l.Add(1, 1) + l.Add(2, 2) + if !l.Contains(1) { + t.Errorf("1 should be contained") + } + + l.Add(3, 3) + if l.Contains(1) { + t.Errorf("Contains should not have updated recent-ness of 1") + } +} + +// Test that Peek doesn't update recent-ness +func Test2Q_Peek(t *testing.T) { + l, err := New2Q(2) + if err != nil { + t.Fatalf("err: %v", err) + } + + l.Add(1, 1) + l.Add(2, 2) + if v, ok := l.Peek(1); !ok || v != 1 { + t.Errorf("1 should be set to 1: %v, %v", v, ok) + } + + l.Add(3, 3) + if l.Contains(1) { + t.Errorf("should not have updated recent-ness of 1") + } +} diff --git a/third_party/github.com/hashicorp/golang-lru/arc_test.go b/third_party/github.com/hashicorp/golang-lru/arc_test.go new file mode 100644 index 00000000000..e2d9b68c6ae --- /dev/null +++ b/third_party/github.com/hashicorp/golang-lru/arc_test.go @@ -0,0 +1,377 @@ +package lru + +import ( + "math/rand" + "testing" + "time" +) + +func init() { + rand.Seed(time.Now().Unix()) +} + +func BenchmarkARC_Rand(b *testing.B) { + l, err := NewARC(8192) + if err != nil { + b.Fatalf("err: %v", err) + } + + trace := make([]int64, b.N*2) + for i := 0; i < b.N*2; i++ { + trace[i] = rand.Int63() % 32768 + } + + b.ResetTimer() + + var hit, miss int + for i := 0; i < 2*b.N; i++ { + if i%2 == 0 { + l.Add(trace[i], trace[i]) + } else { + _, ok := l.Get(trace[i]) + if ok { + hit++ + } else { + miss++ + } + } + } + b.Logf("hit: %d miss: %d ratio: %f", hit, miss, float64(hit)/float64(miss)) +} + +func BenchmarkARC_Freq(b *testing.B) { + l, err := NewARC(8192) + if err != nil { + b.Fatalf("err: %v", err) + } + + trace := make([]int64, b.N*2) + for i := 0; i < b.N*2; i++ { + if i%2 == 0 { + trace[i] = rand.Int63() % 16384 + } else { + trace[i] = rand.Int63() % 32768 + } + } + + b.ResetTimer() + + for i := 0; i < b.N; i++ { + l.Add(trace[i], trace[i]) + } + var hit, miss int + for i := 0; i < b.N; i++ { + _, ok := l.Get(trace[i]) + if ok { + hit++ + } else { + miss++ + } + } + b.Logf("hit: %d miss: %d ratio: %f", hit, miss, float64(hit)/float64(miss)) +} + +func TestARC_RandomOps(t *testing.T) { + size := 128 + l, err := NewARC(128) + if err != nil { + t.Fatalf("err: %v", err) + } + + n := 200000 + for i := 0; i < n; i++ { + key := rand.Int63() % 512 + r := rand.Int63() + switch r % 3 { + case 0: + l.Add(key, key) + case 1: + l.Get(key) + case 2: + l.Remove(key) + } + + if l.t1.Len()+l.t2.Len() > size { + t.Fatalf("bad: t1: %d t2: %d b1: %d b2: %d p: %d", + l.t1.Len(), l.t2.Len(), l.b1.Len(), l.b2.Len(), l.p) + } + if l.b1.Len()+l.b2.Len() > size { + t.Fatalf("bad: t1: %d t2: %d b1: %d b2: %d p: %d", + l.t1.Len(), l.t2.Len(), l.b1.Len(), l.b2.Len(), l.p) + } + } +} + +func TestARC_Get_RecentToFrequent(t *testing.T) { + l, err := NewARC(128) + if err != nil { + t.Fatalf("err: %v", err) + } + + // Touch all the entries, should be in t1 + for i := 0; i < 128; i++ { + l.Add(i, i) + } + if n := l.t1.Len(); n != 128 { + t.Fatalf("bad: %d", n) + } + if n := l.t2.Len(); n != 0 { + t.Fatalf("bad: %d", n) + } + + // Get should upgrade to t2 + for i := 0; i < 128; i++ { + _, ok := l.Get(i) + if !ok { + t.Fatalf("missing: %d", i) + } + } + if n := l.t1.Len(); n != 0 { + t.Fatalf("bad: %d", n) + } + if n := l.t2.Len(); n != 128 { + t.Fatalf("bad: %d", n) + } + + // Get be from t2 + for i := 0; i < 128; i++ { + _, ok := l.Get(i) + if !ok { + t.Fatalf("missing: %d", i) + } + } + if n := l.t1.Len(); n != 0 { + t.Fatalf("bad: %d", n) + } + if n := l.t2.Len(); n != 128 { + t.Fatalf("bad: %d", n) + } +} + +func TestARC_Add_RecentToFrequent(t *testing.T) { + l, err := NewARC(128) + if err != nil { + t.Fatalf("err: %v", err) + } + + // Add initially to t1 + l.Add(1, 1) + if n := l.t1.Len(); n != 1 { + t.Fatalf("bad: %d", n) + } + if n := l.t2.Len(); n != 0 { + t.Fatalf("bad: %d", n) + } + + // Add should upgrade to t2 + l.Add(1, 1) + if n := l.t1.Len(); n != 0 { + t.Fatalf("bad: %d", n) + } + if n := l.t2.Len(); n != 1 { + t.Fatalf("bad: %d", n) + } + + // Add should remain in t2 + l.Add(1, 1) + if n := l.t1.Len(); n != 0 { + t.Fatalf("bad: %d", n) + } + if n := l.t2.Len(); n != 1 { + t.Fatalf("bad: %d", n) + } +} + +func TestARC_Adaptive(t *testing.T) { + l, err := NewARC(4) + if err != nil { + t.Fatalf("err: %v", err) + } + + // Fill t1 + for i := 0; i < 4; i++ { + l.Add(i, i) + } + if n := l.t1.Len(); n != 4 { + t.Fatalf("bad: %d", n) + } + + // Move to t2 + l.Get(0) + l.Get(1) + if n := l.t2.Len(); n != 2 { + t.Fatalf("bad: %d", n) + } + + // Evict from t1 + l.Add(4, 4) + if n := l.b1.Len(); n != 1 { + t.Fatalf("bad: %d", n) + } + + // Current state + // t1 : (MRU) [4, 3] (LRU) + // t2 : (MRU) [1, 0] (LRU) + // b1 : (MRU) [2] (LRU) + // b2 : (MRU) [] (LRU) + + // Add 2, should cause hit on b1 + l.Add(2, 2) + if n := l.b1.Len(); n != 1 { + t.Fatalf("bad: %d", n) + } + if l.p != 1 { + t.Fatalf("bad: %d", l.p) + } + if n := l.t2.Len(); n != 3 { + t.Fatalf("bad: %d", n) + } + + // Current state + // t1 : (MRU) [4] (LRU) + // t2 : (MRU) [2, 1, 0] (LRU) + // b1 : (MRU) [3] (LRU) + // b2 : (MRU) [] (LRU) + + // Add 4, should migrate to t2 + l.Add(4, 4) + if n := l.t1.Len(); n != 0 { + t.Fatalf("bad: %d", n) + } + if n := l.t2.Len(); n != 4 { + t.Fatalf("bad: %d", n) + } + + // Current state + // t1 : (MRU) [] (LRU) + // t2 : (MRU) [4, 2, 1, 0] (LRU) + // b1 : (MRU) [3] (LRU) + // b2 : (MRU) [] (LRU) + + // Add 4, should evict to b2 + l.Add(5, 5) + if n := l.t1.Len(); n != 1 { + t.Fatalf("bad: %d", n) + } + if n := l.t2.Len(); n != 3 { + t.Fatalf("bad: %d", n) + } + if n := l.b2.Len(); n != 1 { + t.Fatalf("bad: %d", n) + } + + // Current state + // t1 : (MRU) [5] (LRU) + // t2 : (MRU) [4, 2, 1] (LRU) + // b1 : (MRU) [3] (LRU) + // b2 : (MRU) [0] (LRU) + + // Add 0, should decrease p + l.Add(0, 0) + if n := l.t1.Len(); n != 0 { + t.Fatalf("bad: %d", n) + } + if n := l.t2.Len(); n != 4 { + t.Fatalf("bad: %d", n) + } + if n := l.b1.Len(); n != 2 { + t.Fatalf("bad: %d", n) + } + if n := l.b2.Len(); n != 0 { + t.Fatalf("bad: %d", n) + } + if l.p != 0 { + t.Fatalf("bad: %d", l.p) + } + + // Current state + // t1 : (MRU) [] (LRU) + // t2 : (MRU) [0, 4, 2, 1] (LRU) + // b1 : (MRU) [5, 3] (LRU) + // b2 : (MRU) [0] (LRU) +} + +func TestARC(t *testing.T) { + l, err := NewARC(128) + if err != nil { + t.Fatalf("err: %v", err) + } + + for i := 0; i < 256; i++ { + l.Add(i, i) + } + if l.Len() != 128 { + t.Fatalf("bad len: %v", l.Len()) + } + + for i, k := range l.Keys() { + if v, ok := l.Get(k); !ok || v != k || v != i+128 { + t.Fatalf("bad key: %v", k) + } + } + for i := 0; i < 128; i++ { + _, ok := l.Get(i) + if ok { + t.Fatalf("should be evicted") + } + } + for i := 128; i < 256; i++ { + _, ok := l.Get(i) + if !ok { + t.Fatalf("should not be evicted") + } + } + for i := 128; i < 192; i++ { + l.Remove(i) + _, ok := l.Get(i) + if ok { + t.Fatalf("should be deleted") + } + } + + l.Purge() + if l.Len() != 0 { + t.Fatalf("bad len: %v", l.Len()) + } + if _, ok := l.Get(200); ok { + t.Fatalf("should contain nothing") + } +} + +// Test that Contains doesn't update recent-ness +func TestARC_Contains(t *testing.T) { + l, err := NewARC(2) + if err != nil { + t.Fatalf("err: %v", err) + } + + l.Add(1, 1) + l.Add(2, 2) + if !l.Contains(1) { + t.Errorf("1 should be contained") + } + + l.Add(3, 3) + if l.Contains(1) { + t.Errorf("Contains should not have updated recent-ness of 1") + } +} + +// Test that Peek doesn't update recent-ness +func TestARC_Peek(t *testing.T) { + l, err := NewARC(2) + if err != nil { + t.Fatalf("err: %v", err) + } + + l.Add(1, 1) + l.Add(2, 2) + if v, ok := l.Peek(1); !ok || v != 1 { + t.Errorf("1 should be set to 1: %v, %v", v, ok) + } + + l.Add(3, 3) + if l.Contains(1) { + t.Errorf("should not have updated recent-ness of 1") + } +} diff --git a/third_party/github.com/hashicorp/golang-lru/lru_test.go b/third_party/github.com/hashicorp/golang-lru/lru_test.go new file mode 100644 index 00000000000..710b045334b --- /dev/null +++ b/third_party/github.com/hashicorp/golang-lru/lru_test.go @@ -0,0 +1,260 @@ +package lru + +import ( + "math/rand" + "testing" +) + +func BenchmarkLRU_Rand(b *testing.B) { + l, err := New(8192) + if err != nil { + b.Fatalf("err: %v", err) + } + + trace := make([]int64, b.N*2) + for i := 0; i < b.N*2; i++ { + trace[i] = rand.Int63() % 32768 + } + + b.ResetTimer() + + var hit, miss int + for i := 0; i < 2*b.N; i++ { + if i%2 == 0 { + l.Add(trace[i], trace[i]) + } else { + _, ok := l.Get(trace[i]) + if ok { + hit++ + } else { + miss++ + } + } + } + b.Logf("hit: %d miss: %d ratio: %f", hit, miss, float64(hit)/float64(miss)) +} + +func BenchmarkLRU_Freq(b *testing.B) { + l, err := New(8192) + if err != nil { + b.Fatalf("err: %v", err) + } + + trace := make([]int64, b.N*2) + for i := 0; i < b.N*2; i++ { + if i%2 == 0 { + trace[i] = rand.Int63() % 16384 + } else { + trace[i] = rand.Int63() % 32768 + } + } + + b.ResetTimer() + + for i := 0; i < b.N; i++ { + l.Add(trace[i], trace[i]) + } + var hit, miss int + for i := 0; i < b.N; i++ { + _, ok := l.Get(trace[i]) + if ok { + hit++ + } else { + miss++ + } + } + b.Logf("hit: %d miss: %d ratio: %f", hit, miss, float64(hit)/float64(miss)) +} + +func TestLRU(t *testing.T) { + evictCounter := 0 + onEvicted := func(k interface{}, v interface{}) { + if k != v { + t.Fatalf("Evict values not equal (%v!=%v)", k, v) + } + evictCounter++ + } + l, err := NewWithEvict(128, onEvicted) + if err != nil { + t.Fatalf("err: %v", err) + } + + for i := 0; i < 256; i++ { + l.Add(i, i) + } + if l.Len() != 128 { + t.Fatalf("bad len: %v", l.Len()) + } + + if evictCounter != 128 { + t.Fatalf("bad evict count: %v", evictCounter) + } + + for i, k := range l.Keys() { + if v, ok := l.Get(k); !ok || v != k || v != i+128 { + t.Fatalf("bad key: %v", k) + } + } + for i := 0; i < 128; i++ { + _, ok := l.Get(i) + if ok { + t.Fatalf("should be evicted") + } + } + for i := 128; i < 256; i++ { + _, ok := l.Get(i) + if !ok { + t.Fatalf("should not be evicted") + } + } + for i := 128; i < 192; i++ { + l.Remove(i) + _, ok := l.Get(i) + if ok { + t.Fatalf("should be deleted") + } + } + + l.Get(192) // expect 192 to be last key in l.Keys() + + for i, k := range l.Keys() { + if (i < 63 && k != i+193) || (i == 63 && k != 192) { + t.Fatalf("out of order key: %v", k) + } + } + + l.Purge() + if l.Len() != 0 { + t.Fatalf("bad len: %v", l.Len()) + } + if _, ok := l.Get(200); ok { + t.Fatalf("should contain nothing") + } +} + +// test that Add returns true/false if an eviction occurred +func TestLRUAdd(t *testing.T) { + evictCounter := 0 + onEvicted := func(k interface{}, v interface{}) { + evictCounter++ + } + + l, err := NewWithEvict(1, onEvicted) + if err != nil { + t.Fatalf("err: %v", err) + } + + if l.Add(1, 1) == true || evictCounter != 0 { + t.Errorf("should not have an eviction") + } + if l.Add(2, 2) == false || evictCounter != 1 { + t.Errorf("should have an eviction") + } +} + +// test that Contains doesn't update recent-ness +func TestLRUContains(t *testing.T) { + l, err := New(2) + if err != nil { + t.Fatalf("err: %v", err) + } + + l.Add(1, 1) + l.Add(2, 2) + if !l.Contains(1) { + t.Errorf("1 should be contained") + } + + l.Add(3, 3) + if l.Contains(1) { + t.Errorf("Contains should not have updated recent-ness of 1") + } +} + +// test that Contains doesn't update recent-ness +func TestLRUContainsOrAdd(t *testing.T) { + l, err := New(2) + if err != nil { + t.Fatalf("err: %v", err) + } + + l.Add(1, 1) + l.Add(2, 2) + contains, evict := l.ContainsOrAdd(1, 1) + if !contains { + t.Errorf("1 should be contained") + } + if evict { + t.Errorf("nothing should be evicted here") + } + + l.Add(3, 3) + contains, evict = l.ContainsOrAdd(1, 1) + if contains { + t.Errorf("1 should not have been contained") + } + if !evict { + t.Errorf("an eviction should have occurred") + } + if !l.Contains(1) { + t.Errorf("now 1 should be contained") + } +} + +// test that Peek doesn't update recent-ness +func TestLRUPeek(t *testing.T) { + l, err := New(2) + if err != nil { + t.Fatalf("err: %v", err) + } + + l.Add(1, 1) + l.Add(2, 2) + if v, ok := l.Peek(1); !ok || v != 1 { + t.Errorf("1 should be set to 1: %v, %v", v, ok) + } + + l.Add(3, 3) + if l.Contains(1) { + t.Errorf("should not have updated recent-ness of 1") + } +} + +// test that Resize can upsize and downsize +func TestLRUResize(t *testing.T) { + onEvictCounter := 0 + onEvicted := func(k interface{}, v interface{}) { + onEvictCounter++ + } + l, err := NewWithEvict(2, onEvicted) + if err != nil { + t.Fatalf("err: %v", err) + } + + // Downsize + l.Add(1, 1) + l.Add(2, 2) + evicted := l.Resize(1); + if evicted != 1 { + t.Errorf("1 element should have been evicted: %v", evicted) + } + if onEvictCounter != 1 { + t.Errorf("onEvicted should have been called 1 time: %v", onEvictCounter) + } + + l.Add(3, 3) + if l.Contains(1) { + t.Errorf("Element 1 should have been evicted") + } + + // Upsize + evicted = l.Resize(2); + if evicted != 0 { + t.Errorf("0 elements should have been evicted: %v", evicted) + } + + l.Add(4, 4) + if !l.Contains(3) || !l.Contains(4) { + t.Errorf("Cache should have contained 2 elements") + } +} diff --git a/third_party/github.com/hashicorp/golang-lru/simplelru/lru_test.go b/third_party/github.com/hashicorp/golang-lru/simplelru/lru_test.go new file mode 100644 index 00000000000..bc7f696cc74 --- /dev/null +++ b/third_party/github.com/hashicorp/golang-lru/simplelru/lru_test.go @@ -0,0 +1,206 @@ +package simplelru + +import "testing" + +func TestLRU(t *testing.T) { + evictCounter := 0 + onEvicted := func(k interface{}, v interface{}) { + if k != v { + t.Fatalf("Evict values not equal (%v!=%v)", k, v) + } + evictCounter++ + } + l, err := NewLRU(128, onEvicted) + if err != nil { + t.Fatalf("err: %v", err) + } + + for i := 0; i < 256; i++ { + l.Add(i, i) + } + if l.Len() != 128 { + t.Fatalf("bad len: %v", l.Len()) + } + + if evictCounter != 128 { + t.Fatalf("bad evict count: %v", evictCounter) + } + + for i, k := range l.Keys() { + if v, ok := l.Get(k); !ok || v != k || v != i+128 { + t.Fatalf("bad key: %v", k) + } + } + for i := 0; i < 128; i++ { + _, ok := l.Get(i) + if ok { + t.Fatalf("should be evicted") + } + } + for i := 128; i < 256; i++ { + _, ok := l.Get(i) + if !ok { + t.Fatalf("should not be evicted") + } + } + for i := 128; i < 192; i++ { + ok := l.Remove(i) + if !ok { + t.Fatalf("should be contained") + } + ok = l.Remove(i) + if ok { + t.Fatalf("should not be contained") + } + _, ok = l.Get(i) + if ok { + t.Fatalf("should be deleted") + } + } + + l.Get(192) // expect 192 to be last key in l.Keys() + + for i, k := range l.Keys() { + if (i < 63 && k != i+193) || (i == 63 && k != 192) { + t.Fatalf("out of order key: %v", k) + } + } + + l.Purge() + if l.Len() != 0 { + t.Fatalf("bad len: %v", l.Len()) + } + if _, ok := l.Get(200); ok { + t.Fatalf("should contain nothing") + } +} + +func TestLRU_GetOldest_RemoveOldest(t *testing.T) { + l, err := NewLRU(128, nil) + if err != nil { + t.Fatalf("err: %v", err) + } + for i := 0; i < 256; i++ { + l.Add(i, i) + } + k, _, ok := l.GetOldest() + if !ok { + t.Fatalf("missing") + } + if k.(int) != 128 { + t.Fatalf("bad: %v", k) + } + + k, _, ok = l.RemoveOldest() + if !ok { + t.Fatalf("missing") + } + if k.(int) != 128 { + t.Fatalf("bad: %v", k) + } + + k, _, ok = l.RemoveOldest() + if !ok { + t.Fatalf("missing") + } + if k.(int) != 129 { + t.Fatalf("bad: %v", k) + } +} + +// Test that Add returns true/false if an eviction occurred +func TestLRU_Add(t *testing.T) { + evictCounter := 0 + onEvicted := func(k interface{}, v interface{}) { + evictCounter++ + } + + l, err := NewLRU(1, onEvicted) + if err != nil { + t.Fatalf("err: %v", err) + } + + if l.Add(1, 1) == true || evictCounter != 0 { + t.Errorf("should not have an eviction") + } + if l.Add(2, 2) == false || evictCounter != 1 { + t.Errorf("should have an eviction") + } +} + +// Test that Contains doesn't update recent-ness +func TestLRU_Contains(t *testing.T) { + l, err := NewLRU(2, nil) + if err != nil { + t.Fatalf("err: %v", err) + } + + l.Add(1, 1) + l.Add(2, 2) + if !l.Contains(1) { + t.Errorf("1 should be contained") + } + + l.Add(3, 3) + if l.Contains(1) { + t.Errorf("Contains should not have updated recent-ness of 1") + } +} + +// Test that Peek doesn't update recent-ness +func TestLRU_Peek(t *testing.T) { + l, err := NewLRU(2, nil) + if err != nil { + t.Fatalf("err: %v", err) + } + + l.Add(1, 1) + l.Add(2, 2) + if v, ok := l.Peek(1); !ok || v != 1 { + t.Errorf("1 should be set to 1: %v, %v", v, ok) + } + + l.Add(3, 3) + if l.Contains(1) { + t.Errorf("should not have updated recent-ness of 1") + } +} + +// Test that Resize can upsize and downsize +func TestLRU_Resize(t *testing.T) { + onEvictCounter := 0 + onEvicted := func(k interface{}, v interface{}) { + onEvictCounter++ + } + l, err := NewLRU(2, onEvicted) + if err != nil { + t.Fatalf("err: %v", err) + } + + // Downsize + l.Add(1, 1) + l.Add(2, 2) + evicted := l.Resize(1); + if evicted != 1 { + t.Errorf("1 element should have been evicted: %v", evicted) + } + if onEvictCounter != 1 { + t.Errorf("onEvicted should have been called 1 time: %v", onEvictCounter) + } + + l.Add(3, 3) + if l.Contains(1) { + t.Errorf("Element 1 should have been evicted") + } + + // Upsize + evicted = l.Resize(2); + if evicted != 0 { + t.Errorf("0 elements should have been evicted: %v", evicted) + } + + l.Add(4, 4) + if !l.Contains(3) || !l.Contains(4) { + t.Errorf("Cache should have contained 2 elements") + } +}