Install base plugins
This commit is contained in:
		
							parent
							
								
									f3093cdbbc
								
							
						
					
					
						commit
						af9f7f4e76
					
				|  | @ -2,250 +2,323 @@ | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|  |   digest = "1:8713dd3229c46881bb56b24fa3b581a0faab01d12e2d973a830965c24061e449" | ||||||
|   name = "cloud.google.com/go" |   name = "cloud.google.com/go" | ||||||
|   packages = ["compute/metadata"] |   packages = ["compute/metadata"] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "1fd54cf41e6e0e178ffe3c52b0e2260281f603e3" |   revision = "1fd54cf41e6e0e178ffe3c52b0e2260281f603e3" | ||||||
|   version = "v0.32.0" |   version = "v0.32.0" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|  |   digest = "1:75d2b55b13298745ec068057251d05d65bbae0a668201fe45ad6986551a55601" | ||||||
|   name = "github.com/BurntSushi/toml" |   name = "github.com/BurntSushi/toml" | ||||||
|   packages = ["."] |   packages = ["."] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "3012a1dbe2e4bd1391d42b32f0577cb7bbc7f005" |   revision = "3012a1dbe2e4bd1391d42b32f0577cb7bbc7f005" | ||||||
|   version = "v0.3.1" |   version = "v0.3.1" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|  |   digest = "1:d8ebbd207f3d3266d4423ce4860c9f3794956306ded6c7ba312ecc69cdfbf04c" | ||||||
|   name = "github.com/PuerkitoBio/purell" |   name = "github.com/PuerkitoBio/purell" | ||||||
|   packages = ["."] |   packages = ["."] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "0bcb03f4b4d0a9428594752bd2a3b9aa0a9d4bd4" |   revision = "0bcb03f4b4d0a9428594752bd2a3b9aa0a9d4bd4" | ||||||
|   version = "v1.1.0" |   version = "v1.1.0" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|   branch = "master" |   branch = "master" | ||||||
|  |   digest = "1:8098cd40cd09879efbf12e33bcd51ead4a66006ac802cd563a66c4f3373b9727" | ||||||
|   name = "github.com/PuerkitoBio/urlesc" |   name = "github.com/PuerkitoBio/urlesc" | ||||||
|   packages = ["."] |   packages = ["."] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "de5bf2ad457846296e2031421a34e2568e304e35" |   revision = "de5bf2ad457846296e2031421a34e2568e304e35" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|  |   digest = "1:8d13c70d5898b091728540686c696baee0d64013b8e43089da80621a49410391" | ||||||
|   name = "github.com/bndr/gojenkins" |   name = "github.com/bndr/gojenkins" | ||||||
|   packages = ["."] |   packages = ["."] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "de43c03cf849dd63a9737df6e05791c7a176c93d" |   revision = "de43c03cf849dd63a9737df6e05791c7a176c93d" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|  |   digest = "1:4b8b5811da6970495e04d1f4e98bb89518cc3cfc3b3f456bdb876ed7b6c74049" | ||||||
|   name = "github.com/davecgh/go-spew" |   name = "github.com/davecgh/go-spew" | ||||||
|   packages = ["spew"] |   packages = ["spew"] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "8991bc29aa16c548c550c7ff78260e27b9ab7c73" |   revision = "8991bc29aa16c548c550c7ff78260e27b9ab7c73" | ||||||
|   version = "v1.1.1" |   version = "v1.1.1" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|  |   digest = "1:707c9f4ee70cc3bb941cf5803d9b8e725bc02277a96301ac8e537510a712ec7c" | ||||||
|   name = "github.com/docker/distribution" |   name = "github.com/docker/distribution" | ||||||
|   packages = [ |   packages = [ | ||||||
|     "digest", |     "digest", | ||||||
|     "reference" |     "reference", | ||||||
|   ] |   ] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "48294d928ced5dd9b378f7fd7c6f5da3ff3f2c89" |   revision = "48294d928ced5dd9b378f7fd7c6f5da3ff3f2c89" | ||||||
|   version = "v2.6.2" |   version = "v2.6.2" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|  |   digest = "1:e6f888d4be8ec0f05c50e2aba83da4948b58045dee54d03be81fa74ea673302c" | ||||||
|   name = "github.com/emicklei/go-restful" |   name = "github.com/emicklei/go-restful" | ||||||
|   packages = [ |   packages = [ | ||||||
|     ".", |     ".", | ||||||
|     "log" |     "log", | ||||||
|   ] |   ] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "3eb9738c1697594ea6e71a7156a9bb32ed216cf0" |   revision = "3eb9738c1697594ea6e71a7156a9bb32ed216cf0" | ||||||
|   version = "v2.8.0" |   version = "v2.8.0" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|  |   digest = "1:81466b4218bf6adddac2572a30ac733a9255919bc2f470b4827a317bd4ee1756" | ||||||
|   name = "github.com/ghodss/yaml" |   name = "github.com/ghodss/yaml" | ||||||
|   packages = ["."] |   packages = ["."] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "0ca9ea5df5451ffdf184b4428c902747c2c11cd7" |   revision = "0ca9ea5df5451ffdf184b4428c902747c2c11cd7" | ||||||
|   version = "v1.0.0" |   version = "v1.0.0" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|   branch = "master" |   branch = "master" | ||||||
|  |   digest = "1:d421af4c4fe51d399667d573982d663fe1fa67020a88d3ae43466ebfe8e2b5c9" | ||||||
|   name = "github.com/go-logr/logr" |   name = "github.com/go-logr/logr" | ||||||
|   packages = ["."] |   packages = ["."] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "9fb12b3b21c5415d16ac18dc5cd42c1cfdd40c4e" |   revision = "9fb12b3b21c5415d16ac18dc5cd42c1cfdd40c4e" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|  |   digest = "1:340497a512995aa69c0add901d79a2096b3449d35a44a6f1f1115091a9f8c687" | ||||||
|   name = "github.com/go-logr/zapr" |   name = "github.com/go-logr/zapr" | ||||||
|   packages = ["."] |   packages = ["."] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "7536572e8d55209135cd5e7ccf7fce43dca217ab" |   revision = "7536572e8d55209135cd5e7ccf7fce43dca217ab" | ||||||
|   version = "v0.1.0" |   version = "v0.1.0" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|  |   digest = "1:260f7ebefc63024c8dfe2c9f1a2935a89fa4213637a1f522f592f80c001cc441" | ||||||
|   name = "github.com/go-openapi/jsonpointer" |   name = "github.com/go-openapi/jsonpointer" | ||||||
|   packages = ["."] |   packages = ["."] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "ef5f0afec364d3b9396b7b77b43dbe26bf1f8004" |   revision = "ef5f0afec364d3b9396b7b77b43dbe26bf1f8004" | ||||||
|   version = "v0.17.2" |   version = "v0.17.2" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|  |   digest = "1:98abd61947ff5c7c6fcfec5473d02a4821ed3a2dd99a4fbfdb7925b0dd745546" | ||||||
|   name = "github.com/go-openapi/jsonreference" |   name = "github.com/go-openapi/jsonreference" | ||||||
|   packages = ["."] |   packages = ["."] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "8483a886a90412cd6858df4ea3483dce9c8e35a3" |   revision = "8483a886a90412cd6858df4ea3483dce9c8e35a3" | ||||||
|   version = "v0.17.2" |   version = "v0.17.2" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|   branch = "master" |   branch = "master" | ||||||
|  |   digest = "1:dfab391de021809e0041f0ab5648da6b74dd16a685472a1b8c3dc06b3dca1ee2" | ||||||
|   name = "github.com/go-openapi/spec" |   name = "github.com/go-openapi/spec" | ||||||
|   packages = ["."] |   packages = ["."] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "5bae59e25b21498baea7f9d46e9c147ec106a42e" |   revision = "5bae59e25b21498baea7f9d46e9c147ec106a42e" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|  |   digest = "1:983f95b2fae6fe8fdd361738325ed6090f4f3bd15ce4db745e899fb5b0fdfc46" | ||||||
|   name = "github.com/go-openapi/swag" |   name = "github.com/go-openapi/swag" | ||||||
|   packages = ["."] |   packages = ["."] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "5899d5c5e619fda5fa86e14795a835f473ca284c" |   revision = "5899d5c5e619fda5fa86e14795a835f473ca284c" | ||||||
|   version = "v0.17.2" |   version = "v0.17.2" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|  |   digest = "1:4fb6ac9e2e67130ed8c5db4154684b390c1c0ce213ba3f4532b7edc614f78999" | ||||||
|   name = "github.com/gobuffalo/envy" |   name = "github.com/gobuffalo/envy" | ||||||
|   packages = ["."] |   packages = ["."] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "801d7253ade1f895f74596b9a96147ed2d3b087e" |   revision = "801d7253ade1f895f74596b9a96147ed2d3b087e" | ||||||
|   version = "v1.6.11" |   version = "v1.6.11" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|  |   digest = "1:2a9d5e367df8c95e780975ca1dd4010bef8e39a3777066d3880ce274b39d4b5a" | ||||||
|   name = "github.com/gogo/protobuf" |   name = "github.com/gogo/protobuf" | ||||||
|   packages = [ |   packages = [ | ||||||
|     "proto", |     "proto", | ||||||
|     "sortkeys" |     "sortkeys", | ||||||
|   ] |   ] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "636bf0302bc95575d69441b25a2603156ffdddf1" |   revision = "636bf0302bc95575d69441b25a2603156ffdddf1" | ||||||
|   version = "v1.1.1" |   version = "v1.1.1" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|   branch = "master" |   branch = "master" | ||||||
|  |   digest = "1:e2b86e41f3d669fc36b50d31d32d22c8ac656c75aa5ea89717ce7177e134ff2a" | ||||||
|   name = "github.com/golang/glog" |   name = "github.com/golang/glog" | ||||||
|   packages = ["."] |   packages = ["."] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "23def4e6c14b4da8ac2ed8007337bc5eb5007998" |   revision = "23def4e6c14b4da8ac2ed8007337bc5eb5007998" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|   branch = "master" |   branch = "master" | ||||||
|  |   digest = "1:aaedc94233e56ed57cdb04e3abfacc85c90c14082b62e3cdbe8ea72fc06ee035" | ||||||
|   name = "github.com/golang/groupcache" |   name = "github.com/golang/groupcache" | ||||||
|   packages = ["lru"] |   packages = ["lru"] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "c65c006176ff7ff98bb916961c7abbc6b0afc0aa" |   revision = "c65c006176ff7ff98bb916961c7abbc6b0afc0aa" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|  |   digest = "1:d7cb4458ea8782e6efacd8f4940796ec559c90833509c436f40c4085b98156dd" | ||||||
|   name = "github.com/golang/protobuf" |   name = "github.com/golang/protobuf" | ||||||
|   packages = [ |   packages = [ | ||||||
|     "proto", |     "proto", | ||||||
|     "ptypes", |     "ptypes", | ||||||
|     "ptypes/any", |     "ptypes/any", | ||||||
|     "ptypes/duration", |     "ptypes/duration", | ||||||
|     "ptypes/timestamp" |     "ptypes/timestamp", | ||||||
|   ] |   ] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "aa810b61a9c79d51363740d207bb46cf8e620ed5" |   revision = "aa810b61a9c79d51363740d207bb46cf8e620ed5" | ||||||
|   version = "v1.2.0" |   version = "v1.2.0" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|   branch = "master" |   branch = "master" | ||||||
|  |   digest = "1:05f95ffdfcf651bdb0f05b40b69e7f5663047f8da75c72d58728acb59b5cc107" | ||||||
|   name = "github.com/google/btree" |   name = "github.com/google/btree" | ||||||
|   packages = ["."] |   packages = ["."] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "4030bb1f1f0c35b30ca7009e9ebd06849dd45306" |   revision = "4030bb1f1f0c35b30ca7009e9ebd06849dd45306" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|   branch = "master" |   branch = "master" | ||||||
|  |   digest = "1:52c5834e2bebac9030c97cc0798ac11c3aa8a39f098aeb419f142533da6cd3cc" | ||||||
|   name = "github.com/google/gofuzz" |   name = "github.com/google/gofuzz" | ||||||
|   packages = ["."] |   packages = ["."] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "24818f796faf91cd76ec7bddd72458fbced7a6c1" |   revision = "24818f796faf91cd76ec7bddd72458fbced7a6c1" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|  |   digest = "1:a1578f7323eca2b88021fdc9a79a99833d40b12c32a5ea4f284e2fad19ea2657" | ||||||
|   name = "github.com/google/uuid" |   name = "github.com/google/uuid" | ||||||
|   packages = ["."] |   packages = ["."] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "d460ce9f8df2e77fb1ba55ca87fafed96c607494" |   revision = "d460ce9f8df2e77fb1ba55ca87fafed96c607494" | ||||||
|   version = "v1.0.0" |   version = "v1.0.0" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|  |   digest = "1:289332c13b80edfefc88397cce5266c16845dcf204fa2f6ac7e464ee4c7f6e96" | ||||||
|   name = "github.com/googleapis/gnostic" |   name = "github.com/googleapis/gnostic" | ||||||
|   packages = [ |   packages = [ | ||||||
|     "OpenAPIv2", |     "OpenAPIv2", | ||||||
|     "compiler", |     "compiler", | ||||||
|     "extensions" |     "extensions", | ||||||
|   ] |   ] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "7c663266750e7d82587642f65e60bc4083f1f84e" |   revision = "7c663266750e7d82587642f65e60bc4083f1f84e" | ||||||
|   version = "v0.2.0" |   version = "v0.2.0" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|   branch = "master" |   branch = "master" | ||||||
|  |   digest = "1:2a2caa63899dae26ed3e4510b806549fd416d94db24ad68279daa62881b26488" | ||||||
|   name = "github.com/gregjones/httpcache" |   name = "github.com/gregjones/httpcache" | ||||||
|   packages = [ |   packages = [ | ||||||
|     ".", |     ".", | ||||||
|     "diskcache" |     "diskcache", | ||||||
|   ] |   ] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "9cad4c3443a7200dd6400aef47183728de563a38" |   revision = "9cad4c3443a7200dd6400aef47183728de563a38" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|  |   digest = "1:b42cde0e1f3c816dd57f57f7bbcf05ca40263ad96f168714c130c611fc0856a6" | ||||||
|   name = "github.com/hashicorp/golang-lru" |   name = "github.com/hashicorp/golang-lru" | ||||||
|   packages = [ |   packages = [ | ||||||
|     ".", |     ".", | ||||||
|     "simplelru" |     "simplelru", | ||||||
|   ] |   ] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "20f1fb78b0740ba8c3cb143a61e86ba5c8669768" |   revision = "20f1fb78b0740ba8c3cb143a61e86ba5c8669768" | ||||||
|   version = "v0.5.0" |   version = "v0.5.0" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|  |   digest = "1:9a52adf44086cead3b384e5d0dbf7a1c1cce65e67552ee3383a8561c42a18cd3" | ||||||
|   name = "github.com/imdario/mergo" |   name = "github.com/imdario/mergo" | ||||||
|   packages = ["."] |   packages = ["."] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "9f23e2d6bd2a77f959b2bf6acdbefd708a83a4a4" |   revision = "9f23e2d6bd2a77f959b2bf6acdbefd708a83a4a4" | ||||||
|   version = "v0.3.6" |   version = "v0.3.6" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|  |   digest = "1:f5b9328966ccea0970b1d15075698eff0ddb3e75889560aad2e9f76b289b536a" | ||||||
|   name = "github.com/joho/godotenv" |   name = "github.com/joho/godotenv" | ||||||
|   packages = ["."] |   packages = ["."] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "23d116af351c84513e1946b527c88823e476be13" |   revision = "23d116af351c84513e1946b527c88823e476be13" | ||||||
|   version = "v1.3.0" |   version = "v1.3.0" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|  |   digest = "1:1d39c063244ad17c4b18e8da1551163b6ffb52bd1640a49a8ec5c3b7bf4dbd5d" | ||||||
|   name = "github.com/json-iterator/go" |   name = "github.com/json-iterator/go" | ||||||
|   packages = ["."] |   packages = ["."] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "1624edc4454b8682399def8740d46db5e4362ba4" |   revision = "1624edc4454b8682399def8740d46db5e4362ba4" | ||||||
|   version = "v1.1.5" |   version = "v1.1.5" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|  |   digest = "1:4059c14e87a2de3a434430340521b5feece186c1469eff0834c29a63870de3ed" | ||||||
|   name = "github.com/konsorten/go-windows-terminal-sequences" |   name = "github.com/konsorten/go-windows-terminal-sequences" | ||||||
|   packages = ["."] |   packages = ["."] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "5c8c8bd35d3832f5d134ae1e1e375b69a4d25242" |   revision = "5c8c8bd35d3832f5d134ae1e1e375b69a4d25242" | ||||||
|   version = "v1.0.1" |   version = "v1.0.1" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|   branch = "master" |   branch = "master" | ||||||
|  |   digest = "1:7d9fcac7f1228470c4ea0ee31cdfb662a758c44df691e39b3e76c11d3e12ba8f" | ||||||
|   name = "github.com/mailru/easyjson" |   name = "github.com/mailru/easyjson" | ||||||
|   packages = [ |   packages = [ | ||||||
|     "buffer", |     "buffer", | ||||||
|     "jlexer", |     "jlexer", | ||||||
|     "jwriter" |     "jwriter", | ||||||
|   ] |   ] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "60711f1a8329503b04e1c88535f419d0bb440bff" |   revision = "60711f1a8329503b04e1c88535f419d0bb440bff" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|  |   digest = "1:56dbf15e091bf7926cb33a57cb6bdfc658fc6d3498d2f76f10a97ce7856f1fde" | ||||||
|   name = "github.com/markbates/inflect" |   name = "github.com/markbates/inflect" | ||||||
|   packages = ["."] |   packages = ["."] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "24b83195037b3bc61fcda2d28b7b0518bce293b6" |   revision = "24b83195037b3bc61fcda2d28b7b0518bce293b6" | ||||||
|   version = "v1.0.4" |   version = "v1.0.4" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|   branch = "master" |   branch = "master" | ||||||
|  |   digest = "1:0e9bfc47ab9941ecc3344e580baca5deb4091177e84dd9773b48b38ec26b93d5" | ||||||
|   name = "github.com/mattbaird/jsonpatch" |   name = "github.com/mattbaird/jsonpatch" | ||||||
|   packages = ["."] |   packages = ["."] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "81af80346b1a01caae0cbc27fd3c1ba5b11e189f" |   revision = "81af80346b1a01caae0cbc27fd3c1ba5b11e189f" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|  |   digest = "1:2f42fa12d6911c7b7659738758631bec870b7e9b4c6be5444f963cdcfccc191f" | ||||||
|   name = "github.com/modern-go/concurrent" |   name = "github.com/modern-go/concurrent" | ||||||
|   packages = ["."] |   packages = ["."] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "bacd9c7ef1dd9b15be4a9909b8ac7a4e313eec94" |   revision = "bacd9c7ef1dd9b15be4a9909b8ac7a4e313eec94" | ||||||
|   version = "1.0.3" |   version = "1.0.3" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|  |   digest = "1:c6aca19413b13dc59c220ad7430329e2ec454cc310bc6d8de2c7e2b93c18a0f6" | ||||||
|   name = "github.com/modern-go/reflect2" |   name = "github.com/modern-go/reflect2" | ||||||
|   packages = ["."] |   packages = ["."] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "4b7aa43c6742a2c18fdef89dd197aaae7dac7ccd" |   revision = "4b7aa43c6742a2c18fdef89dd197aaae7dac7ccd" | ||||||
|   version = "1.0.1" |   version = "1.0.1" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|  |   digest = "1:f3f95a7e55bd970e2d59af0131202401493016a7a90978cd1c4b7137d128bc1a" | ||||||
|   name = "github.com/mrtazz/checkmake" |   name = "github.com/mrtazz/checkmake" | ||||||
|   packages = ["logger"] |   packages = ["logger"] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "53de3e70f28d26a6450a845505c43165cb150b72" |   revision = "53de3e70f28d26a6450a845505c43165cb150b72" | ||||||
|   version = "0.1.0" |   version = "0.1.0" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|  |   digest = "1:121b82bf82f859edc43cc6ce42df4e231881874f576e48ba75b062fb1a2efc80" | ||||||
|   name = "github.com/operator-framework/operator-sdk" |   name = "github.com/operator-framework/operator-sdk" | ||||||
|   packages = [ |   packages = [ | ||||||
|     "internal/util/fileutil", |     "internal/util/fileutil", | ||||||
|  | @ -257,79 +330,109 @@ | ||||||
|     "pkg/scaffold/input", |     "pkg/scaffold/input", | ||||||
|     "pkg/test", |     "pkg/test", | ||||||
|     "pkg/test/e2eutil", |     "pkg/test/e2eutil", | ||||||
|     "version" |     "version", | ||||||
|   ] |   ] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "175a82edae514f57f597110af5447d3f9b1c0fc3" |   revision = "175a82edae514f57f597110af5447d3f9b1c0fc3" | ||||||
|   version = "v0.2.0" |   version = "v0.2.0" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|  |   digest = "1:93b1d84c5fa6d1ea52f4114c37714cddd84d5b78f151b62bb101128dd51399bf" | ||||||
|   name = "github.com/pborman/uuid" |   name = "github.com/pborman/uuid" | ||||||
|   packages = ["."] |   packages = ["."] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "adf5a7427709b9deb95d29d3fa8a2bf9cfd388f1" |   revision = "adf5a7427709b9deb95d29d3fa8a2bf9cfd388f1" | ||||||
|   version = "v1.2" |   version = "v1.2" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|   branch = "master" |   branch = "master" | ||||||
|  |   digest = "1:bf2ac97824a7221eb16b096aecc1c390d4c8a4e49524386aaa2e2dd215cbfb31" | ||||||
|   name = "github.com/petar/GoLLRB" |   name = "github.com/petar/GoLLRB" | ||||||
|   packages = ["llrb"] |   packages = ["llrb"] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "53be0d36a84c2a886ca057d34b6aa4468df9ccb4" |   revision = "53be0d36a84c2a886ca057d34b6aa4468df9ccb4" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|  |   digest = "1:e4e9e026b8e4c5630205cd0208efb491b40ad40552e57f7a646bb8a46896077b" | ||||||
|   name = "github.com/peterbourgon/diskv" |   name = "github.com/peterbourgon/diskv" | ||||||
|   packages = ["."] |   packages = ["."] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "5f041e8faa004a95c88a202771f4cc3e991971e6" |   revision = "5f041e8faa004a95c88a202771f4cc3e991971e6" | ||||||
|   version = "v2.0.1" |   version = "v2.0.1" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|  |   digest = "1:0028cb19b2e4c3112225cd871870f2d9cf49b9b4276531f03438a88e94be86fe" | ||||||
|  |   name = "github.com/pmezard/go-difflib" | ||||||
|  |   packages = ["difflib"] | ||||||
|  |   pruneopts = "NT" | ||||||
|  |   revision = "792786c7400a136282c1664665ae0a8db921c6c2" | ||||||
|  |   version = "v1.0.0" | ||||||
|  | 
 | ||||||
