diff --git a/config/200-clusterrole.yaml b/config/200-clusterrole.yaml index 659d06ec48f..ac718119377 100644 --- a/config/200-clusterrole.yaml +++ b/config/200-clusterrole.yaml @@ -31,13 +31,13 @@ rules: # Controller needs cluster access to all of the CRDs that it is responsible for # managing. - apiGroups: ["tekton.dev"] - resources: ["tasks", "clustertasks", "taskruns", "pipelines", "pipelineruns", "pipelineresources", "conditions"] + resources: ["tasks", "clustertasks", "taskruns", "pipelines", "pipelineruns", "pipelineresources", "conditions", "runs"] verbs: ["get", "list", "create", "update", "delete", "patch", "watch"] - apiGroups: ["tekton.dev"] - resources: ["taskruns/finalizers", "pipelineruns/finalizers"] + resources: ["taskruns/finalizers", "pipelineruns/finalizers", "runs/finalizers"] verbs: ["get", "list", "create", "update", "delete", "patch", "watch"] - apiGroups: ["tekton.dev"] - resources: ["tasks/status", "clustertasks/status", "taskruns/status", "pipelines/status", "pipelineruns/status", "pipelineresources/status"] + resources: ["tasks/status", "clustertasks/status", "taskruns/status", "pipelines/status", "pipelineruns/status", "pipelineresources/status", "runs/status"] verbs: ["get", "list", "create", "update", "delete", "patch", "watch"] --- kind: ClusterRole diff --git a/go.mod b/go.mod index 9d9dede494f..32c87b239d7 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( contrib.go.opencensus.io/exporter/stackdriver v0.13.1 // indirect github.com/GoogleCloudPlatform/cloud-builders/gcs-fetcher v0.0.0-20191203181535-308b93ad1f39 github.com/cloudevents/sdk-go/v2 v2.1.0 - github.com/docker/cli v0.0.0-20200210162036-a4bedce16568 // indirect + github.com/docker/cli v0.0.0-20200303162255-7d407207c304 // indirect github.com/ghodss/yaml v1.0.0 github.com/google/go-cmp v0.4.1 github.com/google/go-containerregistry v0.1.1 @@ -26,6 +26,7 @@ require ( golang.org/x/text v0.3.3 // indirect gomodules.xyz/jsonpatch/v2 v2.1.0 google.golang.org/api v0.25.0 + gotest.tools/v3 v3.0.2 // indirect k8s.io/api v0.17.6 k8s.io/apimachinery v0.17.6 k8s.io/client-go v11.0.1-0.20190805182717-6502b5e7b1b5+incompatible diff --git a/go.sum b/go.sum index ccb0dd02153..65492bec3b9 100644 --- a/go.sum +++ b/go.sum @@ -137,6 +137,7 @@ github.com/Masterminds/semver/v3 v3.1.0/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0 github.com/Masterminds/sprig/v3 v3.0.2/go.mod h1:oesJ8kPONMONaZgtiHNzUShJbksypC5kWczhZAf6+aU= github.com/Masterminds/vcs v1.13.1/go.mod h1:N09YCmOQr6RLxC6UNHzuVwAdodYbbnycGHSmwVJjcKA= github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5 h1:ygIc8M6trr62pF5DucadTWGdEB4mEyvzi0e2nbcmcyA= github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= @@ -295,8 +296,8 @@ github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyG github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017 h1:2HQmlpI3yI9deH18Q6xiSOIjXD4sLI55Y/gfpa8/558= github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/cli v0.0.0-20200130152716-5d0cf8839492/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= -github.com/docker/cli v0.0.0-20200210162036-a4bedce16568 h1:AbI1uj9w4yt6TvfKHfRu7G55KuQe7NCvWPQRKDoXggE= -github.com/docker/cli v0.0.0-20200210162036-a4bedce16568/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v0.0.0-20200303162255-7d407207c304 h1:A7SYzidcyuQ/yS4wezWGYeUioUFJQk8HYWY9aMYTF4I= +github.com/docker/cli v0.0.0-20200303162255-7d407207c304/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v0.0.0-20191216044856-a8371794149d/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY= github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug= github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= @@ -618,6 +619,7 @@ github.com/gostaticanalysis/analysisutil v0.0.0-20190318220348-4088753ea4d3/go.m github.com/gostaticanalysis/analysisutil v0.0.3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE= github.com/gosuri/uitable v0.0.4/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/gregjones/httpcache v0.0.0-20190212212710-3befbb6ad0cc h1:f8eY6cV/x1x+HLjOp4r72s/31/V2aTUtg5oKRRPf8/Q= github.com/gregjones/httpcache v0.0.0-20190212212710-3befbb6ad0cc/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= @@ -662,6 +664,7 @@ github.com/hashicorp/golang-lru v0.5.3 h1:YPkqC67at8FYaadspW/6uE0COsBxS2656RLEr8 github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= @@ -757,6 +760,7 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= github.com/lightstep/tracecontext.go v0.0.0-20181129014701-1757c391b1ac h1:+2b6iGRJe3hvV/yVXrd41yVEjxuFHxasJqDhkIjS4gk= github.com/lightstep/tracecontext.go v0.0.0-20181129014701-1757c391b1ac/go.mod h1:Frd2bnT3w5FB5q49ENTfVlztJES+1k/7lyWX2+9gq/M= @@ -764,6 +768,7 @@ github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -822,6 +827,7 @@ github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0Qu github.com/mitchellh/ioprogress v0.0.0-20180201004757-6a23b12fa88e/go.mod h1:waEya8ee1Ro/lgxpVhkJI4BVASzkm3UZqkx/cFJiYHM= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.3.1 h1:cCBH2gTD2K0OtLlv/Y5H01VQCqmlDxz30kS5Y5bqfLA= github.com/mitchellh/mapstructure v1.3.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= @@ -908,6 +914,7 @@ github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtP github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys= +github.com/pelletier/go-toml v1.8.0 h1:Keo9qb7iRJs2voHvunFtuuYFsbWeOBh8/P9v/kVMFtw= github.com/pelletier/go-toml v1.8.0/go.mod h1:D6yutnOGMveHEPV7VQOuvI/gXY61bv+9bAOTRnLElKs= github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= @@ -1033,16 +1040,20 @@ github.com/sourcegraph/go-diff v0.5.1/go.mod h1:j2dHj3m8aZgQO8lMTcTnBcXkRRRqi34c github.com/sourcegraph/go-diff v0.5.3/go.mod h1:v9JDtjCE4HHHCZGId75rg8gkKKa98RVjBcBGsVmMmak= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8= github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= @@ -1054,6 +1065,7 @@ github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DM github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/spf13/viper v1.6.1/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k= github.com/spf13/viper v1.6.2/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k= +github.com/spf13/viper v1.7.0 h1:xVKxvI7ouOI5I+U9s2eeiUfMaWBVoXA3AWskkrqK0VM= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/src-d/gcfg v1.4.0 h1:xXbNR5AlLSA315x2UO+fTSSAXCDf+Ar38/6oyGbDKQ4= github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI= @@ -1068,6 +1080,7 @@ github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJy github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/tdakkota/asciicheck v0.0.0-20200416190851-d7f85be797a2/go.mod h1:yHp0ai0Z9gUljN3o0xMhYJnH/IcvkdTBOX2fmJ93JEM= @@ -1410,6 +1423,7 @@ golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= golang.org/x/tools v0.0.0-20190719005602-e377ae9d6386/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= @@ -1601,6 +1615,7 @@ gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.46.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.52.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.56.0 h1:DPMeDvGTM54DXbPkVIZsp19fp/I2K7zwA/itHYHKo8Y= gopkg.in/ini.v1 v1.56.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/jcmturner/aescts.v1 v1.0.1/go.mod h1:nsR8qBOg+OucoIW+WMhB3GspUQXq9XorLnQb9XtvcOo= gopkg.in/jcmturner/dnsutils.v1 v1.0.1/go.mod h1:m3v+5svpVOhtFAP/wSz+yzh4Mc0Fg7eRhxkJMWSIz9Q= @@ -1631,6 +1646,8 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20190709130402-674ba3eaed22/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +gotest.tools/v3 v3.0.2 h1:kG1BFyqVHuQoVQiR1bWGnfz/fmHvvuiSPIV7rvl360E= +gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= helm.sh/helm/v3 v3.1.1/go.mod h1:WYsFJuMASa/4XUqLyv54s0U/f3mlAaRErGmyy4z921g= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -1651,6 +1668,7 @@ k8s.io/apimachinery v0.17.6 h1:P0MNfucrmKLPsOSRbhDuG0Tplrpg7hVY4fJHh5sUIUw= k8s.io/apimachinery v0.17.6/go.mod h1:Lg8zZ5iC/O8UjCqW6DNhcQG2m4TdjF9kwG3891OWbbA= k8s.io/apiserver v0.17.6/go.mod h1:sAYqm8hUDNA9aj/TzqwsJoExWrxprKv0tqs/z88qym0= k8s.io/cli-runtime v0.17.2/go.mod h1:aa8t9ziyQdbkuizkNLAw3qe3srSyWh9zlSB7zTqRNPI= +k8s.io/cli-runtime v0.17.3 h1:0ZlDdJgJBKsu77trRUynNiWsRuAvAVPBNaQfnt/1qtc= k8s.io/cli-runtime v0.17.3/go.mod h1:X7idckYphH4SZflgNpOOViSxetiMj6xI0viMAjM81TA= k8s.io/client-go v0.17.6 h1:W/JkbAcIZUPb9vENRTC75ymjQQO3qEJAZyYhOIEOifM= k8s.io/client-go v0.17.6/go.mod h1:tX5eAbQR/Kbqv+5R93rzHQoyRnPjjW2mm9i0lXnW218= @@ -1710,6 +1728,7 @@ rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/boskos v0.0.0-20200530174753-71e795271860/go.mod h1:L1ubP7d1CCMSQSjKiZv6dGbh7b4kfoG+dFPj8cfYDnI= sigs.k8s.io/controller-runtime v0.5.0/go.mod h1:REiJzC7Y00U+2YkMbT8wxgrsX5USpXKGhb2sCtAXiT8= +sigs.k8s.io/kustomize v2.0.3+incompatible h1:JUufWFNlI44MdtnjUqVnvh29rR37PQFzPbLXqhyOyX0= sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU= sigs.k8s.io/structured-merge-diff/v2 v2.0.1/go.mod h1:Wb7vfKAodbKgf6tn1Kl0VvGj7mRH6DGaRcixXEJXTsE= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= diff --git a/pkg/apis/pipeline/v1beta1/pipeline_validation.go b/pkg/apis/pipeline/v1beta1/pipeline_validation.go index a82544ec1cc..9c867b80a8c 100644 --- a/pkg/apis/pipeline/v1beta1/pipeline_validation.go +++ b/pkg/apis/pipeline/v1beta1/pipeline_validation.go @@ -222,19 +222,23 @@ func validatePipelineTasks(ctx context.Context, tasks []PipelineTask, finalTasks taskNames := sets.NewString() var err *apis.FieldError for i, t := range tasks { - if err = validatePipelineTaskName(ctx, "spec.tasks", i, t, taskNames); err != nil { + if err = validatePipelineTask(ctx, "spec.tasks", i, t, taskNames); err != nil { return err } } for i, t := range finalTasks { - if err = validatePipelineTaskName(ctx, "spec.finally", i, t, taskNames); err != nil { + if err = validatePipelineTask(ctx, "spec.finally", i, t, taskNames); err != nil { return err } } return nil } -func validatePipelineTaskName(ctx context.Context, prefix string, i int, t PipelineTask, taskNames sets.String) *apis.FieldError { +func validatePipelineTask(ctx context.Context, prefix string, i int, t PipelineTask, taskNames sets.String) *apis.FieldError { + hasTaskRef := t.TaskRef != nil + hasTaskSpec := t.TaskSpec != nil + isCustomTask := hasTaskRef && t.TaskRef.APIVersion != "" + if errs := validation.IsDNS1123Label(t.Name); len(errs) > 0 { return &apis.FieldError{ Message: fmt.Sprintf("invalid value %q", t.Name), @@ -244,20 +248,28 @@ func validatePipelineTaskName(ctx context.Context, prefix string, i int, t Pipel } } // can't have both taskRef and taskSpec at the same time - if (t.TaskRef != nil && t.TaskRef.Name != "") && t.TaskSpec != nil { + if hasTaskRef && hasTaskSpec { return apis.ErrMultipleOneOf(fmt.Sprintf(prefix+"[%d].taskRef", i), fmt.Sprintf(prefix+"[%d].taskSpec", i)) } // Check that one of TaskRef and TaskSpec is present - if (t.TaskRef == nil || (t.TaskRef != nil && t.TaskRef.Name == "")) && t.TaskSpec == nil { + if !hasTaskRef && !hasTaskSpec { return apis.ErrMissingOneOf(fmt.Sprintf(prefix+"[%d].taskRef", i), fmt.Sprintf(prefix+"[%d].taskSpec", i)) } // Validate TaskSpec if it's present - if t.TaskSpec != nil { + if hasTaskSpec { if err := t.TaskSpec.Validate(ctx); err != nil { return err } } - if t.TaskRef != nil && t.TaskRef.Name != "" { + + // Check that PipelineTask names are unique. + if _, ok := taskNames[t.Name]; ok { + return apis.ErrMultipleOneOf(fmt.Sprintf(prefix+"[%d].name", i)) + } + taskNames[t.Name] = struct{}{} + + // Custom Task refs are allowed to have no name. + if hasTaskRef && t.TaskRef.Name != "" { // Task names are appended to the container name, which must exist and // must be a valid k8s name if errSlice := validation.IsQualifiedName(t.Name); len(errSlice) != 0 { @@ -267,11 +279,31 @@ func validatePipelineTaskName(ctx context.Context, prefix string, i int, t Pipel if errSlice := validation.IsQualifiedName(t.TaskRef.Name); len(errSlice) != 0 { return apis.ErrInvalidValue(strings.Join(errSlice, ","), fmt.Sprintf(prefix+"[%d].taskRef.name", i)) } - if _, ok := taskNames[t.Name]; ok { - return apis.ErrMultipleOneOf(fmt.Sprintf(prefix+"[%d].name", i)) + } + + if hasTaskRef && !isCustomTask && t.TaskRef.Name == "" { + return apis.ErrInvalidValue(t.TaskRef, "taskRef must specify name") + } + if isCustomTask && t.TaskRef.Kind == "" { + return apis.ErrInvalidValue(t.TaskRef, "custom task ref must specify apiVersion and kind") + } + + // TODO(#3133): Support these features if possible. + if isCustomTask { + if t.Retries > 0 { + return apis.ErrInvalidValue(t.Retries, "custom tasks do not support Retries") + } + if t.Resources != nil { + return apis.ErrInvalidValue(t.Resources, "custom tasks do not support PipelineResources") + } + if len(t.Workspaces) > 0 { + return apis.ErrInvalidValue(t.Workspaces, "custom tasks do not support Workspaces") + } + if t.Timeout != nil { + return apis.ErrInvalidValue(t.Timeout, "custom tasks do not support Timeout") } - taskNames[t.Name] = struct{}{} } + return nil } diff --git a/pkg/apis/pipeline/v1beta1/pipeline_validation_test.go b/pkg/apis/pipeline/v1beta1/pipeline_validation_test.go index 9615a56a07a..8ef7467f7e8 100644 --- a/pkg/apis/pipeline/v1beta1/pipeline_validation_test.go +++ b/pkg/apis/pipeline/v1beta1/pipeline_validation_test.go @@ -37,6 +37,13 @@ func TestPipeline_Validate_Success(t *testing.T) { Tasks: []PipelineTask{{Name: "foo", TaskRef: &TaskRef{Name: "foo-task"}}}, }, }, + }, { + name: "pipelinetask custom task references", + p: &Pipeline{ + Spec: PipelineSpec{ + Tasks: []PipelineTask{{Name: "foo", TaskRef: &TaskRef{APIVersion: "example.dev/v0", Kind: "Example", Name: ""}}}, + }, + }, }, { name: "valid pipeline with params, resources, workspaces, task results, and pipeline results", p: &Pipeline{ @@ -261,7 +268,7 @@ func TestValidatePipelineTasks_Success(t *testing.T) { } func TestValidatePipelineTasks_Failure(t *testing.T) { - tests := []struct { + for _, tc := range []struct { name string tasks []PipelineTask }{{ @@ -286,7 +293,7 @@ func TestValidatePipelineTasks_Failure(t *testing.T) { name: "pipeline tasks invalid (duplicate tasks)", tasks: []PipelineTask{ {Name: "foo", TaskRef: &TaskRef{Name: "foo-task"}}, - {Name: "foo", TaskRef: &TaskRef{Name: "foo-task"}}, + {Name: "foo", TaskRef: &TaskRef{APIVersion: "example.dev/v0", Kind: "Example"}}, }, }, { name: "pipeline task with empty task name", @@ -300,12 +307,48 @@ func TestValidatePipelineTasks_Failure(t *testing.T) { }, { name: "pipeline task with invalid taskref name", tasks: []PipelineTask{{Name: "foo", TaskRef: &TaskRef{Name: "_foo-task"}}}, - }} - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - err := validatePipelineTasks(context.Background(), tt.tasks, []PipelineTask{}) + }, { + name: "pipelinetask without name", + tasks: []PipelineTask{{Name: "", TaskRef: &TaskRef{Name: "valid-task"}}}, + }, { + name: "pipelinetask taskRef without name", + tasks: []PipelineTask{{Name: "foo", TaskRef: &TaskRef{Name: ""}}}, + }, { + name: "pipelinetask custom task taskRef without name", + tasks: []PipelineTask{{Name: "foo", TaskRef: &TaskRef{APIVersion: "example.dev/v0", Kind: "", Name: ""}}}, + }, { + name: "pipelinetask custom task doesn't support retries", + tasks: []PipelineTask{{ + Name: "foo", + Retries: 3, + TaskRef: &TaskRef{APIVersion: "example.dev/v0", Kind: "Example"}, + }}, + }, { + name: "pipelinetask custom task doesn't support pipeline resources", + tasks: []PipelineTask{{ + Name: "foo", + Resources: &PipelineTaskResources{}, + TaskRef: &TaskRef{APIVersion: "example.dev/v0", Kind: "Example"}, + }}, + }, { + name: "pipelinetask custom task doesn't support workspaces", + tasks: []PipelineTask{{ + Name: "foo", + Workspaces: []WorkspacePipelineTaskBinding{{}}, + TaskRef: &TaskRef{APIVersion: "example.dev/v0", Kind: "Example"}, + }}, + }, { + name: "pipelinetask custom task doesn't support timeout", + tasks: []PipelineTask{{ + Name: "foo", + Timeout: &metav1.Duration{time.Duration(3)}, + TaskRef: &TaskRef{APIVersion: "example.dev/v0", Kind: "Example"}, + }}, + }} { + t.Run(tc.name, func(t *testing.T) { + err := validatePipelineTasks(context.Background(), tc.tasks, []PipelineTask{}) if err == nil { - t.Error("Pipeline.validatePipelineTasks() did not return error for invalid pipeline tasks:", tt.name) + t.Error("Pipeline.validatePipelineTasks() did not return error for invalid pipeline tasks") } }) } diff --git a/pkg/apis/pipeline/v1beta1/pipelinerun_types.go b/pkg/apis/pipeline/v1beta1/pipelinerun_types.go index 267f5e19491..c7f79900ace 100644 --- a/pkg/apis/pipeline/v1beta1/pipelinerun_types.go +++ b/pkg/apis/pipeline/v1beta1/pipelinerun_types.go @@ -29,13 +29,11 @@ import ( duckv1beta1 "knative.dev/pkg/apis/duck/v1beta1" ) -var ( - groupVersionKind = schema.GroupVersionKind{ - Group: SchemeGroupVersion.Group, - Version: SchemeGroupVersion.Version, - Kind: pipeline.PipelineRunControllerName, - } -) +var groupVersionKind = schema.GroupVersionKind{ + Group: SchemeGroupVersion.Group, + Version: SchemeGroupVersion.Version, + Kind: pipeline.PipelineRunControllerName, +} // +genclient // +genreconciler:krshapedlogic=false @@ -325,6 +323,10 @@ type PipelineRunStatusFields struct { // +optional TaskRuns map[string]*PipelineRunTaskRunStatus `json:"taskRuns,omitempty"` + // map of PipelineRunRunStatus with the run name as the key + // +optional + Runs map[string]*PipelineRunRunStatus `json:"runs,omitempty"` + // PipelineResults are the list of results written out by the pipeline task's containers // +optional PipelineResults []PipelineRunResult `json:"pipelineResults,omitempty"` @@ -354,6 +356,14 @@ type PipelineRunTaskRunStatus struct { ConditionChecks map[string]*PipelineRunConditionCheckStatus `json:"conditionChecks,omitempty"` } +// PipelineRunRunStatus contains the name of the PipelineTask for this Run and the Run's Status +type PipelineRunRunStatus struct { + // PipelineTaskName is the name of the PipelineTask. + PipelineTaskName string `json:"pipelineTaskName,omitempty"` + + // TODO(#3133): Add v1alpha1.RunStatus here, without introducing an import cycle. +} + // PipelineRunConditionCheckStatus returns the condition check status type PipelineRunConditionCheckStatus struct { // ConditionName is the name of the Condition diff --git a/pkg/apis/pipeline/v1beta1/pipelinerun_validation_test.go b/pkg/apis/pipeline/v1beta1/pipelinerun_validation_test.go index 907bf4dae74..aa5a7620fa5 100644 --- a/pkg/apis/pipeline/v1beta1/pipelinerun_validation_test.go +++ b/pkg/apis/pipeline/v1beta1/pipelinerun_validation_test.go @@ -29,7 +29,7 @@ import ( "knative.dev/pkg/apis" ) -func TestPipelineRun_Invalidate(t *testing.T) { +func TestPipelineRun_Invalid(t *testing.T) { tests := []struct { name string pr v1beta1.PipelineRun diff --git a/pkg/apis/pipeline/v1beta1/zz_generated.deepcopy.go b/pkg/apis/pipeline/v1beta1/zz_generated.deepcopy.go index 37733e74976..0e283b635e3 100644 --- a/pkg/apis/pipeline/v1beta1/zz_generated.deepcopy.go +++ b/pkg/apis/pipeline/v1beta1/zz_generated.deepcopy.go @@ -587,6 +587,22 @@ func (in *PipelineRunResult) DeepCopy() *PipelineRunResult { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PipelineRunRunStatus) DeepCopyInto(out *PipelineRunRunStatus) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PipelineRunRunStatus. +func (in *PipelineRunRunStatus) DeepCopy() *PipelineRunRunStatus { + if in == nil { + return nil + } + out := new(PipelineRunRunStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PipelineRunSpec) DeepCopyInto(out *PipelineRunSpec) { *out = *in @@ -716,6 +732,21 @@ func (in *PipelineRunStatusFields) DeepCopyInto(out *PipelineRunStatusFields) { (*out)[key] = outVal } } + if in.Runs != nil { + in, out := &in.Runs, &out.Runs + *out = make(map[string]*PipelineRunRunStatus, len(*in)) + for key, val := range *in { + var outVal *PipelineRunRunStatus + if val == nil { + (*out)[key] = nil + } else { + in, out := &val, &outVal + *out = new(PipelineRunRunStatus) + **out = **in + } + (*out)[key] = outVal + } + } if in.PipelineResults != nil { in, out := &in.PipelineResults, &out.PipelineResults *out = make([]PipelineRunResult, len(*in)) diff --git a/pkg/reconciler/pipelinerun/controller.go b/pkg/reconciler/pipelinerun/controller.go index af9b2b44bed..9ee26b19519 100644 --- a/pkg/reconciler/pipelinerun/controller.go +++ b/pkg/reconciler/pipelinerun/controller.go @@ -24,6 +24,7 @@ import ( "github.com/tektoncd/pipeline/pkg/apis/pipeline" pipelineclient "github.com/tektoncd/pipeline/pkg/client/injection/client" conditioninformer "github.com/tektoncd/pipeline/pkg/client/injection/informers/pipeline/v1alpha1/condition" + runinformer "github.com/tektoncd/pipeline/pkg/client/injection/informers/pipeline/v1alpha1/run" clustertaskinformer "github.com/tektoncd/pipeline/pkg/client/injection/informers/pipeline/v1beta1/clustertask" pipelineinformer "github.com/tektoncd/pipeline/pkg/client/injection/informers/pipeline/v1beta1/pipeline" pipelineruninformer "github.com/tektoncd/pipeline/pkg/client/injection/informers/pipeline/v1beta1/pipelinerun" @@ -49,6 +50,7 @@ func NewController(namespace string, images pipeline.Images) func(context.Contex kubeclientset := kubeclient.Get(ctx) pipelineclientset := pipelineclient.Get(ctx) taskRunInformer := taskruninformer.Get(ctx) + runInformer := runinformer.Get(ctx) taskInformer := taskinformer.Get(ctx) clusterTaskInformer := clustertaskinformer.Get(ctx) pipelineRunInformer := pipelineruninformer.Get(ctx) @@ -70,6 +72,7 @@ func NewController(namespace string, images pipeline.Images) func(context.Contex taskLister: taskInformer.Lister(), clusterTaskLister: clusterTaskInformer.Lister(), taskRunLister: taskRunInformer.Lister(), + runLister: runInformer.Lister(), resourceLister: resourceInformer.Lister(), conditionLister: conditionInformer.Lister(), timeoutHandler: timeoutHandler, @@ -100,6 +103,9 @@ func NewController(namespace string, images pipeline.Images) func(context.Contex taskRunInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ UpdateFunc: controller.PassNew(impl.EnqueueControllerOf), }) + runInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ + UpdateFunc: controller.PassNew(impl.EnqueueControllerOf), + }) go metrics.ReportRunningPipelineRuns(ctx, pipelineRunInformer.Lister()) diff --git a/pkg/reconciler/pipelinerun/pipelinerun.go b/pkg/reconciler/pipelinerun/pipelinerun.go index 47d14c68273..edb9efc14c5 100644 --- a/pkg/reconciler/pipelinerun/pipelinerun.go +++ b/pkg/reconciler/pipelinerun/pipelinerun.go @@ -110,6 +110,7 @@ type Reconciler struct { pipelineRunLister listers.PipelineRunLister pipelineLister listers.PipelineLister taskRunLister listers.TaskRunLister + runLister listersv1alpha1.RunLister taskLister listers.TaskLister clusterTaskLister listers.ClusterTaskLister resourceLister resourcelisters.PipelineResourceLister @@ -172,6 +173,7 @@ func (c *Reconciler) ReconcileKind(ctx context.Context, pr *v1beta1.PipelineRun) return c.finishReconcileUpdateEmitEvents(ctx, pr, before, err) } c.timeoutHandler.Release(pr) + // TODO(#3133): Also updateRunsStatusDirectly to update status of Custom Task Runs. if err := c.updateTaskRunsStatusDirectly(pr); err != nil { logger.Errorf("Failed to update TaskRun status for PipelineRun %s: %v", pr.Name, err) return c.finishReconcileUpdateEmitEvents(ctx, pr, before, err) @@ -197,8 +199,8 @@ func (c *Reconciler) ReconcileKind(ctx context.Context, pr *v1beta1.PipelineRun) } // Make sure that the PipelineRun status is in sync with the actual TaskRuns - err := c.updatePipelineRunStatusFromInformer(ctx, pr) - if err != nil { + // TODO(#3133): Also update PipelineRun status to sync status of any Custom Task Runs. + if err := c.updatePipelineRunStatusFromInformer(ctx, pr); err != nil { // This should not fail. Return the error so we can re-try later. logger.Errorf("Error while syncing the pipelinerun status: %v", err.Error()) return c.finishReconcileUpdateEmitEvents(ctx, pr, before, err) @@ -206,7 +208,8 @@ func (c *Reconciler) ReconcileKind(ctx context.Context, pr *v1beta1.PipelineRun) // Reconcile this copy of the pipelinerun and then write back any status or label // updates regardless of whether the reconciliation errored out. - if err = c.reconcile(ctx, pr); err != nil { + err := c.reconcile(ctx, pr) + if err != nil { logger.Errorf("Reconcile error: %v", err.Error()) } @@ -398,6 +401,9 @@ func (c *Reconciler) reconcile(ctx context.Context, pr *v1beta1.PipelineRun) err func(name string) (*v1beta1.TaskRun, error) { return c.taskRunLister.TaskRuns(pr.Namespace).Get(name) }, + func(name string) (*v1alpha1.Run, error) { + return c.runLister.Runs(pr.Namespace).Get(name) + }, func(name string) (v1beta1.TaskInterface, error) { return c.clusterTaskLister.Get(name) }, @@ -427,11 +433,12 @@ func (c *Reconciler) reconcile(ctx context.Context, pr *v1beta1.PipelineRun) err } for _, rprt := range pipelineState { - err := taskrun.ValidateResolvedTaskResources(rprt.PipelineTask.Params, rprt.ResolvedTaskResources) - if err != nil { - logger.Errorf("Failed to validate pipelinerun %q with error %v", pr.Name, err) - pr.Status.MarkFailed(ReasonFailedValidation, err.Error()) - return controller.NewPermanentError(err) + if !rprt.IsCustomTask() { + if err := taskrun.ValidateResolvedTaskResources(rprt.PipelineTask.Params, rprt.ResolvedTaskResources); err != nil { + logger.Errorf("Failed to validate pipelinerun %q with error %v", pr.Name, err) + pr.Status.MarkFailed(ReasonFailedValidation, err.Error()) + return controller.NewPermanentError(err) + } } } @@ -481,6 +488,7 @@ func (c *Reconciler) reconcile(ctx context.Context, pr *v1beta1.PipelineRun) err // Read the condition the way it was set by the Mark* helpers after = pr.Status.GetCondition(apis.ConditionSucceeded) pr.Status.TaskRuns = getTaskRunsStatus(pr, pipelineState) + pr.Status.Runs = getRunsStatus(pr, pipelineState) logger.Infof("PipelineRun %s status is being set to %s", pr.Name, after) return nil } @@ -489,7 +497,6 @@ func (c *Reconciler) reconcile(ctx context.Context, pr *v1beta1.PipelineRun) err // pipeline run state, and starts them // after all DAG tasks are done, it's responsible for scheduling final tasks and start executing them func (c *Reconciler) runNextSchedulableTask(ctx context.Context, pr *v1beta1.PipelineRun, d *dag.Graph, dfinally *dag.Graph, pipelineState resources.PipelineRunState, as artifacts.ArtifactStorageInterface) error { - logger := logging.FromContext(ctx) recorder := controller.GetEventRecorder(ctx) @@ -525,10 +532,18 @@ func (c *Reconciler) runNextSchedulableTask(ctx context.Context, pr *v1beta1.Pip continue } if rprt.ResolvedConditionChecks == nil || rprt.ResolvedConditionChecks.IsSuccess() { - rprt.TaskRun, err = c.createTaskRun(ctx, rprt, pr, as.StorageBasePath(pr)) - if err != nil { - recorder.Eventf(pr, corev1.EventTypeWarning, "TaskRunCreationFailed", "Failed to create TaskRun %q: %v", rprt.TaskRunName, err) - return fmt.Errorf("error creating TaskRun called %s for PipelineTask %s from PipelineRun %s: %w", rprt.TaskRunName, rprt.PipelineTask.Name, pr.Name, err) + if !rprt.IsCustomTask() { + rprt.TaskRun, err = c.createTaskRun(ctx, rprt, pr, as.StorageBasePath(pr)) + if err != nil { + recorder.Eventf(pr, corev1.EventTypeWarning, "TaskRunCreationFailed", "Failed to create TaskRun %q: %v", rprt.TaskRunName, err) + return fmt.Errorf("error creating TaskRun called %s for PipelineTask %s from PipelineRun %s: %w", rprt.TaskRunName, rprt.PipelineTask.Name, pr.Name, err) + } + } else { + rprt.Run, err = c.createRun(ctx, rprt, pr) + if err != nil { + recorder.Eventf(pr, corev1.EventTypeWarning, "RunCreationFailed", "Failed to create Run %q: %v", rprt.RunName, err) + return fmt.Errorf("error creating Run called %s for PipelineTask %s from PipelineRun %s: %w", rprt.RunName, rprt.PipelineTask.Name, pr.Name, err) + } } } else if !rprt.ResolvedConditionChecks.HasStarted() { for _, rcc := range rprt.ResolvedConditionChecks { @@ -564,9 +579,43 @@ func getPipelineRunResults(pipelineSpec *v1beta1.PipelineSpec, resolvedResultRef return results } +func getRunsStatus(pr *v1beta1.PipelineRun, state []*resources.ResolvedPipelineRunTask) map[string]*v1beta1.PipelineRunRunStatus { + status := map[string]*v1beta1.PipelineRunRunStatus{} + for _, rprt := range state { + if !rprt.IsCustomTask() { + continue + } + if rprt.Run == nil && rprt.ResolvedConditionChecks == nil { + continue + } + + var prrs *v1beta1.PipelineRunRunStatus + if rprt.Run != nil { + prrs = pr.Status.Runs[rprt.RunName] + } + + if prrs == nil { + prrs = &v1beta1.PipelineRunRunStatus{ + PipelineTaskName: rprt.PipelineTask.Name, + } + } + + if rprt.Run != nil { + // TODO(#3133): Support RunStatus. + //prrs.Status = &rprt.Run.Status + } + // TODO(#3133): Include any condition check statuses here too. + status[rprt.RunName] = prrs + } + return status +} + func getTaskRunsStatus(pr *v1beta1.PipelineRun, state []*resources.ResolvedPipelineRunTask) map[string]*v1beta1.PipelineRunTaskRunStatus { - status := make(map[string]*v1beta1.PipelineRunTaskRunStatus) + status := map[string]*v1beta1.PipelineRunTaskRunStatus{} for _, rprt := range state { + if rprt.IsCustomTask() { + continue + } if rprt.TaskRun == nil && rprt.ResolvedConditionChecks == nil { continue } @@ -575,6 +624,7 @@ func getTaskRunsStatus(pr *v1beta1.PipelineRun, state []*resources.ResolvedPipel if rprt.TaskRun != nil { prtrs = pr.Status.TaskRuns[rprt.TaskRun.Name] } + if prtrs == nil { prtrs = &v1beta1.PipelineRunTaskRunStatus{ PipelineTaskName: rprt.PipelineTask.Name, @@ -618,14 +668,11 @@ func (c *Reconciler) updateTaskRunsStatusDirectly(pr *v1beta1.PipelineRun) error // TODO(dibyom): Add conditionCheck statuses here prtrs := pr.Status.TaskRuns[taskRunName] tr, err := c.taskRunLister.TaskRuns(pr.Namespace).Get(taskRunName) - if err != nil { + if err != nil && !errors.IsNotFound(err) { // If the TaskRun isn't found, it just means it won't be run - if !errors.IsNotFound(err) { - return fmt.Errorf("error retrieving TaskRun %s: %w", taskRunName, err) - } - } else { - prtrs.Status = &tr.Status + return fmt.Errorf("error retrieving TaskRun %s: %w", taskRunName, err) } + prtrs.Status = &tr.Status } return nil } @@ -659,7 +706,8 @@ func (c *Reconciler) createTaskRun(ctx context.Context, rprt *resources.Resolved ServiceAccountName: serviceAccountName, Timeout: getTaskRunTimeout(pr, rprt), PodTemplate: podTemplate, - }} + }, + } if rprt.ResolvedTaskResources.TaskName != "" { tr.Spec.TaskRef = &v1beta1.TaskRef{ @@ -696,6 +744,23 @@ func (c *Reconciler) createTaskRun(ctx context.Context, rprt *resources.Resolved return c.PipelineClientSet.TektonV1beta1().TaskRuns(pr.Namespace).Create(tr) } +func (c *Reconciler) createRun(ctx context.Context, rprt *resources.ResolvedPipelineRunTask, pr *v1beta1.PipelineRun) (*v1alpha1.Run, error) { + r := &v1alpha1.Run{ + ObjectMeta: metav1.ObjectMeta{ + Name: rprt.RunName, + Namespace: pr.Namespace, + OwnerReferences: []metav1.OwnerReference{pr.GetOwnerReference()}, + Labels: getTaskrunLabels(pr, rprt.PipelineTask.Name), + Annotations: getTaskrunAnnotations(pr), + }, + Spec: v1alpha1.RunSpec{ + Ref: rprt.PipelineTask.TaskRef, + Params: rprt.PipelineTask.Params, + }, + } + return c.PipelineClientSet.TektonV1alpha1().Runs(pr.Namespace).Create(r) +} + // taskWorkspaceByWorkspaceVolumeSource is returning the WorkspaceBinding with the TaskRun specified name. // If the volume source is a volumeClaimTemplate, the template is applied and passed to TaskRun as a persistentVolumeClaim func taskWorkspaceByWorkspaceVolumeSource(wb v1beta1.WorkspaceBinding, taskWorkspaceName string, pipelineTaskSubPath string, owner metav1.OwnerReference) v1beta1.WorkspaceBinding { diff --git a/pkg/reconciler/pipelinerun/pipelinerun_test.go b/pkg/reconciler/pipelinerun/pipelinerun_test.go index 4f9246cbd4d..6931b8e2ebb 100644 --- a/pkg/reconciler/pipelinerun/pipelinerun_test.go +++ b/pkg/reconciler/pipelinerun/pipelinerun_test.go @@ -408,6 +408,93 @@ func TestReconcile(t *testing.T) { ensurePVCCreated(t, clients, expectedTaskRun.GetPipelineRunPVCName(), "foo") } +// TestReconcile_CustomTask runs "Reconcile" on a PipelineRun with one Custom +// Task reference that has not been run yet. It verifies that the Run is +// created, it checks the resulting API actions, status and events. +func TestReconcile_CustomTask(t *testing.T) { + names.TestingSeed() + const pipelineRunName = "test-pipelinerun-custom-task" + const namespace = "namespace" + prt := NewPipelineRunTest(test.Data{PipelineRuns: []*v1beta1.PipelineRun{{ + ObjectMeta: metav1.ObjectMeta{ + Name: pipelineRunName, + Namespace: namespace, + }, + Spec: v1beta1.PipelineRunSpec{ + PipelineSpec: &v1beta1.PipelineSpec{ + Tasks: []v1beta1.PipelineTask{{ + Name: "custom-task", + TaskRef: &v1beta1.TaskRef{ + APIVersion: "example.dev/v0", + Kind: "Example", + }, + }}, + }, + }, + }}, + }, t) + defer prt.Cancel() + + wantEvents := []string{ + "Normal Started", + "Normal Running Tasks Completed: 0", + } + reconciledRun, clients := prt.reconcileRun(namespace, pipelineRunName, wantEvents, false) + + actions := clients.Pipeline.Actions() + if len(actions) < 2 { + t.Fatalf("Expected client to have at least two action implementation but it has %d", len(actions)) + } + + // Check that the expected Run was created. + trueB := true + actual := actions[0].(ktesting.CreateAction).GetObject() + wantRun := &v1alpha1.Run{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-pipelinerun-custom-task-custom-task-9l9zj", + Namespace: namespace, + OwnerReferences: []metav1.OwnerReference{{ + APIVersion: "tekton.dev/v1beta1", + Kind: "PipelineRun", + Name: "test-pipelinerun-custom-task", + Controller: &trueB, + BlockOwnerDeletion: &trueB, + }}, + Labels: map[string]string{ + "tekton.dev/pipeline": "test-pipelinerun-custom-task", + "tekton.dev/pipelineRun": "test-pipelinerun-custom-task", + "tekton.dev/pipelineTask": "custom-task", + }, + Annotations: map[string]string{}, + }, + Spec: v1alpha1.RunSpec{ + Ref: &v1beta1.TaskRef{ + APIVersion: "example.dev/v0", + Kind: "Example", + }, + }, + } + if d := cmp.Diff(wantRun, actual); d != "" { + t.Errorf("expected to see Run created: %s", diff.PrintWantGot(d)) + } + + // This PipelineRun is in progress now and the status should reflect that + condition := reconciledRun.Status.GetCondition(apis.ConditionSucceeded) + if condition == nil || condition.Status != corev1.ConditionUnknown { + t.Errorf("Expected PipelineRun status to be in progress, but was %v", condition) + } + if condition != nil && condition.Reason != v1beta1.PipelineRunReasonRunning.String() { + t.Errorf("Expected reason %q but was %s", v1beta1.PipelineRunReasonRunning.String(), condition.Reason) + } + + if len(reconciledRun.Status.Runs) != 1 { + t.Errorf("Expected PipelineRun status to include one Run status, got %d", len(reconciledRun.Status.Runs)) + } + if _, exists := reconciledRun.Status.Runs["test-pipelinerun-custom-task-custom-task-9l9zj"]; !exists { + t.Errorf("Expected PipelineRun status to include Run status but was %v", reconciledRun.Status.Runs) + } +} + func TestReconcile_PipelineSpecTaskSpec(t *testing.T) { // TestReconcile_PipelineSpecTaskSpec runs "Reconcile" on a PipelineRun that has an embedded PipelineSpec that has an embedded TaskSpec. // It verifies that a TaskRun is created, it checks the resulting API actions, status and events. diff --git a/pkg/reconciler/pipelinerun/resources/pipelinerunresolution.go b/pkg/reconciler/pipelinerun/resources/pipelinerunresolution.go index f528d05103e..04071376af1 100644 --- a/pkg/reconciler/pipelinerun/resources/pipelinerunresolution.go +++ b/pkg/reconciler/pipelinerun/resources/pipelinerunresolution.go @@ -22,12 +22,7 @@ import ( "reflect" "strconv" - "go.uber.org/zap" - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/util/sets" - "knative.dev/pkg/apis" - + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" resourcev1alpha1 "github.com/tektoncd/pipeline/pkg/apis/resource/v1alpha1" "github.com/tektoncd/pipeline/pkg/contexts" @@ -35,6 +30,11 @@ import ( "github.com/tektoncd/pipeline/pkg/names" "github.com/tektoncd/pipeline/pkg/reconciler/pipeline/dag" "github.com/tektoncd/pipeline/pkg/reconciler/taskrun/resources" + "go.uber.org/zap" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/util/sets" + "knative.dev/pkg/apis" ) const ( @@ -66,79 +66,96 @@ func (e *ConditionNotFoundError) Error() string { // ResolvedPipelineRunTask contains a Task and its associated TaskRun, if it // exists. TaskRun can be nil to represent there being no TaskRun. type ResolvedPipelineRunTask struct { - TaskRunName string - TaskRun *v1beta1.TaskRun + TaskRunName string + TaskRun *v1beta1.TaskRun + + // If the PipelineTask is a Custom Task, RunName and Run will be set. + RunName string + Run *v1alpha1.Run + PipelineTask *v1beta1.PipelineTask ResolvedTaskResources *resources.ResolvedTaskResources // ConditionChecks ~~TaskRuns but for evaling conditions ResolvedConditionChecks TaskConditionCheckState // Could also be a TaskRun or maybe just a Pod? } +// IsCustomTask returns true if the PipelineTask references a Custom Task. +func (t ResolvedPipelineRunTask) IsCustomTask() bool { + return t.PipelineTask.TaskRef != nil && + t.PipelineTask.TaskRef.APIVersion != "" +} + // PipelineRunState is a slice of ResolvedPipelineRunTasks the represents the current execution // state of the PipelineRun. type PipelineRunState []*ResolvedPipelineRunTask func (t ResolvedPipelineRunTask) IsDone() bool { - if t.TaskRun == nil || t.PipelineTask == nil { + if t.PipelineTask == nil { return false } - status := t.TaskRun.Status.GetCondition(apis.ConditionSucceeded) - retriesDone := len(t.TaskRun.Status.RetriesStatus) - retries := t.PipelineTask.Retries - return status.IsTrue() || status.IsFalse() && retriesDone >= retries + if !t.IsCustomTask() { + if t.TaskRun == nil { + return false + } + status := t.TaskRun.Status.GetCondition(apis.ConditionSucceeded) + retriesDone := len(t.TaskRun.Status.RetriesStatus) + retries := t.PipelineTask.Retries + return status.IsTrue() || status.IsFalse() && retriesDone >= retries + } + return t.Run != nil && t.Run.IsDone() } // IsSuccessful returns true only if the taskrun itself has completed successfully func (t ResolvedPipelineRunTask) IsSuccessful() bool { - if t.TaskRun == nil { - return false - } - c := t.TaskRun.Status.GetCondition(apis.ConditionSucceeded) - if c == nil { - return false + if !t.IsCustomTask() { + if t.TaskRun == nil { + return false + } + return t.TaskRun.IsSuccessful() } - - return c.Status == corev1.ConditionTrue + return t.Run != nil && t.Run.IsSuccessful() } -// IsFailure returns true only if the taskrun itself has failed +// IsFailure returns true only if the run has failed and will not be retried. func (t ResolvedPipelineRunTask) IsFailure() bool { - if t.TaskRun == nil { - return false + if !t.IsCustomTask() { + if t.TaskRun == nil { + return false + } + c := t.TaskRun.Status.GetCondition(apis.ConditionSucceeded) + retriesDone := len(t.TaskRun.Status.RetriesStatus) + retries := t.PipelineTask.Retries + return c.IsFalse() && retriesDone >= retries } - c := t.TaskRun.Status.GetCondition(apis.ConditionSucceeded) - retriesDone := len(t.TaskRun.Status.RetriesStatus) - retries := t.PipelineTask.Retries - return c.IsFalse() && retriesDone >= retries + return t.Run != nil && t.Run.IsDone() && !t.Run.IsSuccessful() } // IsCancelled returns true only if the taskrun itself has cancelled func (t ResolvedPipelineRunTask) IsCancelled() bool { - if t.TaskRun == nil { - return false - } + if !t.IsCustomTask() { + if t.TaskRun == nil { + return false + } - c := t.TaskRun.Status.GetCondition(apis.ConditionSucceeded) - if c == nil { - return false - } + c := t.TaskRun.Status.GetCondition(apis.ConditionSucceeded) + if c == nil { + return false + } - return c.IsFalse() && c.Reason == v1beta1.TaskRunReasonCancelled.String() + return c.IsFalse() && c.Reason == v1beta1.TaskRunReasonCancelled.String() + } + // TODO(#3133): Support cancellation of Custom Task runs. + return false } -// IsStarted returns true only if the PipelineRunTask itself has a TaskRun associated +// IsStarted returns true only if the PipelineRunTask itself has a TaskRun or +// Run associated that has a Succeeded-type condition. func (t ResolvedPipelineRunTask) IsStarted() bool { - if t.TaskRun == nil { - return false + if !t.IsCustomTask() { + return t.TaskRun != nil && t.TaskRun.Status.GetCondition(apis.ConditionSucceeded) != nil } - - c := t.TaskRun.Status.GetCondition(apis.ConditionSucceeded) - if c == nil { - return false - } - - return true + return t.Run != nil && t.Run.Status.GetCondition(apis.ConditionSucceeded) != nil } // IsSkipped returns true if a PipelineTask will not be run because @@ -201,7 +218,9 @@ func (state PipelineRunState) IsDone() bool { // IsBeforeFirstTaskRun returns true if the PipelineRun has not yet started its first TaskRun func (state PipelineRunState) IsBeforeFirstTaskRun() bool { for _, t := range state { - if t.TaskRun != nil { + if t.IsCustomTask() && t.Run != nil { + return false + } else if t.TaskRun != nil { return false } } @@ -230,11 +249,19 @@ func (state PipelineRunState) IsStopping(d *dag.Graph) bool { func (state PipelineRunState) GetNextTasks(candidateTasks sets.String) []*ResolvedPipelineRunTask { tasks := []*ResolvedPipelineRunTask{} for _, t := range state { - if _, ok := candidateTasks[t.PipelineTask.Name]; ok && t.TaskRun == nil { + if _, ok := candidateTasks[t.PipelineTask.Name]; ok && t.TaskRun == nil && t.Run == nil { tasks = append(tasks, t) } - if _, ok := candidateTasks[t.PipelineTask.Name]; ok && t.TaskRun != nil { - status := t.TaskRun.Status.GetCondition(apis.ConditionSucceeded) + if _, ok := candidateTasks[t.PipelineTask.Name]; ok { + var status *apis.Condition + switch { + case t.IsCustomTask() && t.Run != nil: + status = t.Run.Status.GetCondition(apis.ConditionSucceeded) + case !t.IsCustomTask() && t.TaskRun != nil: + status = t.TaskRun.Status.GetCondition(apis.ConditionSucceeded) + default: + continue + } if status != nil && status.IsFalse() { if !(t.TaskRun.IsCancelled() || status.Reason == v1beta1.TaskRunReasonCancelled.String() || status.Reason == ReasonConditionCheckFailed) { if len(t.TaskRun.Status.RetriesStatus) < t.PipelineTask.Retries { @@ -266,10 +293,16 @@ func (state PipelineRunState) SuccessfulOrSkippedDAGTasks(d *dag.Graph) []string func (state PipelineRunState) checkTasksDone(d *dag.Graph) bool { for _, t := range state { if isTaskInGraph(t.PipelineTask.Name, d) { - if t.TaskRun == nil { - // this task might have skipped if taskRun is nil - // continue and ignore if this task was skipped - // skipped task is considered part of done + // this task might have skipped if taskRun is nil + // continue and ignore if this task was skipped + // skipped task is considered part of done + if !t.IsCustomTask() && t.TaskRun == nil { + if t.IsSkipped(state, d) { + continue + } + return false + } + if t.IsCustomTask() && t.Run == nil { if t.IsSkipped(state, d) { continue } @@ -305,14 +338,12 @@ func (state PipelineRunState) GetFinalTasks(d *dag.Graph, dfinally *dag.Graph) [ // Check if a PipelineTask belongs to the specified Graph func isTaskInGraph(pipelineTaskName string, d *dag.Graph) bool { - if _, ok := d.Nodes[pipelineTaskName]; ok { - return true - } - return false + _, found := d.Nodes[pipelineTaskName] + return found } -// GetTaskRun is a function that will retrieve the TaskRun name. -type GetTaskRun func(name string) (*v1beta1.TaskRun, error) +// GetRun is a function that will retrieve a Run by name. +type GetRun func(name string) (*v1alpha1.Run, error) // GetResourcesFromBindings will retrieve all Resources bound in PipelineRun pr and return a map // from the declared name of the PipelineResource (which is how the PipelineResource will @@ -408,11 +439,16 @@ func ValidateServiceaccountMapping(p *v1beta1.PipelineSpec, pr *v1beta1.Pipeline // instances from getTask. If it is unable to retrieve an instance of a referenced Task, it // will return an error, otherwise it returns a list of all of the Tasks retrieved. // It will retrieve the Resources needed for the TaskRun using the mapping of providedResources. +// +// TODO: The proliferation of Get* methods here is a smell. This method should +// take a versioned clientset instead which includes methods to retrieve these +// resources, with generated fakes for testing. func ResolvePipelineRun( ctx context.Context, pipelineRun v1beta1.PipelineRun, getTask resources.GetTask, getTaskRun resources.GetTaskRun, + getRun GetRun, getClusterTask resources.GetClusterTask, getCondition GetCondition, tasks []v1beta1.PipelineTask, @@ -422,54 +458,58 @@ func ResolvePipelineRun( state := []*ResolvedPipelineRunTask{} for i := range tasks { pt := tasks[i] - rprt := ResolvedPipelineRunTask{ PipelineTask: &pt, - TaskRunName: GetTaskRunName(pipelineRun.Status.TaskRuns, pt.Name, pipelineRun.Name), } - // Find the Task that this PipelineTask is using - var ( - t v1beta1.TaskInterface - err error - spec v1beta1.TaskSpec - taskName string - kind v1beta1.TaskKind - ) - - if pt.TaskRef != nil { - if pt.TaskRef.Kind == v1beta1.ClusterTaskKind { - t, err = getClusterTask(pt.TaskRef.Name) + if rprt.IsCustomTask() { + rprt.RunName = GetRunName(pipelineRun.Status.Runs, pt.Name, pipelineRun.Name) + run, err := getRun(rprt.RunName) + if err != nil && !errors.IsNotFound(err) { + return nil, fmt.Errorf("error retrieving Run %s: %w", rprt.RunName, err) + } + rprt.Run = run + } else { + rprt.TaskRunName = GetTaskRunName(pipelineRun.Status.TaskRuns, pt.Name, pipelineRun.Name) + // Find the Task that this PipelineTask is using + var ( + t v1beta1.TaskInterface + err error + spec v1beta1.TaskSpec + taskName string + kind v1beta1.TaskKind + ) + + if pt.TaskRef != nil { + if pt.TaskRef.Kind == v1beta1.ClusterTaskKind { + t, err = getClusterTask(pt.TaskRef.Name) + } else { + t, err = getTask(pt.TaskRef.Name) + } + if err != nil { + return nil, &TaskNotFoundError{ + Name: pt.TaskRef.Name, + Msg: err.Error(), + } + } + spec = t.TaskSpec() + taskName = t.TaskMetadata().Name + kind = pt.TaskRef.Kind } else { - t, err = getTask(pt.TaskRef.Name) + spec = *pt.TaskSpec.TaskSpec } + spec.SetDefaults(contexts.WithUpgradeViaDefaulting(ctx)) + rtr, err := ResolvePipelineTaskResources(pt, &spec, taskName, kind, providedResources) if err != nil { - return nil, &TaskNotFoundError{ - Name: pt.TaskRef.Name, - Msg: err.Error(), - } + return nil, fmt.Errorf("couldn't match referenced resources with declared resources: %w", err) } - spec = t.TaskSpec() - taskName = t.TaskMetadata().Name - kind = pt.TaskRef.Kind - } else { - spec = *pt.TaskSpec.TaskSpec - } - spec.SetDefaults(contexts.WithUpgradeViaDefaulting(ctx)) - rtr, err := ResolvePipelineTaskResources(pt, &spec, taskName, kind, providedResources) - if err != nil { - return nil, fmt.Errorf("couldn't match referenced resources with declared resources: %w", err) - } - rprt.ResolvedTaskResources = rtr + rprt.ResolvedTaskResources = rtr - taskRun, err := getTaskRun(rprt.TaskRunName) - if err != nil { - if !errors.IsNotFound(err) { + taskRun, err := getTaskRun(rprt.TaskRunName) + if err != nil && !errors.IsNotFound(err) { return nil, fmt.Errorf("error retrieving TaskRun %s: %w", rprt.TaskRunName, err) } - } - if taskRun != nil { rprt.TaskRun = taskRun } @@ -513,6 +553,18 @@ func GetTaskRunName(taskRunsStatus map[string]*v1beta1.PipelineRunTaskRunStatus, return names.SimpleNameGenerator.RestrictLengthWithRandomSuffix(fmt.Sprintf("%s-%s", prName, ptName)) } +// GetRunName should return a unique name for a `Run` if one has not already +// been defined, and the existing one otherwise. +func GetRunName(runsStatus map[string]*v1beta1.PipelineRunRunStatus, ptName, prName string) string { + for k, v := range runsStatus { + if v.PipelineTaskName == ptName { + return k + } + } + + return names.SimpleNameGenerator.RestrictLengthWithRandomSuffix(fmt.Sprintf("%s-%s", prName, ptName)) +} + // GetPipelineConditionStatus will return the Condition that the PipelineRun prName should be // updated with, based on the status of the TaskRuns in state. func GetPipelineConditionStatus(pr *v1beta1.PipelineRun, state PipelineRunState, logger *zap.SugaredLogger, dag *dag.Graph, dfinally *dag.Graph) *apis.Condition { @@ -621,6 +673,7 @@ func resolveConditionChecks(pt *v1beta1.PipelineTask, taskRunStatus map[string]* } } conditionCheckName := getConditionCheckName(taskRunStatus, taskRunName, crName) + // TODO(#3133): Also handle Custom Task Runs (getRun here) cctr, err := getTaskRun(conditionCheckName) if err != nil { if !errors.IsNotFound(err) { diff --git a/pkg/reconciler/pipelinerun/resources/pipelinerunresolution_test.go b/pkg/reconciler/pipelinerun/resources/pipelinerunresolution_test.go index a1b4dbc0fea..0f04bf7d03b 100644 --- a/pkg/reconciler/pipelinerun/resources/pipelinerunresolution_test.go +++ b/pkg/reconciler/pipelinerun/resources/pipelinerunresolution_test.go @@ -40,9 +40,21 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/sets" "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" duckv1beta1 "knative.dev/pkg/apis/duck/v1beta1" ) +func nopGetRun(string) (*v1alpha1.Run, error) { return nil, errors.New("GetRun should not be called") } +func nopGetTask(string) (v1beta1.TaskInterface, error) { + return nil, errors.New("GetTask should not be called") +} +func nopGetTaskRun(string) (*v1beta1.TaskRun, error) { + return nil, errors.New("GetTaskRun should not be called") +} +func nopGetClusterTask(string) (v1beta1.TaskInterface, error) { + return nil, errors.New("GetClusterTask should not be called") +} + var pts = []v1beta1.PipelineTask{{ Name: "mytask1", TaskRef: &v1beta1.TaskRef{Name: "task"}, @@ -78,6 +90,9 @@ var pts = []v1beta1.PipelineTask{{ Name: "mytask9", TaskRef: &v1beta1.TaskRef{Name: "taskHasParentWithRunAfter"}, RunAfter: []string{"mytask8"}, +}, { + Name: "mytask10", + TaskRef: &v1beta1.TaskRef{APIVersion: "example.dev/v0", Kind: "Example", Name: "customtask"}, }} var p = &v1beta1.Pipeline{ @@ -225,6 +240,7 @@ var noneStartedState = PipelineRunState{{ TaskSpec: &task.Spec, }, }} + var oneStartedState = PipelineRunState{{ PipelineTask: &pts[0], TaskRunName: "pipelinerun-mytask1", @@ -240,6 +256,7 @@ var oneStartedState = PipelineRunState{{ TaskSpec: &task.Spec, }, }} + var oneFinishedState = PipelineRunState{{ PipelineTask: &pts[0], TaskRunName: "pipelinerun-mytask1", @@ -255,6 +272,7 @@ var oneFinishedState = PipelineRunState{{ TaskSpec: &task.Spec, }, }} + var oneFailedState = PipelineRunState{{ PipelineTask: &pts[0], TaskRunName: "pipelinerun-mytask1", @@ -270,6 +288,7 @@ var oneFailedState = PipelineRunState{{ TaskSpec: &task.Spec, }, }} + var allFinishedState = PipelineRunState{{ PipelineTask: &pts[0], TaskRunName: "pipelinerun-mytask1", @@ -516,7 +535,7 @@ var taskWithOptionalResources = &v1beta1.Task{ }, } -func DagFromState(state PipelineRunState) (*dag.Graph, error) { +func dagFromState(state PipelineRunState) (*dag.Graph, error) { pts := []v1beta1.PipelineTask{} for _, rprt := range state { pts = append(pts, *rprt.PipelineTask) @@ -525,7 +544,7 @@ func DagFromState(state PipelineRunState) (*dag.Graph, error) { } func TestGetNextTasks(t *testing.T) { - tcs := []struct { + for _, tc := range []struct { name string state PipelineRunState candidates sets.String @@ -635,8 +654,7 @@ func TestGetNextTasks(t *testing.T) { state: taskCancelled, candidates: sets.NewString("mytask5"), expectedNext: []*ResolvedPipelineRunTask{}, - }} - for _, tc := range tcs { + }} { t.Run(tc.name, func(t *testing.T) { next := tc.state.GetNextTasks(tc.candidates) if d := cmp.Diff(next, tc.expectedNext); d != "" { @@ -647,8 +665,7 @@ func TestGetNextTasks(t *testing.T) { } func TestGetNextTaskWithRetries(t *testing.T) { - - var taskCancelledByStatusState = PipelineRunState{{ + taskCancelledByStatusState := PipelineRunState{{ PipelineTask: &pts[4], // 2 retries needed TaskRunName: "pipelinerun-mytask1", TaskRun: withCancelled(makeRetried(trs[0])), @@ -657,7 +674,7 @@ func TestGetNextTaskWithRetries(t *testing.T) { }, }} - var taskCancelledBySpecState = PipelineRunState{{ + taskCancelledBySpecState := PipelineRunState{{ PipelineTask: &pts[4], TaskRunName: "pipelinerun-mytask1", TaskRun: withCancelledBySpec(makeRetried(trs[0])), @@ -666,7 +683,7 @@ func TestGetNextTaskWithRetries(t *testing.T) { }, }} - var taskRunningState = PipelineRunState{{ + taskRunningState := PipelineRunState{{ PipelineTask: &pts[4], TaskRunName: "pipelinerun-mytask1", TaskRun: makeStarted(trs[0]), @@ -675,7 +692,7 @@ func TestGetNextTaskWithRetries(t *testing.T) { }, }} - var taskSucceededState = PipelineRunState{{ + taskSucceededState := PipelineRunState{{ PipelineTask: &pts[4], TaskRunName: "pipelinerun-mytask1", TaskRun: makeSucceeded(trs[0]), @@ -684,7 +701,7 @@ func TestGetNextTaskWithRetries(t *testing.T) { }, }} - var taskRetriedState = PipelineRunState{{ + taskRetriedState := PipelineRunState{{ PipelineTask: &pts[3], // 1 retry needed TaskRunName: "pipelinerun-mytask1", TaskRun: withCancelled(makeRetried(trs[0])), @@ -693,7 +710,7 @@ func TestGetNextTaskWithRetries(t *testing.T) { }, }} - var taskExpectedState = PipelineRunState{{ + taskExpectedState := PipelineRunState{{ PipelineTask: &pts[4], // 2 retries needed TaskRunName: "pipelinerun-mytask1", TaskRun: withRetries(makeFailed(trs[0])), @@ -702,7 +719,7 @@ func TestGetNextTaskWithRetries(t *testing.T) { }, }} - tcs := []struct { + for _, tc := range []struct { name string state PipelineRunState candidates sets.String @@ -737,12 +754,10 @@ func TestGetNextTaskWithRetries(t *testing.T) { state: taskExpectedState, candidates: sets.NewString("mytask5"), expectedNext: []*ResolvedPipelineRunTask{taskExpectedState[0]}, - }} + }} { + // iterate over *state* to get from candidate and check if TaskRun is there. + // Cancelled TaskRun should have a TaskRun cancelled and with a retry but should not retry. - // iterate over *state* to get from candidate and check if TaskRun is there. - // Cancelled TaskRun should have a TaskRun cancelled and with a retry but should not retry. - - for _, tc := range tcs { t.Run(tc.name, func(t *testing.T) { next := tc.state.GetNextTasks(tc.candidates) if d := cmp.Diff(next, tc.expectedNext); d != "" { @@ -753,8 +768,7 @@ func TestGetNextTaskWithRetries(t *testing.T) { } func TestIsDone(t *testing.T) { - - var taskCancelledByStatusState = PipelineRunState{{ + taskCancelledByStatusState := PipelineRunState{{ PipelineTask: &pts[4], // 2 retries needed TaskRunName: "pipelinerun-mytask1", TaskRun: withCancelled(makeRetried(trs[0])), @@ -763,7 +777,7 @@ func TestIsDone(t *testing.T) { }, }} - var taskCancelledBySpecState = PipelineRunState{{ + taskCancelledBySpecState := PipelineRunState{{ PipelineTask: &pts[4], TaskRunName: "pipelinerun-mytask1", TaskRun: withCancelledBySpec(makeRetried(trs[0])), @@ -772,7 +786,7 @@ func TestIsDone(t *testing.T) { }, }} - var taskRunningState = PipelineRunState{{ + taskRunningState := PipelineRunState{{ PipelineTask: &pts[4], TaskRunName: "pipelinerun-mytask1", TaskRun: makeStarted(trs[0]), @@ -781,7 +795,7 @@ func TestIsDone(t *testing.T) { }, }} - var taskSucceededState = PipelineRunState{{ + taskSucceededState := PipelineRunState{{ PipelineTask: &pts[4], TaskRunName: "pipelinerun-mytask1", TaskRun: makeSucceeded(trs[0]), @@ -790,16 +804,7 @@ func TestIsDone(t *testing.T) { }, }} - var taskRetriedState = PipelineRunState{{ - PipelineTask: &pts[3], // 1 retry needed - TaskRunName: "pipelinerun-mytask1", - TaskRun: withCancelled(makeRetried(trs[0])), - ResolvedTaskResources: &resources.ResolvedTaskResources{ - TaskSpec: &task.Spec, - }, - }} - - var taskExpectedState = PipelineRunState{{ + taskExpectedState := PipelineRunState{{ PipelineTask: &pts[4], // 2 retries needed TaskRunName: "pipelinerun-mytask1", TaskRun: withRetries(makeFailed(trs[0])), @@ -808,25 +813,7 @@ func TestIsDone(t *testing.T) { }, }} - var noPipelineTaskState = PipelineRunState{{ - PipelineTask: nil, - TaskRunName: "pipelinerun-mytask1", - TaskRun: withRetries(makeFailed(trs[0])), - ResolvedTaskResources: &resources.ResolvedTaskResources{ - TaskSpec: &task.Spec, - }, - }} - - var noTaskRunState = PipelineRunState{{ - PipelineTask: &pts[4], // 2 retries needed - TaskRunName: "pipelinerun-mytask1", - TaskRun: nil, - ResolvedTaskResources: &resources.ResolvedTaskResources{ - TaskSpec: &task.Spec, - }, - }} - - tcs := []struct { + for _, tc := range []struct { name string state PipelineRunState expected bool @@ -852,8 +839,15 @@ func TestIsDone(t *testing.T) { expected: true, ptExpected: []bool{true}, }, { - name: "tasks-retried-no-candidates", - state: taskRetriedState, + name: "tasks-retried-no-candidates", + state: PipelineRunState{{ + PipelineTask: &pts[3], // 1 retry needed + TaskRunName: "pipelinerun-mytask1", + TaskRun: withCancelled(makeRetried(trs[0])), + ResolvedTaskResources: &resources.ResolvedTaskResources{ + TaskSpec: &task.Spec, + }, + }}, expected: false, ptExpected: []bool{false}, }, { @@ -862,20 +856,78 @@ func TestIsDone(t *testing.T) { expected: false, ptExpected: []bool{false}, }, { - name: "no-pipelineTask", - state: noPipelineTaskState, + name: "no-pipelineTask", + state: PipelineRunState{{ + PipelineTask: nil, + TaskRunName: "pipelinerun-mytask1", + TaskRun: withRetries(makeFailed(trs[0])), + ResolvedTaskResources: &resources.ResolvedTaskResources{ + TaskSpec: &task.Spec, + }, + }}, + expected: false, + ptExpected: []bool{false}, + }, { + name: "No-taskrun", + state: PipelineRunState{{ + PipelineTask: &pts[4], // 2 retries needed + TaskRunName: "pipelinerun-mytask1", + TaskRun: nil, + ResolvedTaskResources: &resources.ResolvedTaskResources{ + TaskSpec: &task.Spec, + }, + }}, expected: false, ptExpected: []bool{false}, }, { - name: "No-taskrun", - state: noTaskRunState, + name: "no-customtask", + state: PipelineRunState{{ + PipelineTask: &v1beta1.PipelineTask{TaskRef: &v1beta1.TaskRef{ + APIVersion: "example.dev/v0", + Kind: "Example", + }}, + Run: nil, + }}, expected: false, ptExpected: []bool{false}, - }} - - for _, tc := range tcs { + }, { + name: "ongoing-customtask-run", + state: PipelineRunState{{ + PipelineTask: &v1beta1.PipelineTask{TaskRef: &v1beta1.TaskRef{ + APIVersion: "example.dev/v0", + Kind: "Example", + }}, + Run: &v1alpha1.Run{ + Status: v1alpha1.RunStatus{Status: duckv1.Status{ + Conditions: duckv1.Conditions{{ + Type: apis.ConditionSucceeded, + Status: corev1.ConditionUnknown, + }}, + }}, + }, + }}, + expected: false, + ptExpected: []bool{false}, + }, { + name: "done-customtask-run", + state: PipelineRunState{{ + PipelineTask: &v1beta1.PipelineTask{TaskRef: &v1beta1.TaskRef{ + APIVersion: "example.dev/v0", + Kind: "Example", + }}, + Run: &v1alpha1.Run{ + Status: v1alpha1.RunStatus{Status: duckv1.Status{ + Conditions: duckv1.Conditions{{ + Type: apis.ConditionSucceeded, + Status: corev1.ConditionTrue, + }}, + }}, + }, + }}, + expected: true, + ptExpected: []bool{true}, + }} { t.Run(tc.name, func(t *testing.T) { - isDone := tc.state.IsDone() if d := cmp.Diff(isDone, tc.expected); d != "" { t.Errorf("Didn't get expected IsDone %s", diff.PrintWantGot(d)) @@ -892,8 +944,7 @@ func TestIsDone(t *testing.T) { } func TestIsSkipped(t *testing.T) { - - tcs := []struct { + for _, tc := range []struct { name string taskName string state PipelineRunState @@ -1134,11 +1185,9 @@ func TestIsSkipped(t *testing.T) { }, }}, expected: true, - }} - - for _, tc := range tcs { + }} { t.Run(tc.name, func(t *testing.T) { - dag, err := DagFromState(tc.state) + dag, err := dagFromState(tc.state) if err != nil { t.Fatalf("Could not get a dag from the TC state %#v: %v", tc.state, err) } @@ -1156,7 +1205,7 @@ func TestIsSkipped(t *testing.T) { } func TestPipelineRunState_SuccessfulOrSkippedDAGTasks(t *testing.T) { - tcs := []struct { + for _, tc := range []struct { name string state PipelineRunState expectedNames []string @@ -1202,10 +1251,9 @@ func TestPipelineRunState_SuccessfulOrSkippedDAGTasks(t *testing.T) { "not skipped since it failed", state: conditionCheckFailedWithOthersFailedState, expectedNames: []string{pts[5].Name}, - }} - for _, tc := range tcs { + }} { t.Run(tc.name, func(t *testing.T) { - dag, err := DagFromState(tc.state) + dag, err := dagFromState(tc.state) if err != nil { t.Fatalf("Unexpected error while buildig DAG for state %v: %v", tc.state, err) } @@ -1227,8 +1275,7 @@ func getExpectedMessage(status corev1.ConditionStatus, successful, incomplete, s } func TestGetPipelineConditionStatus(t *testing.T) { - - var taskRetriedState = PipelineRunState{{ + taskRetriedState := PipelineRunState{{ PipelineTask: &pts[3], // 1 retry needed TaskRunName: "pipelinerun-mytask1", TaskRun: withCancelled(makeRetried(trs[0])), @@ -1237,13 +1284,13 @@ func TestGetPipelineConditionStatus(t *testing.T) { }, }} - var taskCancelledFailed = PipelineRunState{{ + taskCancelledFailed := PipelineRunState{{ PipelineTask: &pts[4], TaskRunName: "pipelinerun-mytask1", TaskRun: withCancelled(makeFailed(trs[0])), }} - var cancelledTask = PipelineRunState{{ + cancelledTask := PipelineRunState{{ PipelineTask: &pts[3], // 1 retry needed TaskRunName: "pipelinerun-mytask1", TaskRun: &v1beta1.TaskRun{ @@ -1264,7 +1311,7 @@ func TestGetPipelineConditionStatus(t *testing.T) { // Of the 4, 1 passed, 1 cancelled, 2 failed // 1 runAfter the passed one, currently running // 1 runAfter the failed one, which is marked as incomplete - var taskMultipleFailuresSkipRunning = PipelineRunState{{ + taskMultipleFailuresSkipRunning := PipelineRunState{{ TaskRunName: "task0taskrun", PipelineTask: &pts[5], TaskRun: makeSucceeded(trs[0]), @@ -1279,10 +1326,10 @@ func TestGetPipelineConditionStatus(t *testing.T) { TaskRun: makeFailed(trs[0]), }} - var taskMultipleFailuresOneCancel = taskMultipleFailuresSkipRunning + taskMultipleFailuresOneCancel := taskMultipleFailuresSkipRunning taskMultipleFailuresOneCancel = append(taskMultipleFailuresOneCancel, cancelledTask[0]) - var taskNotRunningWithSuccesfulParentsOneFailed = PipelineRunState{{ + taskNotRunningWithSuccesfulParentsOneFailed := PipelineRunState{{ TaskRunName: "task0taskrun", PipelineTask: &pts[5], TaskRun: makeSucceeded(trs[0]), @@ -1297,7 +1344,7 @@ func TestGetPipelineConditionStatus(t *testing.T) { TaskRun: makeFailed(trs[0]), }} - tcs := []struct { + for _, tc := range []struct { name string state []*ResolvedPipelineRunTask expectedStatus corev1.ConditionStatus @@ -1460,11 +1507,10 @@ func TestGetPipelineConditionStatus(t *testing.T) { expectedStatus: corev1.ConditionFalse, expectedReason: v1beta1.PipelineRunReasonCancelled.String(), expectedCancelled: 1, - }} - for _, tc := range tcs { + }} { t.Run(tc.name, func(t *testing.T) { pr := tb.PipelineRun("somepipelinerun") - d, err := DagFromState(tc.state) + d, err := dagFromState(tc.state) if err != nil { t.Fatalf("Unexpected error while buildig DAG for state %v: %v", tc.state, err) } @@ -1484,7 +1530,6 @@ func TestGetPipelineConditionStatus(t *testing.T) { } func TestGetPipelineConditionStatus_WithFinalTasks(t *testing.T) { - // pipeline state with one DAG successful, one final task failed dagSucceededFinalFailed := PipelineRunState{{ TaskRunName: "task0taskrun", @@ -1518,7 +1563,7 @@ func TestGetPipelineConditionStatus_WithFinalTasks(t *testing.T) { TaskRun: makeFailed(trs[0]), }} - tcs := []struct { + for _, tc := range []struct { name string state PipelineRunState dagTasks []v1beta1.PipelineTask @@ -1566,9 +1611,7 @@ func TestGetPipelineConditionStatus_WithFinalTasks(t *testing.T) { expectedSkipped: 0, expectedFailed: 2, expectedCancelled: 0, - }} - - for _, tc := range tcs { + }} { t.Run(tc.name, func(t *testing.T) { pr := tb.PipelineRun("pipelinerun-final-tasks") d, err := dag.Build(v1beta1.PipelineTaskList(tc.dagTasks)) @@ -1596,7 +1639,7 @@ func TestGetPipelineConditionStatus_WithFinalTasks(t *testing.T) { // pipeline should result in timeout if its runtime exceeds its spec.Timeout based on its status.Timeout func TestGetPipelineConditionStatus_PipelineTimeouts(t *testing.T) { - d, err := DagFromState(oneFinishedState) + d, err := dagFromState(oneFinishedState) if err != nil { t.Fatalf("Unexpected error while buildig DAG for state %v: %v", oneFinishedState, err) } @@ -1733,7 +1776,7 @@ func TestResolvePipelineRun(t *testing.T) { getClusterTask := func(name string) (v1beta1.TaskInterface, error) { return nil, nil } getCondition := func(name string) (*v1alpha1.Condition, error) { return nil, nil } - pipelineState, err := ResolvePipelineRun(context.Background(), pr, getTask, getTaskRun, getClusterTask, getCondition, p.Spec.Tasks, providedResources) + pipelineState, err := ResolvePipelineRun(context.Background(), pr, getTask, getTaskRun, nopGetRun, getClusterTask, getCondition, p.Spec.Tasks, providedResources) if err != nil { t.Fatalf("Error getting tasks for fake pipeline %s: %s", p.ObjectMeta.Name, err) } @@ -1790,6 +1833,45 @@ func TestResolvePipelineRun(t *testing.T) { } } +func TestResolvePipelineRun_CustomTask(t *testing.T) { + names.TestingSeed() + pts := []v1beta1.PipelineTask{{ + Name: "customtask", + TaskRef: &v1beta1.TaskRef{APIVersion: "example.dev/v0", Kind: "Example"}, + }, { + Name: "run-exists", + TaskRef: &v1beta1.TaskRef{APIVersion: "example.dev/v0", Kind: "Example"}, + }} + pr := v1beta1.PipelineRun{ + ObjectMeta: metav1.ObjectMeta{Name: "pipelinerun"}, + } + run := &v1alpha1.Run{ObjectMeta: metav1.ObjectMeta{Name: "run-exists-abcde"}} + getRun := func(name string) (*v1alpha1.Run, error) { + if name == "pipelinerun-run-exists-mz4c7" { + return run, nil + } + return nil, kerrors.NewNotFound(v1beta1.Resource("run"), name) + } + nopGetCondition := func(string) (*v1alpha1.Condition, error) { return nil, errors.New("GetCondition should not be called") } + pipelineState, err := ResolvePipelineRun(context.Background(), pr, nopGetTask, nopGetTaskRun, getRun, nopGetClusterTask, nopGetCondition, pts, nil) + if err != nil { + t.Fatalf("ResolvePipelineRun: %v", err) + } + + expectedState := PipelineRunState{{ + PipelineTask: &pts[0], + RunName: "pipelinerun-customtask-9l9zj", + Run: nil, + }, { + PipelineTask: &pts[1], + RunName: "pipelinerun-run-exists-mz4c7", + Run: run, + }} + if d := cmp.Diff(expectedState, pipelineState); d != "" { + t.Errorf("Unexpected pipelien state: %s", diff.PrintWantGot(d)) + } +} + func TestResolvePipelineRun_PipelineTaskHasNoResources(t *testing.T) { pts := []v1beta1.PipelineTask{{ Name: "mytask1", @@ -1812,7 +1894,7 @@ func TestResolvePipelineRun_PipelineTaskHasNoResources(t *testing.T) { Name: "pipelinerun", }, } - pipelineState, err := ResolvePipelineRun(context.Background(), pr, getTask, getTaskRun, getClusterTask, getCondition, pts, providedResources) + pipelineState, err := ResolvePipelineRun(context.Background(), pr, getTask, getTaskRun, nopGetRun, getClusterTask, getCondition, pts, providedResources) if err != nil { t.Fatalf("Did not expect error when resolving PipelineRun without Resources: %v", err) } @@ -1859,7 +1941,7 @@ func TestResolvePipelineRun_TaskDoesntExist(t *testing.T) { Name: "pipelinerun", }, } - _, err := ResolvePipelineRun(context.Background(), pr, getTask, getTaskRun, getClusterTask, getCondition, pts, providedResources) + _, err := ResolvePipelineRun(context.Background(), pr, getTask, getTaskRun, nopGetRun, getClusterTask, getCondition, pts, providedResources) switch err := err.(type) { case nil: t.Fatalf("Expected error getting non-existent Tasks for Pipeline %s but got none", p.Name) @@ -1905,7 +1987,7 @@ func TestResolvePipelineRun_ResourceBindingsDontExist(t *testing.T) { Name: "pipelinerun", }, } - _, err := ResolvePipelineRun(context.Background(), pr, getTask, getTaskRun, getClusterTask, getCondition, tt.p.Spec.Tasks, providedResources) + _, err := ResolvePipelineRun(context.Background(), pr, getTask, getTaskRun, nopGetRun, getClusterTask, getCondition, tt.p.Spec.Tasks, providedResources) if err == nil { t.Fatalf("Expected error when bindings are in incorrect state for Pipeline %s but got none", p.Name) } @@ -1955,7 +2037,7 @@ func TestResolvePipelineRun_withExistingTaskRuns(t *testing.T) { getClusterTask := func(name string) (v1beta1.TaskInterface, error) { return nil, nil } getTaskRun := func(name string) (*v1beta1.TaskRun, error) { return nil, nil } getCondition := func(name string) (*v1alpha1.Condition, error) { return nil, nil } - pipelineState, err := ResolvePipelineRun(context.Background(), pr, getTask, getTaskRun, getClusterTask, getCondition, p.Spec.Tasks, providedResources) + pipelineState, err := ResolvePipelineRun(context.Background(), pr, getTask, getTaskRun, nopGetRun, getClusterTask, getCondition, p.Spec.Tasks, providedResources) if err != nil { t.Fatalf("Error getting tasks for fake pipeline %s: %s", p.ObjectMeta.Name, err) } @@ -2008,7 +2090,7 @@ func TestResolvedPipelineRun_PipelineTaskHasOptionalResources(t *testing.T) { getClusterTask := func(name string) (v1beta1.TaskInterface, error) { return nil, nil } getCondition := func(name string) (*v1alpha1.Condition, error) { return nil, nil } - pipelineState, err := ResolvePipelineRun(context.Background(), pr, getTask, getTaskRun, getClusterTask, getCondition, p.Spec.Tasks, providedResources) + pipelineState, err := ResolvePipelineRun(context.Background(), pr, getTask, getTaskRun, nopGetRun, getClusterTask, getCondition, p.Spec.Tasks, providedResources) if err != nil { t.Fatalf("Error getting tasks for fake pipeline %s: %s", p.ObjectMeta.Name, err) } @@ -2063,55 +2145,50 @@ func TestResolveConditionChecks(t *testing.T) { }, } - tcs := []struct { + for _, tc := range []struct { name string getTaskRun resources.GetTaskRun expectedConditionCheck TaskConditionCheckState - }{ - { - name: "conditionCheck exists", - getTaskRun: func(name string) (*v1beta1.TaskRun, error) { - switch name { - case "pipelinerun-mytask1-9l9zj-always-true-0-mz4c7": - return cc, nil - case "pipelinerun-mytask1-9l9zj": - return &trs[0], nil - default: - return nil, fmt.Errorf("getTaskRun called with unexpected name %s", name) - } - }, - expectedConditionCheck: TaskConditionCheckState{{ - ConditionRegisterName: "always-true-0", - ConditionCheckName: "pipelinerun-mytask1-9l9zj-always-true-0-mz4c7", - Condition: &condition, - ConditionCheck: v1beta1.NewConditionCheck(cc), - PipelineTaskCondition: &ptc, - ResolvedResources: providedResources, - }}, - }, - { - name: "conditionCheck doesn't exist", - getTaskRun: func(name string) (*v1beta1.TaskRun, error) { - if name == "pipelinerun-mytask1-mssqb-always-true-0-78c5n" { - return nil, nil - } else if name == "pipelinerun-mytask1-mssqb" { - return &trs[0], nil - } + }{{ + name: "conditionCheck exists", + getTaskRun: func(name string) (*v1beta1.TaskRun, error) { + switch name { + case "pipelinerun-mytask1-9l9zj-always-true-0-mz4c7": + return cc, nil + case "pipelinerun-mytask1-9l9zj": + return &trs[0], nil + default: return nil, fmt.Errorf("getTaskRun called with unexpected name %s", name) - }, - expectedConditionCheck: TaskConditionCheckState{{ - ConditionRegisterName: "always-true-0", - ConditionCheckName: "pipelinerun-mytask1-mssqb-always-true-0-78c5n", - Condition: &condition, - PipelineTaskCondition: &ptc, - ResolvedResources: providedResources, - }}, + } }, - } - - for _, tc := range tcs { + expectedConditionCheck: TaskConditionCheckState{{ + ConditionRegisterName: "always-true-0", + ConditionCheckName: "pipelinerun-mytask1-9l9zj-always-true-0-mz4c7", + Condition: &condition, + ConditionCheck: v1beta1.NewConditionCheck(cc), + PipelineTaskCondition: &ptc, + ResolvedResources: providedResources, + }}, + }, { + name: "conditionCheck doesn't exist", + getTaskRun: func(name string) (*v1beta1.TaskRun, error) { + if name == "pipelinerun-mytask1-mssqb-always-true-0-78c5n" { + return nil, nil + } else if name == "pipelinerun-mytask1-mssqb" { + return &trs[0], nil + } + return nil, fmt.Errorf("getTaskRun called with unexpected name %s", name) + }, + expectedConditionCheck: TaskConditionCheckState{{ + ConditionRegisterName: "always-true-0", + ConditionCheckName: "pipelinerun-mytask1-mssqb-always-true-0-78c5n", + Condition: &condition, + PipelineTaskCondition: &ptc, + ResolvedResources: providedResources, + }}, + }} { t.Run(tc.name, func(t *testing.T) { - pipelineState, err := ResolvePipelineRun(context.Background(), pr, getTask, tc.getTaskRun, getClusterTask, getCondition, pts, providedResources) + pipelineState, err := ResolvePipelineRun(context.Background(), pr, getTask, tc.getTaskRun, nopGetRun, getClusterTask, getCondition, pts, providedResources) if err != nil { t.Fatalf("Did not expect error when resolving PipelineRun without Conditions: %v", err) } @@ -2166,53 +2243,40 @@ func TestResolveConditionChecks_MultipleConditions(t *testing.T) { }, } - tcs := []struct { - name string - getTaskRun resources.GetTaskRun - expectedConditionCheck TaskConditionCheckState - }{ - { - name: "conditionCheck exists", - getTaskRun: func(name string) (*v1beta1.TaskRun, error) { - switch name { - case "pipelinerun-mytask1-9l9zj-always-true-0-mz4c7": - return cc1, nil - case "pipelinerun-mytask1-9l9zj": - return &trs[0], nil - case "pipelinerun-mytask1-9l9zj-always-true-1-mssqb": - return cc2, nil - } - return nil, fmt.Errorf("getTaskRun called with unexpected name %s", name) - }, - expectedConditionCheck: TaskConditionCheckState{{ - ConditionRegisterName: "always-true-0", - ConditionCheckName: "pipelinerun-mytask1-9l9zj-always-true-0-mz4c7", - Condition: &condition, - ConditionCheck: v1beta1.NewConditionCheck(cc1), - PipelineTaskCondition: &ptc1, - ResolvedResources: providedResources, - }, { - ConditionRegisterName: "always-true-1", - ConditionCheckName: "pipelinerun-mytask1-9l9zj-always-true-1-mssqb", - Condition: &condition, - ConditionCheck: v1beta1.NewConditionCheck(cc2), - PipelineTaskCondition: &ptc2, - ResolvedResources: providedResources, - }}, - }, + getTaskRun := func(name string) (*v1beta1.TaskRun, error) { + switch name { + case "pipelinerun-mytask1-9l9zj-always-true-0-mz4c7": + return cc1, nil + case "pipelinerun-mytask1-9l9zj": + return &trs[0], nil + case "pipelinerun-mytask1-9l9zj-always-true-1-mssqb": + return cc2, nil + } + return nil, fmt.Errorf("getTaskRun called with unexpected name %s", name) } + expectedConditionCheck := TaskConditionCheckState{{ + ConditionRegisterName: "always-true-0", + ConditionCheckName: "pipelinerun-mytask1-9l9zj-always-true-0-mz4c7", + Condition: &condition, + ConditionCheck: v1beta1.NewConditionCheck(cc1), + PipelineTaskCondition: &ptc1, + ResolvedResources: providedResources, + }, { + ConditionRegisterName: "always-true-1", + ConditionCheckName: "pipelinerun-mytask1-9l9zj-always-true-1-mssqb", + Condition: &condition, + ConditionCheck: v1beta1.NewConditionCheck(cc2), + PipelineTaskCondition: &ptc2, + ResolvedResources: providedResources, + }} - for _, tc := range tcs { - t.Run(tc.name, func(t *testing.T) { - pipelineState, err := ResolvePipelineRun(context.Background(), pr, getTask, tc.getTaskRun, getClusterTask, getCondition, pts, providedResources) - if err != nil { - t.Fatalf("Did not expect error when resolving PipelineRun without Conditions: %v", err) - } + pipelineState, err := ResolvePipelineRun(context.Background(), pr, getTask, getTaskRun, nopGetRun, getClusterTask, getCondition, pts, providedResources) + if err != nil { + t.Fatalf("Did not expect error when resolving PipelineRun without Conditions: %v", err) + } - if d := cmp.Diff(tc.expectedConditionCheck, pipelineState[0].ResolvedConditionChecks, cmpopts.IgnoreUnexported(v1beta1.TaskRunSpec{}, ResolvedConditionCheck{})); d != "" { - t.Fatalf("ConditionChecks did not resolve as expected for case %s %s", tc.name, diff.PrintWantGot(d)) - } - }) + if d := cmp.Diff(expectedConditionCheck, pipelineState[0].ResolvedConditionChecks, cmpopts.IgnoreUnexported(v1beta1.TaskRunSpec{}, ResolvedConditionCheck{})); d != "" { + t.Fatalf("ConditionChecks did not resolve as expected: %s", diff.PrintWantGot(d)) } } func TestResolveConditionChecks_ConditionDoesNotExist(t *testing.T) { @@ -2248,7 +2312,7 @@ func TestResolveConditionChecks_ConditionDoesNotExist(t *testing.T) { }, } - _, err := ResolvePipelineRun(context.Background(), pr, getTask, getTaskRun, getClusterTask, getCondition, pts, providedResources) + _, err := ResolvePipelineRun(context.Background(), pr, getTask, getTaskRun, nopGetRun, getClusterTask, getCondition, pts, providedResources) switch err := err.(type) { case nil: @@ -2317,7 +2381,7 @@ func TestResolveConditionCheck_UseExistingConditionCheckName(t *testing.T) { }, } - pipelineState, err := ResolvePipelineRun(context.Background(), pr, getTask, getTaskRun, getClusterTask, getCondition, pts, providedResources) + pipelineState, err := ResolvePipelineRun(context.Background(), pr, getTask, getTaskRun, nopGetRun, getClusterTask, getCondition, pts, providedResources) if err != nil { t.Fatalf("Did not expect error when resolving PipelineRun without Conditions: %v", err) } @@ -2376,7 +2440,7 @@ func TestResolvedConditionCheck_WithResources(t *testing.T) { }, } - tcs := []struct { + for _, tc := range []struct { name string providedResources map[string]*resourcev1alpha1.PipelineResource wantErr bool @@ -2389,11 +2453,9 @@ func TestResolvedConditionCheck_WithResources(t *testing.T) { name: "resource does not exist", providedResources: map[string]*resourcev1alpha1.PipelineResource{}, wantErr: true, - }} - - for _, tc := range tcs { + }} { t.Run(tc.name, func(t *testing.T) { - pipelineState, err := ResolvePipelineRun(context.Background(), pr, getTask, getTaskRun, getClusterTask, getCondition, pts, tc.providedResources) + pipelineState, err := ResolvePipelineRun(context.Background(), pr, getTask, getTaskRun, nopGetRun, getClusterTask, getCondition, pts, tc.providedResources) if tc.wantErr { if err == nil { @@ -2497,7 +2559,7 @@ func TestIsBeforeFirstTaskRun_WithStartedTask(t *testing.T) { } func TestPipelineRunState_GetFinalTasks(t *testing.T) { - tcs := []struct { + for _, tc := range []struct { name string desc string state PipelineRunState @@ -2642,8 +2704,7 @@ func TestPipelineRunState_GetFinalTasks(t *testing.T) { DAGTasks: []v1beta1.PipelineTask{pts[0], pts[5], pts[7], pts[8]}, finalTasks: []v1beta1.PipelineTask{pts[1]}, expectedFinalTasks: []*ResolvedPipelineRunTask{}, - }} - for _, tc := range tcs { + }} { dagGraph, err := dag.Build(v1beta1.PipelineTaskList(tc.DAGTasks)) if err != nil { t.Fatalf("Unexpected error while buildig DAG for pipelineTasks %v: %v", tc.DAGTasks, err) @@ -2660,3 +2721,46 @@ func TestPipelineRunState_GetFinalTasks(t *testing.T) { }) } } + +func TestIsCustomTask(t *testing.T) { + for _, tc := range []struct { + name string + rprt ResolvedPipelineRunTask + want bool + }{{ + name: "custom", + rprt: ResolvedPipelineRunTask{ + PipelineTask: &v1beta1.PipelineTask{ + TaskRef: &v1beta1.TaskRef{ + APIVersion: "example.dev/v0", + }, + }, + }, + want: true, + }, { + name: "non-custom taskref", + rprt: ResolvedPipelineRunTask{ + PipelineTask: &v1beta1.PipelineTask{ + TaskRef: &v1beta1.TaskRef{ + Name: "task", + }, + }, + }, + want: false, + }, { + name: "non-custom taskspec", + rprt: ResolvedPipelineRunTask{ + PipelineTask: &v1beta1.PipelineTask{ + TaskSpec: &v1beta1.EmbeddedTask{}, + }, + }, + want: false, + }} { + t.Run(tc.name, func(t *testing.T) { + got := tc.rprt.IsCustomTask() + if d := cmp.Diff(tc.want, got); d != "" { + t.Errorf("IsCustomTask: %s", diff.PrintWantGot(d)) + } + }) + } +} diff --git a/test/clients.go b/test/clients.go index d05d17ad4e1..8be6ed46339 100644 --- a/test/clients.go +++ b/test/clients.go @@ -60,6 +60,7 @@ type clients struct { PipelineRunClient v1beta1.PipelineRunInterface PipelineResourceClient resourcev1alpha1.PipelineResourceInterface ConditionClient v1alpha1.ConditionInterface + RunClient v1alpha1.RunInterface } // newClients instantiates and returns several clientsets required for making requests to the @@ -95,5 +96,6 @@ func newClients(t *testing.T, configPath, clusterName, namespace string) *client c.PipelineRunClient = cs.TektonV1beta1().PipelineRuns(namespace) c.PipelineResourceClient = rcs.TektonV1alpha1().PipelineResources(namespace) c.ConditionClient = cs.TektonV1alpha1().Conditions(namespace) + c.RunClient = cs.TektonV1alpha1().Runs(namespace) return c } diff --git a/test/controller.go b/test/controller.go index b9c88b71611..8c1a524db08 100644 --- a/test/controller.go +++ b/test/controller.go @@ -20,9 +20,8 @@ import ( "context" "fmt" "sync/atomic" - "testing" + "testing" // Link in the fakes so they get injected into injection.Fake - // Link in the fakes so they get injected into injection.Fake "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" fakepipelineclientset "github.com/tektoncd/pipeline/pkg/client/clientset/versioned/fake" @@ -30,6 +29,7 @@ import ( informersv1beta1 "github.com/tektoncd/pipeline/pkg/client/informers/externalversions/pipeline/v1beta1" fakepipelineclient "github.com/tektoncd/pipeline/pkg/client/injection/client/fake" fakeconditioninformer "github.com/tektoncd/pipeline/pkg/client/injection/informers/pipeline/v1alpha1/condition/fake" + fakeruninformer "github.com/tektoncd/pipeline/pkg/client/injection/informers/pipeline/v1alpha1/run/fake" fakeclustertaskinformer "github.com/tektoncd/pipeline/pkg/client/injection/informers/pipeline/v1beta1/clustertask/fake" fakepipelineinformer "github.com/tektoncd/pipeline/pkg/client/injection/informers/pipeline/v1beta1/pipeline/fake" fakepipelineruninformer "github.com/tektoncd/pipeline/pkg/client/injection/informers/pipeline/v1beta1/pipelinerun/fake" @@ -84,6 +84,7 @@ type Informers struct { PipelineRun informersv1beta1.PipelineRunInformer Pipeline informersv1beta1.PipelineInformer TaskRun informersv1beta1.TaskRunInformer + Run informersv1alpha1.RunInformer Task informersv1beta1.TaskInformer ClusterTask informersv1beta1.ClusterTaskInformer PipelineResource resourceinformersv1alpha1.PipelineResourceInformer @@ -161,6 +162,7 @@ func SeedTestData(t *testing.T, ctx context.Context, d Data) (Clients, Informers PipelineRun: fakepipelineruninformer.Get(ctx), Pipeline: fakepipelineinformer.Get(ctx), TaskRun: faketaskruninformer.Get(ctx), + Run: fakeruninformer.Get(ctx), Task: faketaskinformer.Get(ctx), ClusterTask: fakeclustertaskinformer.Get(ctx), PipelineResource: fakeresourceinformer.Get(ctx), diff --git a/test/custom_task_test.go b/test/custom_task_test.go new file mode 100644 index 00000000000..c1bacae8be8 --- /dev/null +++ b/test/custom_task_test.go @@ -0,0 +1,118 @@ +// +build e2e + +/* +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 test + +import ( + "testing" + "time" + + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" + knativetest "knative.dev/pkg/test" +) + +const ( + apiVersion = "example.dev/v0" + kind = "Example" +) + +func TestCustomTask(t *testing.T) { + c, namespace := setup(t) + knativetest.CleanupOnInterrupt(func() { tearDown(t, c, namespace) }, t.Logf) + defer tearDown(t, c, namespace) + + // Create a PipelineRun that runs a Custom Task. + pipelineRunName := "custom-task-pipeline" + if _, err := c.PipelineRunClient.Create(&v1beta1.PipelineRun{ + ObjectMeta: metav1.ObjectMeta{Name: pipelineRunName}, + Spec: v1beta1.PipelineRunSpec{ + PipelineSpec: &v1beta1.PipelineSpec{ + Tasks: []v1beta1.PipelineTask{{ + Name: "example", + TaskRef: &v1beta1.TaskRef{ + APIVersion: apiVersion, + Kind: kind, + }, + }}, + }, + }, + }); err != nil { + t.Fatalf("Failed to create PipelineRun %q: %v", pipelineRunName, err) + } + + // Wait for the PipelineRun to start. + if err := WaitForPipelineRunState(c, pipelineRunName, time.Minute, Running(pipelineRunName), "PipelineRunRunning"); err != nil { + t.Fatalf("Waiting for PipelineRun to start running: %v", err) + } + + // Get the status of the PipelineRun. + pr, err := c.PipelineRunClient.Get(pipelineRunName, metav1.GetOptions{}) + if err != nil { + t.Fatalf("Failed to get PipelineRun %q: %v", pipelineRunName, err) + } + + // Get the Run name. + if len(pr.Status.Runs) != 1 { + t.Fatalf("PipelineRun had unexpected .status.runs; got %d, want 1", len(pr.Status.Runs)) + } + var runName string + for k := range pr.Status.Runs { + runName = k + break + } + + // Get the Run. + r, err := c.RunClient.Get(runName, metav1.GetOptions{}) + if err != nil { + t.Fatalf("Failed to get Run %q: %v", runName, err) + } + if r.IsDone() { + t.Fatalf("Run unexpectedly done: %v", r.Status.GetCondition(apis.ConditionSucceeded)) + } + + // Simulate a Custom Task controller updating the Run to + // done/successful. + r.Status = v1alpha1.RunStatus{Status: duckv1.Status{ + Conditions: duckv1.Conditions{{ + Type: apis.ConditionSucceeded, + Status: corev1.ConditionTrue, + }}, + }} + if _, err := c.RunClient.UpdateStatus(r); err != nil { + t.Fatalf("Failed to update Run to successful: %v", err) + } + + // Get the Run. + r, err = c.RunClient.Get(runName, metav1.GetOptions{}) + if err != nil { + t.Fatalf("Failed to get Run %q: %v", runName, err) + } + if !r.IsDone() { + t.Fatalf("Run unexpectedly not done after update (UpdateStatus didn't work): %v", r.Status) + } + + // Wait for the PipelineRun to become done/successful. + if err := WaitForPipelineRunState(c, pipelineRunName, time.Minute, PipelineRunSucceed(pipelineRunName), "PipelineRunCompleted"); err != nil { + t.Fatalf("Waiting for PipelineRun to complete successfully: %v", err) + } +} diff --git a/test/init_test.go b/test/init_test.go index 86a5bd16e3d..929df5f97db 100644 --- a/test/init_test.go +++ b/test/init_test.go @@ -34,13 +34,10 @@ import ( "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/wait" - knativetest "knative.dev/pkg/test" - "knative.dev/pkg/test/logging" - - // Mysteriously by k8s libs, or they fail to create `KubeClient`s from config. Apparently just importing it is enough. @_@ side effects @_@. https://github.com/kubernetes/client-go/issues/242 - _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" - // Mysteriously by k8s libs, or they fail to create `KubeClient`s when using oidc authentication. Apparently just importing it is enough. @_@ side effects @_@. https://github.com/kubernetes/client-go/issues/345 + _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" // Mysteriously by k8s libs, or they fail to create `KubeClient`s when using oidc authentication. Apparently just importing it is enough. @_@ side effects @_@. https://github.com/kubernetes/client-go/issues/345 _ "k8s.io/client-go/plugin/pkg/client/auth/oidc" + knativetest "knative.dev/pkg/test" + "knative.dev/pkg/test/logging" // Mysteriously by k8s libs, or they fail to create `KubeClient`s from config. Apparently just importing it is enough. @_@ side effects @_@. https://github.com/kubernetes/client-go/issues/242 ) var initMetrics sync.Once @@ -205,14 +202,31 @@ func getCRDYaml(cs *clients, ns string) ([]byte, error) { for _, i := range ts.Items { printOrAdd(i) } + + cts, err := cs.ClusterTaskClient.List(metav1.ListOptions{}) + if err != nil { + return nil, fmt.Errorf("could not get clustertasks: %w", err) + } + for _, i := range cts.Items { + printOrAdd(i) + } + trs, err := cs.TaskRunClient.List(metav1.ListOptions{}) if err != nil { - return nil, fmt.Errorf("could not get taskrun: %w", err) + return nil, fmt.Errorf("could not get taskruns: %w", err) } for _, i := range trs.Items { printOrAdd(i) } + rs, err := cs.RunClient.List(metav1.ListOptions{}) + if err != nil { + return nil, fmt.Errorf("could not get runs: %v", err) + } + for _, i := range rs.Items { + printOrAdd(i) + } + pods, err := cs.KubeClient.Kube.CoreV1().Pods(ns).List(metav1.ListOptions{}) if err != nil { return nil, fmt.Errorf("could not get pods: %w", err) diff --git a/third_party/LICENSE b/third_party/LICENSE new file mode 100644 index 00000000000..6a66aea5eaf --- /dev/null +++ b/third_party/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/third_party/github.com/docker/cli/cli/config/NOTICE b/third_party/github.com/docker/cli/cli/config/NOTICE index 0c74e15b057..58b19b6d15b 100644 --- a/third_party/github.com/docker/cli/cli/config/NOTICE +++ b/third_party/github.com/docker/cli/cli/config/NOTICE @@ -3,7 +3,7 @@ Copyright 2012-2017 Docker, Inc. This product includes software developed at Docker, Inc. (https://www.docker.com). -This product contains software (https://github.com/kr/pty) developed +This product contains software (https://github.com/creack/pty) developed by Keith Rarick, licensed under the MIT License. The following is courtesy of our legal counsel: diff --git a/third_party/vendor/golang.org/x/crypto/LICENSE b/third_party/vendor/golang.org/x/crypto/LICENSE new file mode 100644 index 00000000000..6a66aea5eaf --- /dev/null +++ b/third_party/vendor/golang.org/x/crypto/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/third_party/vendor/golang.org/x/net/LICENSE b/third_party/vendor/golang.org/x/net/LICENSE new file mode 100644 index 00000000000..6a66aea5eaf --- /dev/null +++ b/third_party/vendor/golang.org/x/net/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/third_party/vendor/golang.org/x/sys/cpu/LICENSE b/third_party/vendor/golang.org/x/sys/cpu/LICENSE new file mode 100644 index 00000000000..6a66aea5eaf --- /dev/null +++ b/third_party/vendor/golang.org/x/sys/cpu/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/third_party/vendor/golang.org/x/text/LICENSE b/third_party/vendor/golang.org/x/text/LICENSE new file mode 100644 index 00000000000..6a66aea5eaf --- /dev/null +++ b/third_party/vendor/golang.org/x/text/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/docker/cli/AUTHORS b/vendor/github.com/docker/cli/AUTHORS index 04edcf794e2..ecb6251ba0d 100644 --- a/vendor/github.com/docker/cli/AUTHORS +++ b/vendor/github.com/docker/cli/AUTHORS @@ -11,6 +11,7 @@ Abin Shahab Ace Tang Addam Hardy Adolfo Ochagavía +Adrian Plata Adrien Duermael Adrien Folie Ahmet Alp Balkan @@ -136,6 +137,7 @@ Dafydd Crosby dalanlan Damien Nadé Dan Cotora +Daniel Cassidy Daniel Dao Daniel Farrell Daniel Gasienica @@ -215,6 +217,7 @@ Felix Rabe Filip Jareš Flavio Crisciani Florian Klein +Forest Johnson Foysal Iqbal François Scala Fred Lifton @@ -231,6 +234,7 @@ George MacRorie George Xie Gianluca Borello Gildas Cuisinier +Goksu Toprak Gou Rao Grant Reaber Greg Pflaum @@ -351,6 +355,7 @@ Kara Alexandra Kareem Khazem Karthik Nayak Kat Samperi +Kathryn Spiers Katie McLaughlin Ke Xu Kei Ohmura @@ -372,7 +377,6 @@ Krasi Georgiev Kris-Mikael Krister Kun Zhang Kunal Kushwaha -Kyle Spiers Lachlan Cooper Lai Jiangshan Lars Kellogg-Stedman @@ -537,6 +541,7 @@ Qiang Huang Qinglan Peng qudongfang Raghavendra K T +Ravi Shekhar Jethani Ray Tsang Reficul Remy Suen @@ -553,6 +558,7 @@ Robin Naundorf Robin Speekenbrink Rodolfo Ortiz Rogelio Canedo +Rohan Verma Roland Kammerer Roman Dudin Rory Hunter @@ -701,6 +707,7 @@ Yuan Sun Yue Zhang Yunxiang Huang Zachary Romero +Zander Mackie zebrilee Zhang Kun Zhang Wei diff --git a/vendor/github.com/docker/cli/NOTICE b/vendor/github.com/docker/cli/NOTICE index 0c74e15b057..58b19b6d15b 100644 --- a/vendor/github.com/docker/cli/NOTICE +++ b/vendor/github.com/docker/cli/NOTICE @@ -3,7 +3,7 @@ Copyright 2012-2017 Docker, Inc. This product includes software developed at Docker, Inc. (https://www.docker.com). -This product contains software (https://github.com/kr/pty) developed +This product contains software (https://github.com/creack/pty) developed by Keith Rarick, licensed under the MIT License. The following is courtesy of our legal counsel: diff --git a/vendor/github.com/docker/cli/cli/config/config.go b/vendor/github.com/docker/cli/cli/config/config.go index f5e33f2b3e9..6e4d73dfad7 100644 --- a/vendor/github.com/docker/cli/cli/config/config.go +++ b/vendor/github.com/docker/cli/cli/config/config.go @@ -106,9 +106,13 @@ func Load(configDir string) (*configfile.ConfigFile, error) { } // Can't find latest config file so check for the old one - confFile := filepath.Join(homedir.Get(), oldConfigfile) + homedir, err := os.UserHomeDir() + if err != nil { + return configFile, errors.Wrap(err, oldConfigfile) + } + confFile := filepath.Join(homedir, oldConfigfile) if _, err := os.Stat(confFile); err != nil { - return configFile, nil //missing file is not an error + return configFile, nil // missing file is not an error } file, err := os.Open(confFile) if err != nil { diff --git a/vendor/github.com/docker/cli/cli/config/configfile/file.go b/vendor/github.com/docker/cli/cli/config/configfile/file.go index 388a5d54d69..a4e97a5caa6 100644 --- a/vendor/github.com/docker/cli/cli/config/configfile/file.go +++ b/vendor/github.com/docker/cli/cli/config/configfile/file.go @@ -196,6 +196,9 @@ func (configFile *ConfigFile) Save() error { os.Remove(temp.Name()) return err } + // Try copying the current config file (if any) ownership and permissions + copyFilePermissions(configFile.Filename, temp.Name()) + return os.Rename(temp.Name(), configFile.Filename) } diff --git a/vendor/github.com/docker/cli/cli/config/configfile/file_unix.go b/vendor/github.com/docker/cli/cli/config/configfile/file_unix.go new file mode 100644 index 00000000000..3ca65c6140d --- /dev/null +++ b/vendor/github.com/docker/cli/cli/config/configfile/file_unix.go @@ -0,0 +1,35 @@ +// +build !windows + +package configfile + +import ( + "os" + "syscall" +) + +// copyFilePermissions copies file ownership and permissions from "src" to "dst", +// ignoring any error during the process. +func copyFilePermissions(src, dst string) { + var ( + mode os.FileMode = 0600 + uid, gid int + ) + + fi, err := os.Stat(src) + if err != nil { + return + } + if fi.Mode().IsRegular() { + mode = fi.Mode() + } + if err := os.Chmod(dst, mode); err != nil { + return + } + + uid = int(fi.Sys().(*syscall.Stat_t).Uid) + gid = int(fi.Sys().(*syscall.Stat_t).Gid) + + if uid > 0 && gid > 0 { + _ = os.Chown(dst, uid, gid) + } +} diff --git a/vendor/github.com/docker/cli/cli/config/configfile/file_windows.go b/vendor/github.com/docker/cli/cli/config/configfile/file_windows.go new file mode 100644 index 00000000000..42fffc39ad2 --- /dev/null +++ b/vendor/github.com/docker/cli/cli/config/configfile/file_windows.go @@ -0,0 +1,5 @@ +package configfile + +func copyFilePermissions(src, dst string) { + // TODO implement for Windows +} diff --git a/vendor/modules.txt b/vendor/modules.txt index a15f3998765..85b4b25edde 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -118,7 +118,7 @@ github.com/cloudevents/sdk-go/v2/types github.com/davecgh/go-spew/spew # github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/dgrijalva/jwt-go -# github.com/docker/cli v0.0.0-20200210162036-a4bedce16568 +# github.com/docker/cli v0.0.0-20200303162255-7d407207c304 github.com/docker/cli/cli/config github.com/docker/cli/cli/config/configfile github.com/docker/cli/cli/config/credentials