|  | [[projects]] | ||||||
|  |   digest = "1:4e63570205b765959739e2ef37add1d229cab7dbf70d80341a0608816120493b" | ||||||
|   name = "github.com/rogpeppe/go-internal" |   name = "github.com/rogpeppe/go-internal" | ||||||
|   packages = [ |   packages = [ | ||||||
|     "modfile", |     "modfile", | ||||||
|     "module", |     "module", | ||||||
|     "semver" |     "semver", | ||||||
|   ] |   ] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "d87f08a7d80821c797ffc8eb8f4e01675f378736" |   revision = "d87f08a7d80821c797ffc8eb8f4e01675f378736" | ||||||
|   version = "v1.0.0" |   version = "v1.0.0" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|  |   digest = "1:cd2f2cba5b7ffafd0412fb647ff4bcff170292de57270f05fbbf391e3eb9566b" | ||||||
|   name = "github.com/sirupsen/logrus" |   name = "github.com/sirupsen/logrus" | ||||||
|   packages = ["."] |   packages = ["."] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "bcd833dfe83d3cebad139e4a29ed79cb2318bf95" |   revision = "bcd833dfe83d3cebad139e4a29ed79cb2318bf95" | ||||||
|   version = "v1.2.0" |   version = "v1.2.0" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|  |   digest = "1:2a7c79c506479dc73c0100982a40bacc89e06d96dc458eb41c9b6aa44d9e0b6d" | ||||||
|   name = "github.com/spf13/afero" |   name = "github.com/spf13/afero" | ||||||
|   packages = [ |   packages = [ | ||||||
|     ".", |     ".", | ||||||
|     "mem" |     "mem", | ||||||
|   ] |   ] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "d40851caa0d747393da1ffb28f7f9d8b4eeffebd" |   revision = "d40851caa0d747393da1ffb28f7f9d8b4eeffebd" | ||||||
|   version = "v1.1.2" |   version = "v1.1.2" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|  |   digest = "1:9d8420bbf131d1618bde6530af37c3799340d3762cc47210c1d9532a4c3a2779" | ||||||
|   name = "github.com/spf13/pflag" |   name = "github.com/spf13/pflag" | ||||||
|   packages = ["."] |   packages = ["."] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "298182f68c66c05229eb03ac171abe6e309ee79a" |   revision = "298182f68c66c05229eb03ac171abe6e309ee79a" | ||||||
|   version = "v1.0.3" |   version = "v1.0.3" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|   branch = "master" |   digest = "1:4af061277c04a7660e082acc2020f4c66d2c21dfc62e0242ffa1d2120cdfb4ec" | ||||||
|   name = "github.com/sqs/goreturns" |   name = "github.com/stretchr/testify" | ||||||
|   packages = ["returns"] |   packages = ["assert"] | ||||||
|   revision = "538ac601451833c7c4449f8431d65d53c1c60e41" |   pruneopts = "NT" | ||||||
|  |   revision = "f35b8ab0b5a2cef36673838d662e249dd9c94686" | ||||||
|  |   version = "v1.2.2" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|  |   digest = "1:22f696cee54865fb8e9ff91df7b633f6b8f22037a8015253c6b6a71ca82219c7" | ||||||
|   name = "go.uber.org/atomic" |   name = "go.uber.org/atomic" | ||||||
|   packages = ["."] |   packages = ["."] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "1ea20fb1cbb1cc08cbd0d913a96dead89aa18289" |   revision = "1ea20fb1cbb1cc08cbd0d913a96dead89aa18289" | ||||||
|   version = "v1.3.2" |   version = "v1.3.2" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|  |   digest = "1:58ca93bdf81bac106ded02226b5395a0595d5346cdc4caa8d9c1f3a5f8f9976e" | ||||||
|   name = "go.uber.org/multierr" |   name = "go.uber.org/multierr" | ||||||
|   packages = ["."] |   packages = ["."] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "3c4937480c32f4c13a875a1829af76c98ca3d40a" |   revision = "3c4937480c32f4c13a875a1829af76c98ca3d40a" | ||||||
|   version = "v1.1.0" |   version = "v1.1.0" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|  |   digest = "1:572fa4496563920f3e3107a2294cf2621d6cc4ffd03403fb6397b1bab9fa082a" | ||||||
|   name = "go.uber.org/zap" |   name = "go.uber.org/zap" | ||||||
|   packages = [ |   packages = [ | ||||||
|     ".", |     ".", | ||||||
|  | @ -337,19 +440,23 @@ | ||||||
|     "internal/bufferpool", |     "internal/bufferpool", | ||||||
|     "internal/color", |     "internal/color", | ||||||
|     "internal/exit", |     "internal/exit", | ||||||
|     "zapcore" |     "zapcore", | ||||||
|   ] |   ] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "ff33455a0e382e8a81d14dd7c922020b6b5e7982" |   revision = "ff33455a0e382e8a81d14dd7c922020b6b5e7982" | ||||||
|   version = "v1.9.1" |   version = "v1.9.1" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|   branch = "master" |   branch = "master" | ||||||
|  |   digest = "1:47924c7ab4b3a18145d150e535525f582a07511e5452c4e1a5b79d883c2a429f" | ||||||
|   name = "golang.org/x/crypto" |   name = "golang.org/x/crypto" | ||||||
|   packages = ["ssh/terminal"] |   packages = ["ssh/terminal"] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "4d3f4d9ffa16a13f451c3b2999e9c49e9750bf06" |   revision = "4d3f4d9ffa16a13f451c3b2999e9c49e9750bf06" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|   branch = "master" |   branch = "master" | ||||||
|  |   digest = "1:a7fcf4f3e5247a06ad4c28108f0bc1d4ab980a1a0567e7790260cf2d3d77f37d" | ||||||
|   name = "golang.org/x/net" |   name = "golang.org/x/net" | ||||||
|   packages = [ |   packages = [ | ||||||
|     "context", |     "context", | ||||||
|  | @ -359,32 +466,38 @@ | ||||||
|     "http/httpguts", |     "http/httpguts", | ||||||
|     "http2", |     "http2", | ||||||
|     "http2/hpack", |     "http2/hpack", | ||||||
|     "idna" |     "idna", | ||||||
|   ] |   ] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "c10e9556a7bc0e7c942242b606f0acf024ad5d6a" |   revision = "c10e9556a7bc0e7c942242b606f0acf024ad5d6a" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|   branch = "master" |   branch = "master" | ||||||
|  |   digest = "1:b17011812136abe011d81b40b30470808df923687e831760511d878408d208df" | ||||||
|   name = "golang.org/x/oauth2" |   name = "golang.org/x/oauth2" | ||||||
|   packages = [ |   packages = [ | ||||||
|     ".", |     ".", | ||||||
|     "google", |     "google", | ||||||
|     "internal", |     "internal", | ||||||
|     "jws", |     "jws", | ||||||
|     "jwt" |     "jwt", | ||||||
|   ] |   ] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "e0f2c55a7fc7d04742e0eef7918aa2389b0e1919" |   revision = "e0f2c55a7fc7d04742e0eef7918aa2389b0e1919" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|   branch = "master" |   branch = "master" | ||||||
|  |   digest = "1:04b92b5bc6c1031cc9083fbc2fdeda90f3a69b7c1bf5eed6bbf9a3563d946c6e" | ||||||
|   name = "golang.org/x/sys" |   name = "golang.org/x/sys" | ||||||
|   packages = [ |   packages = [ | ||||||
|     "unix", |     "unix", | ||||||
|     "windows" |     "windows", | ||||||
|   ] |   ] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "9b800f95dbbc54abff0acf7ee32d88ba4e328c89" |   revision = "9b800f95dbbc54abff0acf7ee32d88ba4e328c89" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|  |   digest = "1:8c74f97396ed63cc2ef04ebb5fc37bb032871b8fd890a25991ed40974b00cd2a" | ||||||
|   name = "golang.org/x/text" |   name = "golang.org/x/text" | ||||||
|   packages = [ |   packages = [ | ||||||
|     "collate", |     "collate", | ||||||
|  | @ -401,29 +514,35 @@ | ||||||
|     "unicode/cldr", |     "unicode/cldr", | ||||||
|     "unicode/norm", |     "unicode/norm", | ||||||
|     "unicode/rangetable", |     "unicode/rangetable", | ||||||
|     "width" |     "width", | ||||||
|   ] |   ] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0" |   revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0" | ||||||
|   version = "v0.3.0" |   version = "v0.3.0" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|   branch = "master" |   branch = "master" | ||||||
|  |   digest = "1:c9e7a4b4d47c0ed205d257648b0e5b0440880cb728506e318f8ac7cd36270bc4" | ||||||
|   name = "golang.org/x/time" |   name = "golang.org/x/time" | ||||||
|   packages = ["rate"] |   packages = ["rate"] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "fbb02b2291d28baffd63558aa44b4b56f178d650" |   revision = "fbb02b2291d28baffd63558aa44b4b56f178d650" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|   branch = "master" |   branch = "master" | ||||||
|  |   digest = "1:d9646d2cb3517e532bcc75614352e589c5f26e6d1b8ae2587eaef0c7c60cea3a" | ||||||
|   name = "golang.org/x/tools" |   name = "golang.org/x/tools" | ||||||
|   packages = [ |   packages = [ | ||||||
|     "go/ast/astutil", |     "go/ast/astutil", | ||||||
|     "imports", |     "imports", | ||||||
|     "internal/fastwalk", |     "internal/fastwalk", | ||||||
|     "internal/gopathwalk" |     "internal/gopathwalk", | ||||||
|   ] |   ] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "92b943e6bff73e0dfe9e975d94043d8f31067b06" |   revision = "92b943e6bff73e0dfe9e975d94043d8f31067b06" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|  |   digest = "1:2a4972ee51c3b9dfafbb3451fa0552e7a198d9d12c721bfc492050fe2f72e0f6" | ||||||
|   name = "google.golang.org/appengine" |   name = "google.golang.org/appengine" | ||||||
|   packages = [ |   packages = [ | ||||||
|     ".", |     ".", | ||||||
|  | @ -435,24 +554,30 @@ | ||||||
|     "internal/modules", |     "internal/modules", | ||||||
|     "internal/remote_api", |     "internal/remote_api", | ||||||
|     "internal/urlfetch", |     "internal/urlfetch", | ||||||
|     "urlfetch" |     "urlfetch", | ||||||
|   ] |   ] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "4a4468ece617fc8205e99368fa2200e9d1fad421" |   revision = "4a4468ece617fc8205e99368fa2200e9d1fad421" | ||||||
|   version = "v1.3.0" |   version = "v1.3.0" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|  |   digest = "1:2d1fbdc6777e5408cabeb02bf336305e724b925ff4546ded0fa8715a7267922a" | ||||||
|   name = "gopkg.in/inf.v0" |   name = "gopkg.in/inf.v0" | ||||||
|   packages = ["."] |   packages = ["."] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "d2d2541c53f18d2a059457998ce2876cc8e67cbf" |   revision = "d2d2541c53f18d2a059457998ce2876cc8e67cbf" | ||||||
|   version = "v0.9.1" |   version = "v0.9.1" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|  |   digest = "1:7c95b35057a0ff2e19f707173cc1a947fa43a6eb5c4d300d196ece0334046082" | ||||||
|   name = "gopkg.in/yaml.v2" |   name = "gopkg.in/yaml.v2" | ||||||
|   packages = ["."] |   packages = ["."] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183" |   revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183" | ||||||
|   version = "v2.2.1" |   version = "v2.2.1" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|  |   digest = "1:f11e5753e619f411a51a49d60d39b2bc4da6766f5f0af2e2291daa6a3d9385d5" | ||||||
|   name = "k8s.io/api" |   name = "k8s.io/api" | ||||||
|   packages = [ |   packages = [ | ||||||
|     "admission/v1beta1", |     "admission/v1beta1", | ||||||
|  | @ -484,20 +609,24 @@ | ||||||
|     "settings/v1alpha1", |     "settings/v1alpha1", | ||||||
|     "storage/v1", |     "storage/v1", | ||||||
|     "storage/v1alpha1", |     "storage/v1alpha1", | ||||||
|     "storage/v1beta1" |     "storage/v1beta1", | ||||||
|   ] |   ] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "2d6f90ab1293a1fb871cf149423ebb72aa7423aa" |   revision = "2d6f90ab1293a1fb871cf149423ebb72aa7423aa" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|  |   digest = "1:117a407949aaaad9f7fbe3da8d6c2055f2c223ac0cbebd39f47ff71899622a91" | ||||||
|   name = "k8s.io/apiextensions-apiserver" |   name = "k8s.io/apiextensions-apiserver" | ||||||
|   packages = [ |   packages = [ | ||||||
|     "pkg/apis/apiextensions", |     "pkg/apis/apiextensions", | ||||||
|     "pkg/apis/apiextensions/v1beta1", |     "pkg/apis/apiextensions/v1beta1", | ||||||
|     "pkg/client/clientset/clientset/scheme" |     "pkg/client/clientset/clientset/scheme", | ||||||
|   ] |   ] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "408db4a50408e2149acbd657bceb2480c13cb0a4" |   revision = "408db4a50408e2149acbd657bceb2480c13cb0a4" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|  |   digest = "1:b07bf863262aae765494d60f0d524483f211b29f9bb27d445a79c13af8676bf2" | ||||||
|   name = "k8s.io/apimachinery" |   name = "k8s.io/apimachinery" | ||||||
|   packages = [ |   packages = [ | ||||||
|     "pkg/api/errors", |     "pkg/api/errors", | ||||||
|  | @ -541,11 +670,13 @@ | ||||||
|     "pkg/version", |     "pkg/version", | ||||||
|     "pkg/watch", |     "pkg/watch", | ||||||
|     "third_party/forked/golang/json", |     "third_party/forked/golang/json", | ||||||
|     "third_party/forked/golang/reflect" |     "third_party/forked/golang/reflect", | ||||||
|   ] |   ] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "103fd098999dc9c0c88536f5c9ad2e5da39373ae" |   revision = "103fd098999dc9c0c88536f5c9ad2e5da39373ae" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|  |   digest = "1:1689a49a3ebc6e379849181f1e0899fccf143cab47586078721818bdcdb712bc" | ||||||
|   name = "k8s.io/client-go" |   name = "k8s.io/client-go" | ||||||
|   packages = [ |   packages = [ | ||||||
|     "discovery", |     "discovery", | ||||||
|  | @ -613,11 +744,13 @@ | ||||||
|     "util/integer", |     "util/integer", | ||||||
|     "util/jsonpath", |     "util/jsonpath", | ||||||
|     "util/retry", |     "util/retry", | ||||||
|     "util/workqueue" |     "util/workqueue", | ||||||
|   ] |   ] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "1f13a808da65775f22cbf47862c4e5898d8f4ca1" |   revision = "1f13a808da65775f22cbf47862c4e5898d8f4ca1" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|  |   digest = "1:8ab487a323486c8bbbaa3b689850487fdccc6cbea8690620e083b2d230a4447e" | ||||||
|   name = "k8s.io/code-generator" |   name = "k8s.io/code-generator" | ||||||
|   packages = [ |   packages = [ | ||||||
|     "cmd/client-gen", |     "cmd/client-gen", | ||||||
|  | @ -643,12 +776,14 @@ | ||||||
|     "cmd/lister-gen/generators", |     "cmd/lister-gen/generators", | ||||||
|     "cmd/openapi-gen", |     "cmd/openapi-gen", | ||||||
|     "cmd/openapi-gen/args", |     "cmd/openapi-gen/args", | ||||||
|     "pkg/util" |     "pkg/util", | ||||||
|   ] |   ] | ||||||
|  |   pruneopts = "T" | ||||||
|   revision = "6702109cc68eb6fe6350b83e14407c8d7309fd1a" |   revision = "6702109cc68eb6fe6350b83e14407c8d7309fd1a" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|   branch = "master" |   branch = "master" | ||||||
|  |   digest = "1:c84b5ef38d786290246a9cc791a48b6ed890cd32468179a51a91492161ec6d65" | ||||||
|   name = "k8s.io/gengo" |   name = "k8s.io/gengo" | ||||||
|   packages = [ |   packages = [ | ||||||
|     "args", |     "args", | ||||||
|  | @ -658,11 +793,13 @@ | ||||||
|     "generator", |     "generator", | ||||||
|     "namer", |     "namer", | ||||||
|     "parser", |     "parser", | ||||||
|     "types" |     "types", | ||||||
|   ] |   ] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "7338e4bfd6915369a1375890db1bbda0158c9863" |   revision = "7338e4bfd6915369a1375890db1bbda0158c9863" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|  |   digest = "1:c48a795cd7048bb1888273bc604b6e69b22f9b8089c3df65f77cc527757b515c" | ||||||
|   name = "k8s.io/kube-openapi" |   name = "k8s.io/kube-openapi" | ||||||
|   packages = [ |   packages = [ | ||||||
|     "cmd/openapi-gen/args", |     "cmd/openapi-gen/args", | ||||||
|  | @ -670,11 +807,13 @@ | ||||||
|     "pkg/generators", |     "pkg/generators", | ||||||
|     "pkg/generators/rules", |     "pkg/generators/rules", | ||||||
|     "pkg/util/proto", |     "pkg/util/proto", | ||||||
|     "pkg/util/sets" |     "pkg/util/sets", | ||||||
|   ] |   ] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "0cf8f7e6ed1d2e3d47d02e3b6e559369af24d803" |   revision = "0cf8f7e6ed1d2e3d47d02e3b6e559369af24d803" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|  |   digest = "1:d1b7a6ed45c957e6308759f31fdbff8063741ecb08b7c3b6d67f0c9f4357b2ae" | ||||||
|   name = "sigs.k8s.io/controller-runtime" |   name = "sigs.k8s.io/controller-runtime" | ||||||
|   packages = [ |   packages = [ | ||||||
|     "pkg/cache", |     "pkg/cache", | ||||||
|  | @ -702,14 +841,57 @@ | ||||||
|     "pkg/source/internal", |     "pkg/source/internal", | ||||||
|     "pkg/webhook/admission", |     "pkg/webhook/admission", | ||||||
|     "pkg/webhook/admission/types", |     "pkg/webhook/admission/types", | ||||||
|     "pkg/webhook/types" |     "pkg/webhook/types", | ||||||
|   ] |   ] | ||||||
|  |   pruneopts = "NT" | ||||||
|   revision = "5fd1e9e9fac5261e9ad9d47c375afc014fc31d21" |   revision = "5fd1e9e9fac5261e9ad9d47c375afc014fc31d21" | ||||||
|   version = "v0.1.7" |   version = "v0.1.7" | ||||||
| 
 | 
 | ||||||
| [solve-meta] | [solve-meta] | ||||||
|   analyzer-name = "dep" |   analyzer-name = "dep" | ||||||
|   analyzer-version = 1 |   analyzer-version = 1 | ||||||
|   inputs-digest = "a223e91cda589ee8ba60969192795e2139d96b046d4aecc35338a4d60e116f61" |   input-imports = [ | ||||||
|  |     "github.com/bndr/gojenkins", | ||||||
|  |     "github.com/docker/distribution/reference", | ||||||
|  |     "github.com/go-logr/logr", | ||||||
|  |     "github.com/mrtazz/checkmake/logger", | ||||||
|  |     "github.com/operator-framework/operator-sdk/pkg/k8sutil", | ||||||
|  |     "github.com/operator-framework/operator-sdk/pkg/leader", | ||||||
|  |     "github.com/operator-framework/operator-sdk/pkg/ready", | ||||||
|  |     "github.com/operator-framework/operator-sdk/pkg/test", | ||||||
|  |     "github.com/operator-framework/operator-sdk/pkg/test/e2eutil", | ||||||
|  |     "github.com/operator-framework/operator-sdk/version", | ||||||
|  |     "github.com/stretchr/testify/assert", | ||||||
|  |     "k8s.io/api/core/v1", | ||||||
|  |     "k8s.io/apimachinery/pkg/api/errors", | ||||||
|  |     "k8s.io/apimachinery/pkg/api/resource", | ||||||
|  |     "k8s.io/apimachinery/pkg/apis/meta/v1", | ||||||
|  |     "k8s.io/apimachinery/pkg/labels", | ||||||
|  |     "k8s.io/apimachinery/pkg/runtime", | ||||||
|  |     "k8s.io/apimachinery/pkg/runtime/schema", | ||||||
|  |     "k8s.io/apimachinery/pkg/types", | ||||||
|  |     "k8s.io/apimachinery/pkg/util/intstr", | ||||||
|  |     "k8s.io/apimachinery/pkg/util/wait", | ||||||
|  |     "k8s.io/client-go/plugin/pkg/client/auth/gcp", | ||||||
|  |     "k8s.io/code-generator/cmd/client-gen", | ||||||
|  |     "k8s.io/code-generator/cmd/conversion-gen", | ||||||
|  |     "k8s.io/code-generator/cmd/deepcopy-gen", | ||||||
|  |     "k8s.io/code-generator/cmd/defaulter-gen", | ||||||
|  |     "k8s.io/code-generator/cmd/informer-gen", | ||||||
|  |     "k8s.io/code-generator/cmd/lister-gen", | ||||||
|  |     "k8s.io/code-generator/cmd/openapi-gen", | ||||||
|  |     "k8s.io/gengo/args", | ||||||
|  |     "sigs.k8s.io/controller-runtime/pkg/client", | ||||||
|  |     "sigs.k8s.io/controller-runtime/pkg/client/config", | ||||||
|  |     "sigs.k8s.io/controller-runtime/pkg/controller", | ||||||
|  |     "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil", | ||||||
|  |     "sigs.k8s.io/controller-runtime/pkg/handler", | ||||||
|  |     "sigs.k8s.io/controller-runtime/pkg/manager", | ||||||
|  |     "sigs.k8s.io/controller-runtime/pkg/reconcile", | ||||||
|  |     "sigs.k8s.io/controller-runtime/pkg/runtime/log", | ||||||
|  |     "sigs.k8s.io/controller-runtime/pkg/runtime/scheme", | ||||||
|  |     "sigs.k8s.io/controller-runtime/pkg/runtime/signals", | ||||||
|  |     "sigs.k8s.io/controller-runtime/pkg/source", | ||||||
|  |   ] | ||||||
|   solver-name = "gps-cdcl" |   solver-name = "gps-cdcl" | ||||||
|   solver-version = 1 |   solver-version = 1 | ||||||
|  |  | ||||||
|  | @ -17,7 +17,7 @@ spec: | ||||||
|       containers: |       containers: | ||||||
|         - name: jenkins-operator |         - name: jenkins-operator | ||||||
|           # Replace this with the built image name |           # Replace this with the built image name | ||||||
|           image: jenkins-operator |           image: REPLACE_IMAGE | ||||||
|           ports: |           ports: | ||||||
|           - containerPort: 60000 |           - containerPort: 60000 | ||||||
|             name: metrics |             name: metrics | ||||||
|  |  | ||||||
|  | @ -16,11 +16,13 @@ type JenkinsSpec struct { | ||||||
| 	SeedJobs []SeedJob     `json:"seedJobs,omitempty"` | 	SeedJobs []SeedJob     `json:"seedJobs,omitempty"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // JenkinsMaster defines the Jenkins master pod attributes
 | // JenkinsMaster defines the Jenkins master pod attributes and plugins,
 | ||||||
|  | // every single change requires Jenkins master pod restart
 | ||||||
| type JenkinsMaster struct { | type JenkinsMaster struct { | ||||||
| 	Image       string                      `json:"image,omitempty"` | 	Image       string                      `json:"image,omitempty"` | ||||||
| 	Annotations map[string]string           `json:"masterAnnotations,omitempty"` | 	Annotations map[string]string           `json:"masterAnnotations,omitempty"` | ||||||
| 	Resources   corev1.ResourceRequirements `json:"resources,omitempty"` | 	Resources   corev1.ResourceRequirements `json:"resources,omitempty"` | ||||||
|  | 	Plugins     map[string][]string         `json:"plugins,omitempty"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // JenkinsStatus defines the observed state of Jenkins
 | // JenkinsStatus defines the observed state of Jenkins
 | ||||||
|  |  | ||||||
|  | @ -97,6 +97,21 @@ func (in *JenkinsMaster) DeepCopyInto(out *JenkinsMaster) { | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	in.Resources.DeepCopyInto(&out.Resources) | 	in.Resources.DeepCopyInto(&out.Resources) | ||||||
|  | 	if in.Plugins != nil { | ||||||
|  | 		in, out := &in.Plugins, &out.Plugins | ||||||
|  | 		*out = make(map[string][]string, len(*in)) | ||||||
|  | 		for key, val := range *in { | ||||||
|  | 			var outVal []string | ||||||
|  | 			if val == nil { | ||||||
|  | 				(*out)[key] = nil | ||||||
|  | 			} else { | ||||||
|  | 				in, out := &val, &outVal | ||||||
|  | 				*out = make([]string, len(*in)) | ||||||
|  | 				copy(*out, *in) | ||||||
|  | 			} | ||||||
|  | 			(*out)[key] = outVal | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
| 	return | 	return | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -9,8 +9,10 @@ import ( | ||||||
| 	virtuslabv1alpha1 "github.com/VirtusLab/jenkins-operator/pkg/apis/virtuslab/v1alpha1" | 	virtuslabv1alpha1 "github.com/VirtusLab/jenkins-operator/pkg/apis/virtuslab/v1alpha1" | ||||||
| 	jenkinsclient "github.com/VirtusLab/jenkins-operator/pkg/controller/jenkins/client" | 	jenkinsclient "github.com/VirtusLab/jenkins-operator/pkg/controller/jenkins/client" | ||||||
| 	"github.com/VirtusLab/jenkins-operator/pkg/controller/jenkins/configuration/base/resources" | 	"github.com/VirtusLab/jenkins-operator/pkg/controller/jenkins/configuration/base/resources" | ||||||
|  | 	"github.com/VirtusLab/jenkins-operator/pkg/controller/jenkins/plugin" | ||||||
| 	"github.com/VirtusLab/jenkins-operator/pkg/log" | 	"github.com/VirtusLab/jenkins-operator/pkg/log" | ||||||
| 
 | 
 | ||||||
|  | 	"github.com/bndr/gojenkins" | ||||||
| 	"github.com/go-logr/logr" | 	"github.com/go-logr/logr" | ||||||
| 	corev1 "k8s.io/api/core/v1" | 	corev1 "k8s.io/api/core/v1" | ||||||
| 	"k8s.io/apimachinery/pkg/api/errors" | 	"k8s.io/apimachinery/pkg/api/errors" | ||||||
|  | @ -22,6 +24,10 @@ import ( | ||||||
| 	"sigs.k8s.io/controller-runtime/pkg/reconcile" | 	"sigs.k8s.io/controller-runtime/pkg/reconcile" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | const ( | ||||||
|  | 	fetchAllPlugins = 1 | ||||||
|  | ) | ||||||
|  | 
 | ||||||
| // ReconcileJenkinsBaseConfiguration defines values required for Jenkins base configuration
 | // ReconcileJenkinsBaseConfiguration defines values required for Jenkins base configuration
 | ||||||
| type ReconcileJenkinsBaseConfiguration struct { | type ReconcileJenkinsBaseConfiguration struct { | ||||||
| 	client          client.Client | 	client          client.Client | ||||||
|  | @ -46,11 +52,6 @@ func New(client client.Client, scheme *runtime.Scheme, logger logr.Logger, | ||||||
| 
 | 
 | ||||||
| // Reconcile takes care of base configuration
 | // Reconcile takes care of base configuration
 | ||||||
| func (r *ReconcileJenkinsBaseConfiguration) Reconcile() (*reconcile.Result, jenkinsclient.Jenkins, error) { | func (r *ReconcileJenkinsBaseConfiguration) Reconcile() (*reconcile.Result, jenkinsclient.Jenkins, error) { | ||||||
| 	if !r.validate(r.jenkins) { |  | ||||||
| 		r.logger.V(log.VWarn).Info("Please correct Jenkins CR") |  | ||||||
| 		return &reconcile.Result{}, nil, nil |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	metaObject := resources.NewResourceObjectMeta(r.jenkins) | 	metaObject := resources.NewResourceObjectMeta(r.jenkins) | ||||||
| 
 | 
 | ||||||
| 	if err := r.createOperatorCredentialsSecret(metaObject); err != nil { | 	if err := r.createOperatorCredentialsSecret(metaObject); err != nil { | ||||||
|  | @ -97,9 +98,65 @@ func (r *ReconcileJenkinsBaseConfiguration) Reconcile() (*reconcile.Result, jenk | ||||||
| 	} | 	} | ||||||
| 	r.logger.V(log.VDebug).Info("Jenkins API client set") | 	r.logger.V(log.VDebug).Info("Jenkins API client set") | ||||||
| 
 | 
 | ||||||
|  | 	ok, err := r.verifyBasePlugins(jenkinsClient) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return &reconcile.Result{}, nil, err | ||||||
|  | 	} | ||||||
|  | 	if !ok { | ||||||
|  | 		r.logger.V(log.VWarn).Info("Please correct Jenkins CR (spec.master.plugins)") | ||||||
|  | 		currentJenkinsMasterPod, err := r.getJenkinsMasterPod(metaObject) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return &reconcile.Result{}, nil, err | ||||||
|  | 		} | ||||||
|  | 		if err := r.client.Delete(context.TODO(), currentJenkinsMasterPod); err != nil { | ||||||
|  | 			return &reconcile.Result{}, nil, err | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	return nil, jenkinsClient, nil | 	return nil, jenkinsClient, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func (r *ReconcileJenkinsBaseConfiguration) verifyBasePlugins(jenkinsClient jenkinsclient.Jenkins) (bool, error) { | ||||||
|  | 	allPluginsInJenkins, err := jenkinsClient.GetPlugins(fetchAllPlugins) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return false, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	var installedPlugins []string | ||||||
|  | 	for _, jenkinsPlugin := range allPluginsInJenkins.Raw.Plugins { | ||||||
|  | 		if !jenkinsPlugin.Deleted { | ||||||
|  | 			installedPlugins = append(installedPlugins, plugin.Plugin{Name: jenkinsPlugin.ShortName, Version: jenkinsPlugin.Version}.String()) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	r.logger.V(log.VDebug).Info(fmt.Sprintf("Installed plugins '%+v'", installedPlugins)) | ||||||
|  | 
 | ||||||
|  | 	status := true | ||||||
|  | 	for rootPluginName, p := range plugin.BasePluginsMap { | ||||||
|  | 		rootPlugin, _ := plugin.New(rootPluginName) | ||||||
|  | 		if found, ok := isPluginInstalled(allPluginsInJenkins, *rootPlugin); !ok { | ||||||
|  | 			r.logger.V(log.VWarn).Info(fmt.Sprintf("Missing plugin '%s', actual '%+v'", rootPlugin, found)) | ||||||
|  | 			status = false | ||||||
|  | 		} | ||||||
|  | 		for _, requiredPlugin := range p { | ||||||
|  | 			if found, ok := isPluginInstalled(allPluginsInJenkins, requiredPlugin); !ok { | ||||||
|  | 				r.logger.V(log.VWarn).Info(fmt.Sprintf("Missing plugin '%s', actual '%+v'", requiredPlugin, found)) | ||||||
|  | 				status = false | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return status, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func isPluginInstalled(plugins *gojenkins.Plugins, requiredPlugin plugin.Plugin) (gojenkins.Plugin, bool) { | ||||||
|  | 	p := plugins.Contains(requiredPlugin.Name) | ||||||
|  | 	if p == nil { | ||||||
|  | 		return gojenkins.Plugin{}, false | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return *p, p.Active && p.Enabled && !p.Deleted | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func (r *ReconcileJenkinsBaseConfiguration) createOperatorCredentialsSecret(meta metav1.ObjectMeta) error { | func (r *ReconcileJenkinsBaseConfiguration) createOperatorCredentialsSecret(meta metav1.ObjectMeta) error { | ||||||
| 	found := &corev1.Secret{} | 	found := &corev1.Secret{} | ||||||
| 	err := r.client.Get(context.TODO(), types.NamespacedName{Name: resources.GetOperatorCredentialsSecretName(r.jenkins), Namespace: r.jenkins.ObjectMeta.Namespace}, found) | 	err := r.client.Get(context.TODO(), types.NamespacedName{Name: resources.GetOperatorCredentialsSecretName(r.jenkins), Namespace: r.jenkins.ObjectMeta.Namespace}, found) | ||||||
|  |  | ||||||
|  | @ -11,6 +11,234 @@ import ( | ||||||
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | const installPluginsCommand = "install-plugins.sh" | ||||||
|  | 
 | ||||||
|  | // bash scripts installs single jenkins plugin with concrete version
 | ||||||
|  | const installPluginsBashFmt = `#!/bin/bash -eu | ||||||
|  | 
 | ||||||
|  | # Resolve dependencies and download plugins given on the command line | ||||||
|  | # | ||||||
|  | # FROM jenkins | ||||||
|  | # RUN install-plugins.sh docker-slaves github-branch-source | ||||||
|  | 
 | ||||||
|  | set -o pipefail | ||||||
|  | 
 | ||||||
|  | REF_DIR=${REF:-%s/plugins} | ||||||
|  | FAILED="$REF_DIR/failed-plugins.txt" | ||||||
|  | 
 | ||||||
|  | . /usr/local/bin/jenkins-support | ||||||
|  | 
 | ||||||
|  | getLockFile() { | ||||||
|  |     printf '%%s' "$REF_DIR/${1}.lock" | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | getArchiveFilename() { | ||||||
|  |     printf '%%s' "$REF_DIR/${1}.jpi" | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | download() { | ||||||
|  |     local plugin originalPlugin version lock ignoreLockFile | ||||||
|  |     plugin="$1" | ||||||
|  |     version="${2:-latest}" | ||||||
|  |     ignoreLockFile="${3:-}" | ||||||
|  |     lock="$(getLockFile "$plugin")" | ||||||
|  | 
 | ||||||
|  |     if [[ $ignoreLockFile ]] || mkdir "$lock" &>/dev/null; then | ||||||
|  |         if ! doDownload "$plugin" "$version"; then | ||||||
|  |             # some plugin don't follow the rules about artifact ID | ||||||
|  |             # typically: docker-plugin | ||||||
|  |             originalPlugin="$plugin" | ||||||
|  |             plugin="${plugin}-plugin" | ||||||
|  |             if ! doDownload "$plugin" "$version"; then | ||||||
|  |                 echo "Failed to download plugin: $originalPlugin or $plugin" >&2 | ||||||
|  |                 echo "Not downloaded: ${originalPlugin}" >> "$FAILED" | ||||||
|  |                 return 1 | ||||||
|  |             fi | ||||||
|  |         fi | ||||||
|  | 
 | ||||||
|  |         if ! checkIntegrity "$plugin"; then | ||||||
|  |             echo "Downloaded file is not a valid ZIP: $(getArchiveFilename "$plugin")" >&2 | ||||||
|  |             echo "Download integrity: ${plugin}" >> "$FAILED" | ||||||
|  |             return 1 | ||||||
|  |         fi | ||||||
|  | 
 | ||||||
|  |     fi | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | doDownload() { | ||||||
|  |     local plugin version url jpi | ||||||
|  |     plugin="$1" | ||||||
|  |     version="$2" | ||||||
|  |     jpi="$(getArchiveFilename "$plugin")" | ||||||
|  | 
 | ||||||
|  |     # If plugin already exists and is the same version do not download | ||||||
|  |     if test -f "$jpi" && unzip -p "$jpi" META-INF/MANIFEST.MF | tr -d '\r' | grep "^Plugin-Version: ${version}$" > /dev/null; then | ||||||
|  |         echo "Using provided plugin: $plugin" | ||||||
|  |         return 0 | ||||||
|  |     fi | ||||||
|  | 
 | ||||||
|  |     if [[ "$version" == "latest" && -n "$JENKINS_UC_LATEST" ]]; then | ||||||
|  |         # If version-specific Update Center is available, which is the case for LTS versions, | ||||||
|  |         # use it to resolve latest versions. | ||||||
|  |         url="$JENKINS_UC_LATEST/latest/${plugin}.hpi" | ||||||
|  |     elif [[ "$version" == "experimental" && -n "$JENKINS_UC_EXPERIMENTAL" ]]; then | ||||||
|  |         # Download from the experimental update center | ||||||
|  |         url="$JENKINS_UC_EXPERIMENTAL/latest/${plugin}.hpi" | ||||||
|  |     elif [[ "$version" == incrementals* ]] ; then | ||||||
|  |         # Download from Incrementals repo: https://jenkins.io/blog/2018/05/15/incremental-deployment/
 | ||||||
|  |         # Example URL: https://repo.jenkins-ci.org/incrementals/org/jenkins-ci/plugins/workflow/workflow-support/2.19-rc289.d09828a05a74/workflow-support-2.19-rc289.d09828a05a74.hpi
 | ||||||
|  |         local groupId incrementalsVersion | ||||||
|  |         arrIN=(${version//;/ })
 | ||||||
|  |         groupId=${arrIN[1]} | ||||||
|  |         incrementalsVersion=${arrIN[2]} | ||||||
|  |         url="${JENKINS_INCREMENTALS_REPO_MIRROR}/$(echo "${groupId}" | tr '.' '/')/${plugin}/${incrementalsVersion}/${plugin}-${incrementalsVersion}.hpi" | ||||||
|  |     else | ||||||
|  |         JENKINS_UC_DOWNLOAD=${JENKINS_UC_DOWNLOAD:-"$JENKINS_UC/download"} | ||||||
|  |         url="$JENKINS_UC_DOWNLOAD/plugins/$plugin/$version/${plugin}.hpi" | ||||||
|  |     fi | ||||||
|  | 
 | ||||||
|  |     echo "Downloading plugin: $plugin from $url" | ||||||
|  |     retry_command curl "${CURL_OPTIONS:--sSfL}" --connect-timeout "${CURL_CONNECTION_TIMEOUT:-20}" --retry "${CURL_RETRY:-5}" --retry-delay "${CURL_RETRY_DELAY:-0}" --retry-max-time "${CURL_RETRY_MAX_TIME:-60}" "$url" -o "$jpi" | ||||||
|  |     return $? | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | checkIntegrity() { | ||||||
|  |     local plugin jpi | ||||||
|  |     plugin="$1" | ||||||
|  |     jpi="$(getArchiveFilename "$plugin")" | ||||||
|  | 
 | ||||||
|  |     unzip -t -qq "$jpi" >/dev/null | ||||||
|  |     return $? | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bundledPlugins() { | ||||||
|  |     local JENKINS_WAR=/usr/share/jenkins/jenkins.war | ||||||
|  |     if [ -f $JENKINS_WAR ] | ||||||
|  |     then | ||||||
|  |         TEMP_PLUGIN_DIR=/tmp/plugintemp.$$ | ||||||
|  |         for i in $(jar tf $JENKINS_WAR | grep -E '[^detached-]plugins.*\..pi' | sort) | ||||||
|  |         do | ||||||
|  |             rm -fr $TEMP_PLUGIN_DIR | ||||||
|  |             mkdir -p $TEMP_PLUGIN_DIR | ||||||
|  |             PLUGIN=$(basename "$i"|cut -f1 -d'.') | ||||||
|  |             (cd $TEMP_PLUGIN_DIR;jar xf "$JENKINS_WAR" "$i";jar xvf "$TEMP_PLUGIN_DIR/$i" META-INF/MANIFEST.MF >/dev/null 2>&1) | ||||||
|  |             VER=$(grep -E -i Plugin-Version "$TEMP_PLUGIN_DIR/META-INF/MANIFEST.MF"|cut -d: -f2|sed 's/ //')
 | ||||||
|  |             echo "$PLUGIN:$VER" | ||||||
|  |         done | ||||||
|  |         rm -fr $TEMP_PLUGIN_DIR | ||||||
|  |     else | ||||||
|  |         rm -f "$TEMP_ALREADY_INSTALLED" | ||||||
|  |         echo "ERROR file not found: $JENKINS_WAR" | ||||||
|  |         exit 1 | ||||||
|  |     fi | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | versionFromPlugin() { | ||||||
|  |     local plugin=$1 | ||||||
|  |     if [[ $plugin =~ .*:.* ]]; then | ||||||
|  |         echo "${plugin##*:}" | ||||||
|  |     else | ||||||
|  |         echo "latest" | ||||||
|  |     fi | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | installedPlugins() { | ||||||
|  |     for f in "$REF_DIR"/*.jpi; do | ||||||
|  |         echo "$(basename "$f" | sed -e 's/\.jpi//'):$(get_plugin_version "$f")" | ||||||
|  |     done | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | jenkinsMajorMinorVersion() { | ||||||
|  |     local JENKINS_WAR | ||||||
|  |     JENKINS_WAR=/usr/share/jenkins/jenkins.war | ||||||
|  |     if [[ -f "$JENKINS_WAR" ]]; then | ||||||
|  |         local version major minor | ||||||
|  |         version="$(java -jar /usr/share/jenkins/jenkins.war --version)" | ||||||
|  |         major="$(echo "$version" | cut -d '.' -f 1)" | ||||||
|  |         minor="$(echo "$version" | cut -d '.' -f 2)" | ||||||
|  |         echo "$major.$minor" | ||||||
|  |     else | ||||||
|  |         echo "ERROR file not found: $JENKINS_WAR" | ||||||
|  |         return 1 | ||||||
|  |     fi | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | main() { | ||||||
|  |     local plugin pluginVersion jenkinsVersion | ||||||
|  |     local plugins=() | ||||||
|  | 
 | ||||||
|  |     mkdir -p "$REF_DIR" || exit 1 | ||||||
|  |     rm -f "$FAILED" | ||||||
|  | 
 | ||||||
|  |     # Read plugins from stdin or from the command line arguments | ||||||
|  |     if [[ ($# -eq 0) ]]; then | ||||||
|  |         while read -r line || [ "$line" != "" ]; do | ||||||
|  |             # Remove leading/trailing spaces, comments, and empty lines | ||||||
|  |             plugin=$(echo "${line}" | tr -d '\r' | sed -e 's/^[ \t]*//g' -e 's/[ \t]*$//g' -e 's/[ \t]*#.*$//g' -e '/^[ \t]*$/d')
 | ||||||
|  | 
 | ||||||
|  |             # Avoid adding empty plugin into array | ||||||
|  |             if [ ${#plugin} -ne 0 ]; then | ||||||
|  |                 plugins+=("${plugin}") | ||||||
|  |             fi | ||||||
|  |         done | ||||||
|  |     else | ||||||
|  |         plugins=("$@") | ||||||
|  |     fi | ||||||
|  | 
 | ||||||
|  |     # Create lockfile manually before first run to make sure any explicit version set is used. | ||||||
|  |     echo "Creating initial locks..." | ||||||
|  |     for plugin in "${plugins[@]}"; do | ||||||
|  |         mkdir "$(getLockFile "${plugin%%:*}")" | ||||||
|  |     done | ||||||
|  | 
 | ||||||
|  |     echo "Analyzing war..." | ||||||
|  |     bundledPlugins="$(bundledPlugins)" | ||||||
|  | 
 | ||||||
|  |     echo "Registering preinstalled plugins..." | ||||||
|  |     installedPlugins="$(installedPlugins)" | ||||||
|  | 
 | ||||||
|  |     # Check if there's a version-specific update center, which is the case for LTS versions | ||||||
|  |     jenkinsVersion="$(jenkinsMajorMinorVersion)" | ||||||
|  |     if curl -fsL -o /dev/null "$JENKINS_UC/$jenkinsVersion"; then | ||||||
|  |         JENKINS_UC_LATEST="$JENKINS_UC/$jenkinsVersion" | ||||||
|  |         echo "Using version-specific update center: $JENKINS_UC_LATEST..." | ||||||
|  |     else | ||||||
|  |         JENKINS_UC_LATEST= | ||||||
|  |     fi | ||||||
|  | 
 | ||||||
|  |     echo "Downloading plugins..." | ||||||
|  |     for plugin in "${plugins[@]}"; do | ||||||
|  |         pluginVersion="" | ||||||
|  | 
 | ||||||
|  |         if [[ $plugin =~ .*:.* ]]; then | ||||||
|  |             pluginVersion=$(versionFromPlugin "${plugin}") | ||||||
|  |             plugin="${plugin%%:*}" | ||||||
|  |         fi | ||||||
|  | 
 | ||||||
|  |         download "$plugin" "$pluginVersion" "true" & | ||||||
|  |     done | ||||||
|  |     wait | ||||||
|  | 
 | ||||||
|  |     echo | ||||||
|  |     echo "WAR bundled plugins:" | ||||||
|  |     echo "${bundledPlugins}" | ||||||
|  |     echo | ||||||
|  |     echo "Installed plugins:" | ||||||
|  |     installedPlugins | ||||||
|  | 
 | ||||||
|  |     if [[ -f $FAILED ]]; then | ||||||
|  |         echo "Some plugins failed to download!" "$(<"$FAILED")" >&2 | ||||||
|  |         exit 1 | ||||||
|  |     fi | ||||||
|  | 
 | ||||||
|  |     echo "Cleaning up locks" | ||||||
|  |     rm -r "$REF_DIR"/*.lock | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | main "$@" | ||||||
|  | ` | ||||||
|  | 
 | ||||||
| var initBashTemplate = template.Must(template.New(initScriptName).Parse(`#!/usr/bin/env bash | var initBashTemplate = template.Must(template.New(initScriptName).Parse(`#!/usr/bin/env bash | ||||||
| set -e | set -e | ||||||
| set -x | set -x | ||||||
|  | @ -19,18 +247,19 @@ set -x | ||||||
| mkdir -p {{ .JenkinsHomePath }}/init.groovy.d | mkdir -p {{ .JenkinsHomePath }}/init.groovy.d | ||||||
| cp -n {{ .BaseConfigurationPath }}/*.groovy {{ .JenkinsHomePath }}/init.groovy.d | cp -n {{ .BaseConfigurationPath }}/*.groovy {{ .JenkinsHomePath }}/init.groovy.d | ||||||
| 
 | 
 | ||||||
| touch {{ .JenkinsHomePath }}/plugins.txt | mkdir -p {{ .JenkinsHomePath }}/scripts | ||||||
| cat > {{ .JenkinsHomePath }}/plugins.txt <<EOL | cp {{ .JenkinsScriptsVolumePath }}/*.sh {{ .JenkinsHomePath }}/scripts | ||||||
| credentials:2.1.18 | chmod +x {{ .JenkinsHomePath }}/scripts/*.sh | ||||||
| ssh-credentials:1.14 |  | ||||||
| job-dsl:1.70 |  | ||||||
| git:3.9.1 |  | ||||||
| workflow-cps:2.61 |  | ||||||
| workflow-job:2.30 |  | ||||||
| workflow-aggregator:2.6 |  | ||||||
| EOL |  | ||||||
| 
 | 
 | ||||||
| /usr/local/bin/install-plugins.sh < {{ .JenkinsHomePath }}/plugins.txt | {{- $jenkinsHomePath := .JenkinsHomePath }} | ||||||
|  | {{- $installPluginsCommand := .InstallPluginsCommand }} | ||||||
|  | 
 | ||||||
|  | echo "Installing plugins - begin" | ||||||
|  | {{- range $rootPluginName, $plugins := .Plugins }} | ||||||
|  | echo "Installing required plugins for '{{ $rootPluginName }}'" | ||||||
|  | {{ $jenkinsHomePath }}/scripts/{{ $installPluginsCommand }} {{ $rootPluginName }} {{ range $index, $plugin := $plugins }}{{ . }} {{ end }} | ||||||
|  | {{- end }} | ||||||
|  | echo "Installing plugins - end" | ||||||
| 
 | 
 | ||||||
| /sbin/tini -s -- /usr/local/bin/jenkins.sh | /sbin/tini -s -- /usr/local/bin/jenkins.sh | ||||||
| `)) | `)) | ||||||
|  | @ -42,13 +271,19 @@ func buildConfigMapTypeMeta() metav1.TypeMeta { | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func buildInitBashScript() (*string, error) { | func buildInitBashScript(pluginsToInstall map[string][]string) (*string, error) { | ||||||
| 	data := struct { | 	data := struct { | ||||||
| 		JenkinsHomePath          string | 		JenkinsHomePath          string | ||||||
| 		BaseConfigurationPath    string | 		BaseConfigurationPath    string | ||||||
|  | 		InstallPluginsCommand    string | ||||||
|  | 		JenkinsScriptsVolumePath string | ||||||
|  | 		Plugins                  map[string][]string | ||||||
| 	}{ | 	}{ | ||||||
| 		JenkinsHomePath:          jenkinsHomePath, | 		JenkinsHomePath:          jenkinsHomePath, | ||||||
| 		BaseConfigurationPath:    jenkinsBaseConfigurationVolumePath, | 		BaseConfigurationPath:    jenkinsBaseConfigurationVolumePath, | ||||||
|  | 		Plugins:                  pluginsToInstall, | ||||||
|  | 		InstallPluginsCommand:    installPluginsCommand, | ||||||
|  | 		JenkinsScriptsVolumePath: jenkinsScriptsVolumePath, | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	output, err := render.Render(initBashTemplate, data) | 	output, err := render.Render(initBashTemplate, data) | ||||||
|  | @ -67,7 +302,7 @@ func getScriptsConfigMapName(jenkins *virtuslabv1alpha1.Jenkins) string { | ||||||
| func NewScriptsConfigMap(meta metav1.ObjectMeta, jenkins *virtuslabv1alpha1.Jenkins) (*corev1.ConfigMap, error) { | func NewScriptsConfigMap(meta metav1.ObjectMeta, jenkins *virtuslabv1alpha1.Jenkins) (*corev1.ConfigMap, error) { | ||||||
| 	meta.Name = getScriptsConfigMapName(jenkins) | 	meta.Name = getScriptsConfigMapName(jenkins) | ||||||
| 
 | 
 | ||||||
| 	initBashScript, err := buildInitBashScript() | 	initBashScript, err := buildInitBashScript(jenkins.Spec.Master.Plugins) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
|  | @ -77,6 +312,7 @@ func NewScriptsConfigMap(meta metav1.ObjectMeta, jenkins *virtuslabv1alpha1.Jenk | ||||||
| 		ObjectMeta: meta, | 		ObjectMeta: meta, | ||||||
| 		Data: map[string]string{ | 		Data: map[string]string{ | ||||||
| 			initScriptName:        *initBashScript, | 			initScriptName:        *initBashScript, | ||||||
|  | 			installPluginsCommand: fmt.Sprintf(installPluginsBashFmt, jenkinsHomePath), | ||||||
| 		}, | 		}, | ||||||
| 	}, nil | 	}, nil | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,9 +1,12 @@ | ||||||
| package base | package base | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  | 	"fmt" | ||||||
| 	"regexp" | 	"regexp" | ||||||
| 
 | 
 | ||||||
| 	virtuslabv1alpha1 "github.com/VirtusLab/jenkins-operator/pkg/apis/virtuslab/v1alpha1" | 	virtuslabv1alpha1 "github.com/VirtusLab/jenkins-operator/pkg/apis/virtuslab/v1alpha1" | ||||||
|  | 	"github.com/VirtusLab/jenkins-operator/pkg/controller/jenkins/plugin" | ||||||
|  | 	"github.com/VirtusLab/jenkins-operator/pkg/log" | ||||||
| 
 | 
 | ||||||
| 	docker "github.com/docker/distribution/reference" | 	docker "github.com/docker/distribution/reference" | ||||||
| ) | ) | ||||||
|  | @ -12,16 +15,52 @@ var ( | ||||||
| 	dockerImageRegexp = regexp.MustCompile(`^` + docker.TagRegexp.String() + `$`) | 	dockerImageRegexp = regexp.MustCompile(`^` + docker.TagRegexp.String() + `$`) | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func (r *ReconcileJenkinsBaseConfiguration) validate(jenkins *virtuslabv1alpha1.Jenkins) bool { | // Validate validates Jenkins CR Spec.master section
 | ||||||
|  | func (r *ReconcileJenkinsBaseConfiguration) Validate(jenkins *virtuslabv1alpha1.Jenkins) bool { | ||||||
| 	if jenkins.Spec.Master.Image == "" { | 	if jenkins.Spec.Master.Image == "" { | ||||||
| 		r.logger.V(0).Info("Image not set") | 		r.logger.V(log.VWarn).Info("Image not set") | ||||||
| 		return false | 		return false | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if !dockerImageRegexp.MatchString(jenkins.Spec.Master.Image) && !docker.ReferenceRegexp.MatchString(jenkins.Spec.Master.Image) { | 	if !dockerImageRegexp.MatchString(jenkins.Spec.Master.Image) && !docker.ReferenceRegexp.MatchString(jenkins.Spec.Master.Image) { | ||||||
| 		r.logger.V(0).Info("Invalid image") | 		r.logger.V(log.VWarn).Info("Invalid image") | ||||||
|  | 		return false | ||||||
|  | 
 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if !r.validatePlugins(jenkins.Spec.Master.Plugins) { | ||||||
| 		return false | 		return false | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return true | 	return true | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | func (r *ReconcileJenkinsBaseConfiguration) validatePlugins(plugins map[string][]string) bool { | ||||||
|  | 	valid := true | ||||||
|  | 	allPlugins := map[string][]plugin.Plugin{} | ||||||
|  | 
 | ||||||
|  | 	for rootPluginName, dependentPluginNames := range plugins { | ||||||
|  | 		if _, err := plugin.New(rootPluginName); err != nil { | ||||||
|  | 			r.logger.V(log.VWarn).Info(fmt.Sprintf("Invalid root plugin name '%s'", rootPluginName)) | ||||||
|  | 			valid = false | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		dependentPlugins := []plugin.Plugin{} | ||||||
|  | 		for _, pluginName := range dependentPluginNames { | ||||||
|  | 			if p, err := plugin.New(pluginName); err != nil { | ||||||
|  | 				r.logger.V(log.VWarn).Info(fmt.Sprintf("Invalid dependent plugin name '%s' in root plugin '%s'", pluginName, rootPluginName)) | ||||||
|  | 				valid = false | ||||||
|  | 			} else { | ||||||
|  | 				dependentPlugins = append(dependentPlugins, *p) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		allPlugins[rootPluginName] = dependentPlugins | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if valid { | ||||||
|  | 		return plugin.VerifyDependencies(allPlugins) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return valid | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -0,0 +1,58 @@ | ||||||
|  | package base | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"testing" | ||||||
|  | 
 | ||||||
|  | 	"github.com/stretchr/testify/assert" | ||||||
|  | 	logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func TestValidatePlugins(t *testing.T) { | ||||||
|  | 	data := []struct { | ||||||
|  | 		plugins        map[string][]string | ||||||
|  | 		expectedResult bool | ||||||
|  | 	}{ | ||||||
|  | 		{ | ||||||
|  | 			plugins: map[string][]string{ | ||||||
|  | 				"valid-plugin-name:1.0": { | ||||||
|  | 					"valid-plugin-name:1.0", | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			expectedResult: true, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			plugins: map[string][]string{ | ||||||
|  | 				"invalid-plugin-name": { | ||||||
|  | 					"invalid-plugin-name", | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			expectedResult: false, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			plugins: map[string][]string{ | ||||||
|  | 				"valid-plugin-name:1.0": { | ||||||
|  | 					"valid-plugin-name:1.0", | ||||||
|  | 					"valid-plugin-name2:1.0", | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			expectedResult: true, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			plugins: map[string][]string{ | ||||||
|  | 				"valid-plugin-name:1.0": {}, | ||||||
|  | 			}, | ||||||
|  | 			expectedResult: true, | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	baseReconcileLoop := New(nil, nil, logf.ZapLogger(false), | ||||||
|  | 		nil, false, false) | ||||||
|  | 
 | ||||||
|  | 	for index, testingData := range data { | ||||||
|  | 		t.Run(fmt.Sprintf("Testing %d plugins set", index), func(t *testing.T) { | ||||||
|  | 			result := baseReconcileLoop.validatePlugins(testingData.plugins) | ||||||
|  | 			assert.Equal(t, testingData.expectedResult, result) | ||||||
|  | 		}) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | @ -6,6 +6,7 @@ import ( | ||||||
| 	virtuslabv1alpha1 "github.com/VirtusLab/jenkins-operator/pkg/apis/virtuslab/v1alpha1" | 	virtuslabv1alpha1 "github.com/VirtusLab/jenkins-operator/pkg/apis/virtuslab/v1alpha1" | ||||||
| 	"github.com/VirtusLab/jenkins-operator/pkg/controller/jenkins/configuration/base" | 	"github.com/VirtusLab/jenkins-operator/pkg/controller/jenkins/configuration/base" | ||||||
| 	"github.com/VirtusLab/jenkins-operator/pkg/controller/jenkins/configuration/user" | 	"github.com/VirtusLab/jenkins-operator/pkg/controller/jenkins/configuration/user" | ||||||
|  | 	"github.com/VirtusLab/jenkins-operator/pkg/controller/jenkins/plugin" | ||||||
| 	"github.com/VirtusLab/jenkins-operator/pkg/log" | 	"github.com/VirtusLab/jenkins-operator/pkg/log" | ||||||
| 
 | 
 | ||||||
| 	"github.com/go-logr/logr" | 	"github.com/go-logr/logr" | ||||||
|  | @ -95,8 +96,17 @@ func (r *ReconcileJenkins) Reconcile(request reconcile.Request) (reconcile.Resul | ||||||
| 		return reconcile.Result{}, err | 		return reconcile.Result{}, err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	err = r.setDefaults(jenkins) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return reconcile.Result{}, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	// Reconcile base configuration
 | 	// Reconcile base configuration
 | ||||||
| 	baseConfiguration := base.New(r.client, r.scheme, logger, jenkins, r.local, r.minikube) | 	baseConfiguration := base.New(r.client, r.scheme, logger, jenkins, r.local, r.minikube) | ||||||
|  | 	if !baseConfiguration.Validate(jenkins) { | ||||||
|  | 		logger.V(log.VWarn).Info("Please correct Jenkins CR") | ||||||
|  | 		return reconcile.Result{}, nil // don't requeue
 | ||||||
|  | 	} | ||||||
| 	result, jenkinsClient, err := baseConfiguration.Reconcile() | 	result, jenkinsClient, err := baseConfiguration.Reconcile() | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return reconcile.Result{}, err | 		return reconcile.Result{}, err | ||||||
|  | @ -137,3 +147,11 @@ func (r *ReconcileJenkins) Reconcile(request reconcile.Request) (reconcile.Resul | ||||||
| func (r *ReconcileJenkins) buildLogger(jenkinsName string) logr.Logger { | func (r *ReconcileJenkins) buildLogger(jenkinsName string) logr.Logger { | ||||||
| 	return log.Log.WithValues("cr", jenkinsName) | 	return log.Log.WithValues("cr", jenkinsName) | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | func (r *ReconcileJenkins) setDefaults(jenkins *virtuslabv1alpha1.Jenkins) error { | ||||||
|  | 	if len(jenkins.Spec.Master.Plugins) == 0 { | ||||||
|  | 		jenkins.Spec.Master.Plugins = plugin.BasePlugins() | ||||||
|  | 		return r.client.Update(context.TODO(), jenkins) | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -0,0 +1,115 @@ | ||||||
|  | package plugin | ||||||
|  | 
 | ||||||
|  | // BasePlugins returns map of plugins to install by operator
 | ||||||
|  | func BasePlugins() (plugins map[string][]string) { | ||||||
|  | 	plugins = map[string][]string{} | ||||||
|  | 
 | ||||||
|  | 	for rootPluginName, dependentPlugins := range BasePluginsMap { | ||||||
|  | 		plugins[rootPluginName] = []string{} | ||||||
|  | 		for _, pluginName := range dependentPlugins { | ||||||
|  | 			plugins[rootPluginName] = append(plugins[rootPluginName], pluginName.String()) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // BasePluginsMap contains plugins to install by operator
 | ||||||
|  | var BasePluginsMap = map[string][]Plugin{ | ||||||
|  | 	Must(New("kubernetes:1.13.8")).String(): { | ||||||
|  | 		Must(New("apache-httpcomponents-client-4-api:4.5.5-3.0")), | ||||||
|  | 		Must(New("cloudbees-folder:6.7")), | ||||||
|  | 		Must(New("credentials:2.1.18")), | ||||||
|  | 		Must(New("durable-task:1.28")), | ||||||
|  | 		Must(New("jackson2-api:2.9.8")), | ||||||
|  | 		Must(New("kubernetes-credentials:0.4.0")), | ||||||
|  | 		Must(New("plain-credentials:1.5")), | ||||||
|  | 		Must(New("structs:1.17")), | ||||||
|  | 		Must(New("variant:1.1")), | ||||||
|  | 		Must(New("workflow-step-api:2.17")), | ||||||
|  | 	}, | ||||||
|  | 	Must(New("workflow-job:2.31")).String(): { | ||||||
|  | 		Must(New("scm-api:2.3.0")), | ||||||
|  | 		Must(New("script-security:1.49")), | ||||||
|  | 		Must(New("structs:1.17")), | ||||||
|  | 		Must(New("workflow-api:2.33")), | ||||||
|  | 		Must(New("workflow-step-api:2.17")), | ||||||
|  | 		Must(New("workflow-support:2.24")), | ||||||
|  | 	}, | ||||||
|  | 	Must(New("workflow-aggregator:2.6")).String(): { | ||||||
|  | 		Must(New("ace-editor:1.1")), | ||||||
|  | 		Must(New("apache-httpcomponents-client-4-api:4.5.5-3.0")), | ||||||
|  | 		Must(New("authentication-tokens:1.3")), | ||||||
|  | 		Must(New("branch-api:2.1.2")), | ||||||
|  | 		Must(New("cloudbees-folder:6.7")), | ||||||
|  | 		Must(New("credentials-binding:1.17")), | ||||||
|  | 		Must(New("credentials:2.1.18")), | ||||||
|  | 		Must(New("display-url-api:2.3.0")), | ||||||
|  | 		Must(New("docker-commons:1.13")), | ||||||
|  | 		Must(New("docker-workflow:1.17")), | ||||||
|  | 		Must(New("durable-task:1.28")), | ||||||
|  | 		Must(New("git-client:2.7.4")), | ||||||
|  | 		Must(New("git-server:1.7")), | ||||||
|  | 		Must(New("handlebars:1.1.1")), | ||||||
|  | 		Must(New("jackson2-api:2.9.8")), | ||||||
|  | 		Must(New("jquery-detached:1.2.1")), | ||||||
|  | 		Must(New("jsch:0.1.54.2")), | ||||||
|  | 		Must(New("junit:1.26.1")), | ||||||
|  | 		Must(New("lockable-resources:2.3")), | ||||||
|  | 		Must(New("mailer:1.22")), | ||||||
|  | 		Must(New("matrix-project:1.13")), | ||||||
|  | 		Must(New("momentjs:1.1.1")), | ||||||
|  | 		Must(New("pipeline-build-step:2.7")), | ||||||
|  | 		Must(New("pipeline-graph-analysis:1.9")), | ||||||
|  | 		Must(New("pipeline-input-step:2.9")), | ||||||
|  | 		Must(New("pipeline-milestone-step:1.3.1")), | ||||||
|  | 		Must(New("pipeline-model-api:1.3.4")), | ||||||
|  | 		Must(New("pipeline-model-declarative-agent:1.1.1")), | ||||||
|  | 		Must(New("pipeline-model-definition:1.3.4")), | ||||||
|  | 		Must(New("pipeline-model-extensions:1.3.4")), | ||||||
|  | 		Must(New("pipeline-rest-api:2.10")), | ||||||
|  | 		Must(New("pipeline-stage-step:2.3")), | ||||||
|  | 		Must(New("pipeline-stage-tags-metadata:1.3.4")), | ||||||
|  | 		Must(New("pipeline-stage-view:2.10")), | ||||||
|  | 		Must(New("plain-credentials:1.5")), | ||||||
|  | 		Must(New("scm-api:2.3.0")), | ||||||
|  | 		Must(New("script-security:1.49")), | ||||||
|  | 		Must(New("ssh-credentials:1.14")), | ||||||
|  | 		Must(New("structs:1.17")), | ||||||
|  | 		Must(New("workflow-api:2.33")), | ||||||
|  | 		Must(New("workflow-basic-steps:2.13")), | ||||||
|  | 		Must(New("workflow-cps-global-lib:2.12")), | ||||||
|  | 		Must(New("workflow-cps:2.61")), | ||||||
|  | 		Must(New("workflow-durable-task-step:2.27")), | ||||||
|  | 		Must(New("workflow-job:2.31")), | ||||||
|  | 		Must(New("workflow-multibranch:2.20")), | ||||||
|  | 		Must(New("workflow-scm-step:2.7")), | ||||||
|  | 		Must(New("workflow-step-api:2.17")), | ||||||
|  | 		Must(New("workflow-support:2.24")), | ||||||
|  | 	}, | ||||||
|  | 	Must(New("git:3.9.1")).String(): { | ||||||
|  | 		Must(New("apache-httpcomponents-client-4-api:4.5.5-3.0")), | ||||||
|  | 		Must(New("credentials:2.1.18")), | ||||||
|  | 		Must(New("display-url-api:2.3.0")), | ||||||
|  | 		Must(New("git-client:2.7.4")), | ||||||
|  | 		Must(New("jsch:0.1.54.2")), | ||||||
|  | 		Must(New("junit:1.26.1")), | ||||||
|  | 		Must(New("mailer:1.22")), | ||||||
|  | 		Must(New("matrix-project:1.13")), | ||||||
|  | 		Must(New("scm-api:2.3.0")), | ||||||
|  | 		Must(New("script-security:1.49")), | ||||||
|  | 		Must(New("ssh-credentials:1.14")), | ||||||
|  | 		Must(New("structs:1.17")), | ||||||
|  | 		Must(New("workflow-api:2.33")), | ||||||
|  | 		Must(New("workflow-scm-step:2.7")), | ||||||
|  | 		Must(New("workflow-step-api:2.17")), | ||||||
|  | 	}, | ||||||
|  | 	Must(New("job-dsl:1.70")).String(): { | ||||||
|  | 		Must(New("script-security:1.49")), | ||||||
|  | 		Must(New("structs:1.17")), | ||||||
|  | 	}, | ||||||
|  | 	Must(New("jobConfigHistory:2.19")).String(): {}, | ||||||
|  | 	Must(New("configuration-as-code:1.4")).String(): { | ||||||
|  | 		Must(New("configuration-as-code-support:1.4")), | ||||||
|  | 	}, | ||||||
|  | } | ||||||
|  | @ -0,0 +1,91 @@ | ||||||
|  | package plugin | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"strings" | ||||||
|  | 
 | ||||||
|  | 	"github.com/VirtusLab/jenkins-operator/pkg/log" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // Plugin represents jenkins plugin
 | ||||||
|  | type Plugin struct { | ||||||
|  | 	Name                     string `json:"name"` | ||||||
|  | 	Version                  string `json:"version"` | ||||||
|  | 	rootPluginNameAndVersion string | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (p Plugin) String() string { | ||||||
|  | 	return fmt.Sprintf("%s:%s", p.Name, p.Version) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // New creates plugin from string, for example "name-of-plugin:0.0.1"
 | ||||||
|  | func New(nameWithVersion string) (*Plugin, error) { | ||||||
|  | 	val := strings.SplitN(nameWithVersion, ":", 2) | ||||||
|  | 	if val == nil || len(val) != 2 { | ||||||
|  | 		return nil, fmt.Errorf("invalid plugin format '%s'", nameWithVersion) | ||||||
|  | 	} | ||||||
|  | 	return &Plugin{ | ||||||
|  | 		Name:    val[0], | ||||||
|  | 		Version: val[1], | ||||||
|  | 	}, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Must returns plugin from pointer and throws panic when error is set
 | ||||||
|  | func Must(plugin *Plugin, err error) Plugin { | ||||||
|  | 	if err != nil { | ||||||
|  | 		panic(err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return *plugin | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // VerifyDependencies checks if all plugins have compatible versions
 | ||||||
|  | func VerifyDependencies(values ...map[string][]Plugin) bool { | ||||||
|  | 	// key - plugin name, value array of versions
 | ||||||
|  | 	allPlugins := make(map[string][]Plugin) | ||||||
|  | 	valid := true | ||||||
|  | 
 | ||||||
|  | 	for _, value := range values { | ||||||
|  | 		if value != nil { | ||||||
|  | 			for rootPluginNameAndVersion, plugins := range value { | ||||||
|  | 				if rootPlugin, err := New(rootPluginNameAndVersion); err != nil { | ||||||
|  | 					valid = false | ||||||
|  | 				} else { | ||||||
|  | 					allPlugins[rootPlugin.Name] = append(allPlugins[rootPlugin.Name], Plugin{ | ||||||
|  | 						Name:                     rootPlugin.Name, | ||||||
|  | 						Version:                  rootPlugin.Version, | ||||||
|  | 						rootPluginNameAndVersion: rootPluginNameAndVersion}) | ||||||
|  | 				} | ||||||
|  | 				for _, plugin := range plugins { | ||||||
|  | 					allPlugins[plugin.Name] = append(allPlugins[plugin.Name], Plugin{ | ||||||
|  | 						Name:                     plugin.Name, | ||||||
|  | 						Version:                  plugin.Version, | ||||||
|  | 						rootPluginNameAndVersion: rootPluginNameAndVersion}) | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	for pluginName, versions := range allPlugins { | ||||||
|  | 		if len(versions) == 1 { | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		for _, firstVersion := range versions { | ||||||
|  | 			for _, secondVersion := range versions { | ||||||
|  | 				if firstVersion.Version != secondVersion.Version { | ||||||
|  | 					log.Log.V(log.VWarn).Info(fmt.Sprintf("Plugin '%s' requires version '%s' but plugin '%s' requires '%s' for plugin '%s'", | ||||||
|  | 						firstVersion.rootPluginNameAndVersion, | ||||||
|  | 						firstVersion.Version, | ||||||
|  | 						secondVersion.rootPluginNameAndVersion, | ||||||
|  | 						secondVersion.Version, | ||||||
|  | 						pluginName, | ||||||
|  | 					)) | ||||||
|  | 					valid = false | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return valid | ||||||
|  | } | ||||||
|  | @ -0,0 +1,90 @@ | ||||||
|  | package plugin | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"github.com/VirtusLab/jenkins-operator/pkg/log" | ||||||
|  | 	"testing" | ||||||
|  | 
 | ||||||
|  | 	"github.com/stretchr/testify/assert" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func TestVerifyDependencies(t *testing.T) { | ||||||
|  | 	data := []struct { | ||||||
|  | 		basePlugins    map[string][]Plugin | ||||||
|  | 		extraPlugins   map[string][]Plugin | ||||||
|  | 		expectedResult bool | ||||||
|  | 	}{ | ||||||
|  | 		{ | ||||||
|  | 			basePlugins: map[string][]Plugin{ | ||||||
|  | 				"first-root-plugin:1.0.0": { | ||||||
|  | 					Must(New("first-plugin:0.0.1")), | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			expectedResult: true, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			basePlugins: map[string][]Plugin{ | ||||||
|  | 				"first-root-plugin:1.0.0": { | ||||||
|  | 					Must(New("first-plugin:0.0.1")), | ||||||
|  | 				}, | ||||||
|  | 				"second-root-plugin:1.0.0": { | ||||||
|  | 					Must(New("first-plugin:0.0.1")), | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			expectedResult: true, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			basePlugins: map[string][]Plugin{ | ||||||
|  | 				"first-root-plugin:1.0.0": { | ||||||
|  | 					Must(New("first-plugin:0.0.1")), | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			extraPlugins: map[string][]Plugin{ | ||||||
|  | 				"second-root-plugin:2.0.0": { | ||||||
|  | 					Must(New("first-plugin:0.0.1")), | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			expectedResult: true, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			basePlugins: map[string][]Plugin{ | ||||||
|  | 				"first-root-plugin:1.0.0": { | ||||||
|  | 					Must(New("first-plugin:0.0.1")), | ||||||
|  | 				}, | ||||||
|  | 				"first-root-plugin:2.0.0": { | ||||||
|  | 					Must(New("first-plugin:0.0.2")), | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			expectedResult: false, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			basePlugins: map[string][]Plugin{ | ||||||
|  | 				"first-root-plugin:1.0.0": { | ||||||
|  | 					Must(New("first-plugin:0.0.1")), | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			extraPlugins: map[string][]Plugin{ | ||||||
|  | 				"first-root-plugin:2.0.0": { | ||||||
|  | 					Must(New("first-plugin:0.0.2")), | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			expectedResult: false, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			basePlugins: map[string][]Plugin{ | ||||||
|  | 				"invalid-plugin-name": {}, | ||||||
|  | 			}, | ||||||
|  | 			expectedResult: false, | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	debug := false | ||||||
|  | 	log.SetupLogger(&debug) | ||||||
|  | 
 | ||||||
|  | 	for index, testingData := range data { | ||||||
|  | 		t.Run(fmt.Sprintf("Testing %d data", index), func(t *testing.T) { | ||||||
|  | 			result := VerifyDependencies(testingData.basePlugins, testingData.extraPlugins) | ||||||
|  | 			assert.Equal(t, testingData.expectedResult, result) | ||||||
|  | 		}) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | @ -5,6 +5,9 @@ import ( | ||||||
| 	"testing" | 	"testing" | ||||||
| 
 | 
 | ||||||
| 	virtuslabv1alpha1 "github.com/VirtusLab/jenkins-operator/pkg/apis/virtuslab/v1alpha1" | 	virtuslabv1alpha1 "github.com/VirtusLab/jenkins-operator/pkg/apis/virtuslab/v1alpha1" | ||||||
|  | 	"github.com/VirtusLab/jenkins-operator/pkg/controller/jenkins/plugin" | ||||||
|  | 
 | ||||||
|  | 	"github.com/bndr/gojenkins" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func TestBaseConfiguration(t *testing.T) { | func TestBaseConfiguration(t *testing.T) { | ||||||
|  | @ -17,7 +20,8 @@ func TestBaseConfiguration(t *testing.T) { | ||||||
| 	waitForJenkinsBaseConfigurationToComplete(t, jenkins) | 	waitForJenkinsBaseConfigurationToComplete(t, jenkins) | ||||||
| 
 | 
 | ||||||
| 	verifyJenkinsMasterPodAttributes(t, jenkins) | 	verifyJenkinsMasterPodAttributes(t, jenkins) | ||||||
| 	verifyJenkinsAPIConnection(t, jenkins) | 	jenkinsClient := verifyJenkinsAPIConnection(t, jenkins) | ||||||
|  | 	verifyBasePlugins(t, jenkinsClient) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func verifyJenkinsMasterPodAttributes(t *testing.T, jenkins *virtuslabv1alpha1.Jenkins) { | func verifyJenkinsMasterPodAttributes(t *testing.T, jenkins *virtuslabv1alpha1.Jenkins) { | ||||||
|  | @ -39,3 +43,40 @@ func verifyJenkinsMasterPodAttributes(t *testing.T, jenkins *virtuslabv1alpha1.J | ||||||
| 
 | 
 | ||||||
| 	t.Log("Jenkins pod attributes are valid") | 	t.Log("Jenkins pod attributes are valid") | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | func verifyBasePlugins(t *testing.T, jenkinsClient *gojenkins.Jenkins) { | ||||||
|  | 	allPluginsInJenkins, err := jenkinsClient.GetPlugins(1) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatal(err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	for rootPluginName, p := range plugin.BasePluginsMap { | ||||||
|  | 		rootPlugin, err := plugin.New(rootPluginName) | ||||||
|  | 		if err != nil { | ||||||
|  | 			t.Fatal(err) | ||||||
|  | 		} | ||||||
|  | 		if found, ok := isPluginValid(t, allPluginsInJenkins, *rootPlugin); !ok { | ||||||
|  | 			t.Fatalf("Invalid plugin '%s', actual '%+v'", rootPlugin, found) | ||||||
|  | 		} | ||||||
|  | 		for _, requiredPlugin := range p { | ||||||
|  | 			if found, ok := isPluginValid(t, allPluginsInJenkins, requiredPlugin); !ok { | ||||||
|  | 				t.Fatalf("Invalid plugin '%s', actual '%+v'", requiredPlugin, found) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	t.Log("Base plugins have been installed") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func isPluginValid(t *testing.T, plugins *gojenkins.Plugins, requiredPlugin plugin.Plugin) (*gojenkins.Plugin, bool) { | ||||||
|  | 	p := plugins.Contains(requiredPlugin.Name) | ||||||
|  | 	if p == nil { | ||||||
|  | 		return p, false | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if !p.Active || !p.Enabled || p.Deleted { | ||||||
|  | 		return p, false | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return p, requiredPlugin.Version == p.Version | ||||||
|  | } | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue