diff --git a/.github/workflows/build-package.yml b/.github/workflows/build-package.yml index 428e7e180..7753f9796 100644 --- a/.github/workflows/build-package.yml +++ b/.github/workflows/build-package.yml @@ -202,7 +202,7 @@ jobs: spark-operator-chart-version: 1.1.25 - name: Check mpyl health - run: mpyl health --ci + run: mpyl health - name: Lint projects run: mpyl projects lint diff --git a/Pipfile b/Pipfile index d4056313d..1a2cbd774 100644 --- a/Pipfile +++ b/Pipfile @@ -18,7 +18,6 @@ slack-sdk = "==3.21.3" atlassian-python-api = "==3.39.0" click = "==8.1.7" rich = "==13.8.0" -jenkinsapi = "==0.3.13" pyaml-env = "==1.2.1" python-dotenv = "==1.0.0" questionary = "==2.0.1" diff --git a/Pipfile.lock b/Pipfile.lock index b31db559b..ce4bc3706 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "850b36b950a385286e33e2c8b0912b06b60ee10907d6fbe2b1e8e84b2651e631" + "sha256": "41c4cfd836eadf628d8fc3a48fdf6b2b970c4cacad905616e3107b8269c7fe40" }, "pipfile-spec": 6, "requires": { @@ -338,14 +338,6 @@ "markers": "python_version >= '3.6'", "version": "==3.10" }, - "jenkinsapi": { - "hashes": [ - "sha256:246a98a63e61f54a15d16105cb15488c5670734df41e86c7af0d5d9c0af240b9", - "sha256:c1633f99d0400903f92e8962adfec7bae09f5ed9d984c6b37831b014de6efa42" - ], - "index": "pypi", - "version": "==0.3.13" - }, "jmespath": { "hashes": [ "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980", @@ -677,13 +669,6 @@ "markers": "python_version >= '3.8' and python_version < '4'", "version": "==0.72.0" }, - "pytz": { - "hashes": [ - "sha256:2aa355083c50a0f93fa581709deac0c9ad65cca8a9e9beac660adcbd493c798a", - "sha256:31c7c1817eb7fae7ca4b8c7ee50c72f93aa2dd863de768e1ef4245d426aa0725" - ], - "version": "==2024.2" - }, "pyyaml": { "hashes": [ "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff", @@ -1167,100 +1152,100 @@ }, "aiohttp": { "hashes": [ - "sha256:10c7932337285a6bfa3a5fe1fd4da90b66ebfd9d0cbd1544402e1202eb9a8c3e", - "sha256:177126e971782769b34933e94fddd1089cef0fe6b82fee8a885e539f5b0f0c6a", - "sha256:1ce46dfb49cfbf9e92818be4b761d4042230b1f0e05ffec0aad15b3eb162b905", - "sha256:1e7a6af57091056a79a35104d6ec29d98ec7f1fb7270ad9c6fff871b678d1ff8", - "sha256:21a72f4a9c69a8567a0aca12042f12bba25d3139fd5dd8eeb9931f4d9e8599cd", - "sha256:21c1925541ca84f7b5e0df361c0a813a7d6a56d3b0030ebd4b220b8d232015f9", - "sha256:21f8225f7dc187018e8433c9326be01477fb2810721e048b33ac49091b19fb4a", - "sha256:22cdeb684d8552490dd2697a5138c4ecb46f844892df437aaf94f7eea99af879", - "sha256:270e653b5a4b557476a1ed40e6b6ce82f331aab669620d7c95c658ef976c9c5e", - "sha256:2df786c96c57cd6b87156ba4c5f166af7b88f3fc05f9d592252fdc83d8615a3c", - "sha256:32710d6b3b6c09c60c794d84ca887a3a2890131c0b02b3cefdcc6709a2260a7c", - "sha256:33a68011a38020ed4ff41ae0dbf4a96a202562ecf2024bdd8f65385f1d07f6ef", - "sha256:365783e1b7c40b59ed4ce2b5a7491bae48f41cd2c30d52647a5b1ee8604c68ad", - "sha256:3a95d2686bc4794d66bd8de654e41b5339fab542b2bca9238aa63ed5f4f2ce82", - "sha256:3b2036479b6b94afaaca7d07b8a68dc0e67b0caf5f6293bb6a5a1825f5923000", - "sha256:3c7f270f4ca92760f98a42c45a58674fff488e23b144ec80b1cc6fa2effed377", - "sha256:3f6d47e392c27206701565c8df4cac6ebed28fdf6dcaea5b1eea7a4631d8e6db", - "sha256:40d2d719c3c36a7a65ed26400e2b45b2d9ed7edf498f4df38b2ae130f25a0d01", - "sha256:4618f0d2bf523043866a9ff8458900d8eb0a6d4018f251dae98e5f1fb699f3a8", - "sha256:471a8c47344b9cc309558b3fcc469bd2c12b49322b4b31eb386c4a2b2d44e44a", - "sha256:4954e6b06dd0be97e1a5751fc606be1f9edbdc553c5d9b57d72406a8fbd17f9d", - "sha256:497a7d20caea8855c5429db3cdb829385467217d7feb86952a6107e033e031b9", - "sha256:4b91f4f62ad39a8a42d511d66269b46cb2fb7dea9564c21ab6c56a642d28bff5", - "sha256:4dbf252ac19860e0ab56cd480d2805498f47c5a2d04f5995d8d8a6effd04b48c", - "sha256:4e10b04542d27e21538e670156e88766543692a0a883f243ba8fad9ddea82e53", - "sha256:5284997e3d88d0dfb874c43e51ae8f4a6f4ca5b90dcf22995035187253d430db", - "sha256:57359785f27394a8bcab0da6dcd46706d087dfebf59a8d0ad2e64a4bc2f6f94f", - "sha256:597128cb7bc5f068181b49a732961f46cb89f85686206289d6ccb5e27cb5fbe2", - "sha256:5aa1a073514cf59c81ad49a4ed9b5d72b2433638cd53160fd2f3a9cfa94718db", - "sha256:680dbcff5adc7f696ccf8bf671d38366a1f620b5616a1d333d0cb33956065395", - "sha256:6984dda9d79064361ab58d03f6c1e793ea845c6cfa89ffe1a7b9bb400dfd56bd", - "sha256:69de056022e7abf69cb9fec795515973cc3eeaff51e3ea8d72a77aa933a91c52", - "sha256:6c7efa6616a95e3bd73b8a69691012d2ef1f95f9ea0189e42f338fae080c2fc6", - "sha256:6d1ad868624f6cea77341ef2877ad4e71f7116834a6cd7ec36ec5c32f94ee6ae", - "sha256:713dff3f87ceec3bde4f3f484861464e722cf7533f9fa6b824ec82bb5a9010a7", - "sha256:71462f8eeca477cbc0c9700a9464e3f75f59068aed5e9d4a521a103692da72dc", - "sha256:7c38cfd355fd86c39b2d54651bd6ed7d63d4fe3b5553f364bae3306e2445f847", - "sha256:8296edd99d0dd9d0eb8b9e25b3b3506eef55c1854e9cc230f0b3f885f680410b", - "sha256:85431c9131a9a0f65260dc7a65c800ca5eae78c4c9931618f18c8e0933a0e0c1", - "sha256:85e4d7bd05d18e4b348441e7584c681eff646e3bf38f68b2626807f3add21aa2", - "sha256:8885ca09d3a9317219c0831276bfe26984b17b2c37b7bf70dd478d17092a4772", - "sha256:8960fabc20bfe4fafb941067cda8e23c8c17c98c121aa31c7bf0cdab11b07842", - "sha256:9443d9ebc5167ce1fbb552faf2d666fb22ef5716a8750be67efd140a7733738c", - "sha256:9721554bfa9e15f6e462da304374c2f1baede3cb06008c36c47fa37ea32f1dc4", - "sha256:98a4eb60e27033dee9593814ca320ee8c199489fbc6b2699d0f710584db7feb7", - "sha256:98fae99d5c2146f254b7806001498e6f9ffb0e330de55a35e72feb7cb2fa399b", - "sha256:9a281cba03bdaa341c70b7551b2256a88d45eead149f48b75a96d41128c240b3", - "sha256:a087c84b4992160ffef7afd98ef24177c8bd4ad61c53607145a8377457385100", - "sha256:a1ba7bc139592339ddeb62c06486d0fa0f4ca61216e14137a40d626c81faf10c", - "sha256:a3081246bab4d419697ee45e555cef5cd1def7ac193dff6f50be761d2e44f194", - "sha256:a72f89aea712c619b2ca32c6f4335c77125ede27530ad9705f4f349357833695", - "sha256:a78ba86d5a08207d1d1ad10b97aed6ea48b374b3f6831d02d0b06545ac0f181e", - "sha256:a961ee6f2cdd1a2be4735333ab284691180d40bad48f97bb598841bfcbfb94ec", - "sha256:ab1546fc8e00676febc81c548a876c7bde32f881b8334b77f84719ab2c7d28dc", - "sha256:ab2d6523575fc98896c80f49ac99e849c0b0e69cc80bf864eed6af2ae728a52b", - "sha256:aff048793d05e1ce05b62e49dccf81fe52719a13f4861530706619506224992b", - "sha256:b1a012677b8e0a39e181e218de47d6741c5922202e3b0b65e412e2ce47c39337", - "sha256:b667e2a03407d79a76c618dc30cedebd48f082d85880d0c9c4ec2faa3e10f43e", - "sha256:b91557ee0893da52794b25660d4f57bb519bcad8b7df301acd3898f7197c5d81", - "sha256:badb51d851358cd7535b647bb67af4854b64f3c85f0d089c737f75504d5910ec", - "sha256:c36074b26f3263879ba8e4dbd33db2b79874a3392f403a70b772701363148b9f", - "sha256:c4916070e12ae140110aa598031876c1bf8676a36a750716ea0aa5bd694aa2e7", - "sha256:c6769d71bfb1ed60321363a9bc05e94dcf05e38295ef41d46ac08919e5b00d19", - "sha256:c887019dbcb4af58a091a45ccf376fffe800b5531b45c1efccda4bedf87747ea", - "sha256:cd9716ef0224fe0d0336997eb242f40619f9f8c5c57e66b525a1ebf9f1d8cebe", - "sha256:ceacea31f8a55cdba02bc72c93eb2e1b77160e91f8abd605969c168502fd71eb", - "sha256:d088ca05381fd409793571d8e34eca06daf41c8c50a05aeed358d2d340c7af81", - "sha256:d3a79200a9d5e621c4623081ddb25380b713c8cf5233cd11c1aabad990bb9381", - "sha256:d82404a0e7b10e0d7f022cf44031b78af8a4f99bd01561ac68f7c24772fed021", - "sha256:d95ae4420669c871667aad92ba8cce6251d61d79c1a38504621094143f94a8b4", - "sha256:da57af0c54a302b7c655fa1ccd5b1817a53739afa39924ef1816e7b7c8a07ccb", - "sha256:ddb9b9764cfb4459acf01c02d2a59d3e5066b06a846a364fd1749aa168efa2be", - "sha256:de23085cf90911600ace512e909114385026b16324fa203cc74c81f21fd3276a", - "sha256:e1f0f7b27171b2956a27bd8f899751d0866ddabdd05cbddf3520f945130a908c", - "sha256:e32148b4a745e70a255a1d44b5664de1f2e24fcefb98a75b60c83b9e260ddb5b", - "sha256:e45fdfcb2d5bcad83373e4808825b7512953146d147488114575780640665027", - "sha256:e56bb7e31c4bc79956b866163170bc89fd619e0581ce813330d4ea46921a4881", - "sha256:e860985f30f3a015979e63e7ba1a391526cdac1b22b7b332579df7867848e255", - "sha256:ee3587506898d4a404b33bd19689286ccf226c3d44d7a73670c8498cd688e42c", - "sha256:ee97c4e54f457c366e1f76fbbf3e8effee9de57dae671084a161c00f481106ce", - "sha256:ef9b484604af05ca745b6108ca1aaa22ae1919037ae4f93aaf9a37ba42e0b835", - "sha256:f21e8f2abed9a44afc3d15bba22e0dfc71e5fa859bea916e42354c16102b036f", - "sha256:f23a6c1d09de5de89a33c9e9b229106cb70dcfdd55e81a3a3580eaadaa32bc92", - "sha256:f5d5d5401744dda50b943d8764508d0e60cc2d3305ac1e6420935861a9d544bc", - "sha256:f78e2a78432c537ae876a93013b7bc0027ba5b93ad7b3463624c4b6906489332", - "sha256:f8179855a4e4f3b931cb1764ec87673d3fbdcca2af496c8d30567d7b034a13db", - "sha256:fc0e7f91705445d79beafba9bb3057dd50830e40fe5417017a76a214af54e122", - "sha256:fe285a697c851734285369614443451462ce78aac2b77db23567507484b1dc6f", - "sha256:fe3d79d6af839ffa46fdc5d2cf34295390894471e9875050eafa584cb781508d", - "sha256:fecd55e7418fabd297fd836e65cbd6371aa4035a264998a091bbf13f94d9c44d", - "sha256:ffef3d763e4c8fc97e740da5b4d0f080b78630a3914f4e772a122bbfa608c1db" + "sha256:02d1d6610588bcd743fae827bd6f2e47e0d09b346f230824b4c6fb85c6065f9c", + "sha256:03690541e4cc866eef79626cfa1ef4dd729c5c1408600c8cb9e12e1137eed6ab", + "sha256:0bc059ecbce835630e635879f5f480a742e130d9821fbe3d2f76610a6698ee25", + "sha256:0c21c82df33b264216abffff9f8370f303dab65d8eee3767efbbd2734363f677", + "sha256:1298b854fd31d0567cbb916091be9d3278168064fca88e70b8468875ef9ff7e7", + "sha256:1321658f12b6caffafdc35cfba6c882cb014af86bef4e78c125e7e794dfb927b", + "sha256:143b0026a9dab07a05ad2dd9e46aa859bffdd6348ddc5967b42161168c24f857", + "sha256:16e6a51d8bc96b77f04a6764b4ad03eeef43baa32014fce71e882bd71302c7e4", + "sha256:172ad884bb61ad31ed7beed8be776eb17e7fb423f1c1be836d5cb357a096bf12", + "sha256:17c272cfe7b07a5bb0c6ad3f234e0c336fb53f3bf17840f66bd77b5815ab3d16", + "sha256:1a0ee6c0d590c917f1b9629371fce5f3d3f22c317aa96fbdcce3260754d7ea21", + "sha256:2746d8994ebca1bdc55a1e998feff4e94222da709623bb18f6e5cfec8ec01baf", + "sha256:2914caa46054f3b5ff910468d686742ff8cff54b8a67319d75f5d5945fd0a13d", + "sha256:2bbf94d4a0447705b7775417ca8bb8086cc5482023a6e17cdc8f96d0b1b5aba6", + "sha256:2bd9f3eac515c16c4360a6a00c38119333901b8590fe93c3257a9b536026594d", + "sha256:2c33fa6e10bb7ed262e3ff03cc69d52869514f16558db0626a7c5c61dde3c29f", + "sha256:2d37f4718002863b82c6f391c8efd4d3a817da37030a29e2682a94d2716209de", + "sha256:3668d0c2a4d23fb136a753eba42caa2c0abbd3d9c5c87ee150a716a16c6deec1", + "sha256:36d4fba838be5f083f5490ddd281813b44d69685db910907636bc5dca6322316", + "sha256:40ff5b7660f903dc587ed36ef08a88d46840182d9d4b5694e7607877ced698a1", + "sha256:42775de0ca04f90c10c5c46291535ec08e9bcc4756f1b48f02a0657febe89b10", + "sha256:482c85cf3d429844396d939b22bc2a03849cb9ad33344689ad1c85697bcba33a", + "sha256:4e6cb75f8ddd9c2132d00bc03c9716add57f4beff1263463724f6398b813e7eb", + "sha256:4edc3fd701e2b9a0d605a7b23d3de4ad23137d23fc0dbab726aa71d92f11aaaf", + "sha256:4fd16b30567c5b8e167923be6e027eeae0f20cf2b8a26b98a25115f28ad48ee0", + "sha256:5002a02c17fcfd796d20bac719981d2fca9c006aac0797eb8f430a58e9d12431", + "sha256:51d0a4901b27272ae54e42067bc4b9a90e619a690b4dc43ea5950eb3070afc32", + "sha256:558b3d223fd631ad134d89adea876e7fdb4c93c849ef195049c063ada82b7d08", + "sha256:5c070430fda1a550a1c3a4c2d7281d3b8cfc0c6715f616e40e3332201a253067", + "sha256:5f392ef50e22c31fa49b5a46af7f983fa3f118f3eccb8522063bee8bfa6755f8", + "sha256:60555211a006d26e1a389222e3fab8cd379f28e0fbf7472ee55b16c6c529e3a6", + "sha256:608cecd8d58d285bfd52dbca5b6251ca8d6ea567022c8a0eaae03c2589cd9af9", + "sha256:60ad5b8a7452c0f5645c73d4dad7490afd6119d453d302cd5b72b678a85d6044", + "sha256:63649309da83277f06a15bbdc2a54fbe75efb92caa2c25bb57ca37762789c746", + "sha256:6ebdc3b3714afe1b134b3bbeb5f745eed3ecbcff92ab25d80e4ef299e83a5465", + "sha256:6f3c6648aa123bcd73d6f26607d59967b607b0da8ffcc27d418a4b59f4c98c7c", + "sha256:7003f33f5f7da1eb02f0446b0f8d2ccf57d253ca6c2e7a5732d25889da82b517", + "sha256:776e9f3c9b377fcf097c4a04b241b15691e6662d850168642ff976780609303c", + "sha256:85711eec2d875cd88c7eb40e734c4ca6d9ae477d6f26bd2b5bb4f7f60e41b156", + "sha256:87d1e4185c5d7187684d41ebb50c9aeaaaa06ca1875f4c57593071b0409d2444", + "sha256:8a3f063b41cc06e8d0b3fcbbfc9c05b7420f41287e0cd4f75ce0a1f3d80729e6", + "sha256:8b3fb28a9ac8f2558760d8e637dbf27aef1e8b7f1d221e8669a1074d1a266bb2", + "sha256:8bd9125dd0cc8ebd84bff2be64b10fdba7dc6fd7be431b5eaf67723557de3a31", + "sha256:8be1a65487bdfc285bd5e9baf3208c2132ca92a9b4020e9f27df1b16fab998a9", + "sha256:8cc0d13b4e3b1362d424ce3f4e8c79e1f7247a00d792823ffd640878abf28e56", + "sha256:8d9d10d10ec27c0d46ddaecc3c5598c4db9ce4e6398ca872cdde0525765caa2f", + "sha256:8debb45545ad95b58cc16c3c1cc19ad82cffcb106db12b437885dbee265f0ab5", + "sha256:91aa966858593f64c8a65cdefa3d6dc8fe3c2768b159da84c1ddbbb2c01ab4ef", + "sha256:9331dd34145ff105177855017920dde140b447049cd62bb589de320fd6ddd582", + "sha256:99f9678bf0e2b1b695e8028fedac24ab6770937932eda695815d5a6618c37e04", + "sha256:9fdf5c839bf95fc67be5794c780419edb0dbef776edcfc6c2e5e2ffd5ee755fa", + "sha256:a14e4b672c257a6b94fe934ee62666bacbc8e45b7876f9dd9502d0f0fe69db16", + "sha256:a19caae0d670771ea7854ca30df76f676eb47e0fd9b2ee4392d44708f272122d", + "sha256:a35ed3d03910785f7d9d6f5381f0c24002b2b888b298e6f941b2fc94c5055fcd", + "sha256:a61df62966ce6507aafab24e124e0c3a1cfbe23c59732987fc0fd0d71daa0b88", + "sha256:a6e00c8a92e7663ed2be6fcc08a2997ff06ce73c8080cd0df10cc0321a3168d7", + "sha256:ac3196952c673822ebed8871cf8802e17254fff2a2ed4835d9c045d9b88c5ec7", + "sha256:ac74e794e3aee92ae8f571bfeaa103a141e409863a100ab63a253b1c53b707eb", + "sha256:ad3675c126f2a95bde637d162f8231cff6bc0bc9fbe31bd78075f9ff7921e322", + "sha256:aeebd3061f6f1747c011e1d0b0b5f04f9f54ad1a2ca183e687e7277bef2e0da2", + "sha256:ba1a599255ad6a41022e261e31bc2f6f9355a419575b391f9655c4d9e5df5ff5", + "sha256:bbdb8def5268f3f9cd753a265756f49228a20ed14a480d151df727808b4531dd", + "sha256:c2555e4949c8d8782f18ef20e9d39730d2656e218a6f1a21a4c4c0b56546a02e", + "sha256:c2695c61cf53a5d4345a43d689f37fc0f6d3a2dc520660aec27ec0f06288d1f9", + "sha256:c2b627d3c8982691b06d89d31093cee158c30629fdfebe705a91814d49b554f8", + "sha256:c46131c6112b534b178d4e002abe450a0a29840b61413ac25243f1291613806a", + "sha256:c54dc329cd44f7f7883a9f4baaefe686e8b9662e2c6c184ea15cceee587d8d69", + "sha256:c7d7cafc11d70fdd8801abfc2ff276744ae4cb39d8060b6b542c7e44e5f2cfc2", + "sha256:cb0b2d5d51f96b6cc19e6ab46a7b684be23240426ae951dcdac9639ab111b45e", + "sha256:d15a29424e96fad56dc2f3abed10a89c50c099f97d2416520c7a543e8fddf066", + "sha256:d1f5c9169e26db6a61276008582d945405b8316aae2bb198220466e68114a0f5", + "sha256:d271f770b52e32236d945911b2082f9318e90ff835d45224fa9e28374303f729", + "sha256:d646fdd74c25bbdd4a055414f0fe32896c400f38ffbdfc78c68e62812a9e0257", + "sha256:d6e395c3d1f773cf0651cd3559e25182eb0c03a2777b53b4575d8adc1149c6e9", + "sha256:d7c071235a47d407b0e93aa6262b49422dbe48d7d8566e1158fecc91043dd948", + "sha256:d97273a52d7f89a75b11ec386f786d3da7723d7efae3034b4dda79f6f093edc1", + "sha256:dcf354661f54e6a49193d0b5653a1b011ba856e0b7a76bda2c33e4c6892f34ea", + "sha256:e3e7fabedb3fe06933f47f1538df7b3a8d78e13d7167195f51ca47ee12690373", + "sha256:e525b69ee8a92c146ae5b4da9ecd15e518df4d40003b01b454ad694a27f498b5", + "sha256:e709d6ac598c5416f879bb1bae3fd751366120ac3fa235a01de763537385d036", + "sha256:e83dfefb4f7d285c2d6a07a22268344a97d61579b3e0dce482a5be0251d672ab", + "sha256:e86260b76786c28acf0b5fe31c8dca4c2add95098c709b11e8c35b424ebd4f5b", + "sha256:e883b61b75ca6efc2541fcd52a5c8ccfe288b24d97e20ac08fdf343b8ac672ea", + "sha256:f0a44bb40b6aaa4fb9a5c1ee07880570ecda2065433a96ccff409c9c20c1624a", + "sha256:f82ace0ec57c94aaf5b0e118d4366cff5889097412c75aa14b4fd5fc0c44ee3e", + "sha256:f9ca09414003c0e96a735daa1f071f7d7ed06962ef4fa29ceb6c80d06696d900", + "sha256:fa430b871220dc62572cef9c69b41e0d70fcb9d486a4a207a5de4c1f25d82593", + "sha256:fc262c3df78c8ff6020c782d9ce02e4bcffe4900ad71c0ecdad59943cba54442", + "sha256:fcd546782d03181b0b1d20b43d612429a90a68779659ba8045114b867971ab71", + "sha256:fd4ceeae2fb8cabdd1b71c82bfdd39662473d3433ec95b962200e9e752fb70d0", + "sha256:fec5fac7aea6c060f317f07494961236434928e6f4374e170ef50b3001e14581" ], "markers": "python_version >= '3.6'", - "version": "==3.10.8" + "version": "==3.10.9" }, "aiosignal": { "hashes": [ diff --git a/mpyl_config.example.yml b/mpyl_config.example.yml index 6241423b8..34cf32584 100644 --- a/mpyl_config.example.yml +++ b/mpyl_config.example.yml @@ -67,12 +67,6 @@ docker: compose: periodSeconds: 2 failureThreshold: 20 -jenkins: - url: 'https://acme.infra.nl/' - pipelines: - some-pipeline: 'Acme Pipeline - Main' - mpyl-test: 'MPyL Pipeline - Test' - defaultPipeline: 'mpyl-test' sbt: command: 'sbt' clientCommand: 'sbtn' diff --git a/releases/notes/1.7.5.md b/releases/notes/1.7.5.md new file mode 100644 index 000000000..7c4681488 --- /dev/null +++ b/releases/notes/1.7.5.md @@ -0,0 +1,9 @@ + +#### Demonstrate MPyL plugin mechanism. +MPyL allows steps to be implemented outside and registered via a [plugin mechanism](https://vandebron.github.io/mpyl/mpyl/steps.html) + +Creating steps outside the MPyL library gives a much quicker roundtrip, +because you can build and test steps locally in the repo in which you're using MPyL. + +The mechanism is demonstrated in [plugin-run.py](../../plugin-run.py) which imports two +[Gradle](https://gradle.org/) build steps defined in [plugins/gradle.py](../../plugins/gradle.py). \ No newline at end of file diff --git a/src/mpyl/artifacts/build_artifacts.py b/src/mpyl/artifacts/build_artifacts.py index c1406bfab..16e9f1778 100644 --- a/src/mpyl/artifacts/build_artifacts.py +++ b/src/mpyl/artifacts/build_artifacts.py @@ -14,12 +14,11 @@ from git.exc import GitCommandError from github import Github -from ..cli.commands.build.jenkins import get_token from ..constants import RUN_ARTIFACTS_FOLDER from ..project import Project, Target, load_project from ..steps.deploy.k8s.deploy_config import DeployConfig, get_namespace from ..steps.models import RunProperties -from ..utilities.github import GithubConfig +from ..utilities.github import GithubConfig, get_token from ..utilities.repo import Repository, RepoConfig diff --git a/src/mpyl/cli/build.py b/src/mpyl/cli/build.py index d8aa71d50..c77cda678 100644 --- a/src/mpyl/cli/build.py +++ b/src/mpyl/cli/build.py @@ -28,7 +28,6 @@ ) from . import create_console_logger from .commands.build.artifacts import prepare_artifacts_repo, branch_name -from .commands.build.jenkins import JenkinsRunParameters, run_jenkins, get_token from ..artifacts.build_artifacts import ( ManifestPathTransformer, BuildCacheTransformer, @@ -46,7 +45,7 @@ from ..steps.deploy.k8s.deploy_config import DeployConfig from ..steps.models import RunProperties from ..steps.run_properties import construct_run_properties -from ..utilities.github import GithubConfig +from ..utilities.github import GithubConfig, get_token from ..utilities.pyaml_env import parse_config from ..utilities.repo import Repository, RepoConfig @@ -322,131 +321,6 @@ def ask_for_tag_input(ctx, _param, value) -> Optional[str]: return value -@build.command(help="Run a multi branch pipeline build on Jenkins") -@click.option( - "--user", - "-u", - help="Authentication API user. Can be set via env var JENKINS_USER", - envvar="JENKINS_USER", - type=click.STRING, - required=True, -) -@click.option( - "--password", - "-p", - help="Authentication API password. Can be set via env var JENKINS_PASSWORD", - envvar="JENKINS_PASSWORD", - type=click.STRING, - required=True, -) -@click.option( - "--pipeline", - "-pl", - help="The pipeline to run. Must be one of the pipelines listed in `jenkins.pipelines`. " - "Default value is `jenkins.defaultPipeline`", - type=Pipeline(), - required=False, -) -@click.option( - "--version", - "-v", - help="A specific version on https://pypi.org/project/mpyl/ to use for the build.", - type=click.STRING, - required=False, -) -@click.option( - "--test", - "-t", - help="The version supplied by `--version` should be considered from the Test PyPi mirror at" - " https://test.pypi.org/project/mpyl/.", - is_flag=True, - default=False, - required=False, -) -@click.option( - "--arguments", - "-a", - multiple=True, - help="A series of arguments to pass to the pipeline. Note that will run within the pipenv in jenkins. " - "To execute `mpyl build status`, pass `-a run -a mpyl -a build -a status`", -) -@click.option( - "--background", - "-bg", - help="Starts Jenkins build in a 'fire and forget' fashion. " - "Can be set via env var MPYL_JENKINS_BACKGROUND", - envvar="MPYL_JENKINS_BACKGROUND", - is_flag=True, - default=False, -) -@click.option( - "--silent", - "-s", - help="Indicates whether to show Jenkins' logging or not. " - "Can be set via env var MPYL_JENKINS_SILENT", - envvar="MPYL_JENKINS_SILENT", - is_flag=True, - default=False, -) -@click.option( - "--tag", - is_flag=False, - flag_value="prompt", - default="not_set", - callback=ask_for_tag_input, -) -@click.pass_context -def jenkins( # pylint: disable=too-many-arguments, too-many-locals - ctx, - user, - password, - pipeline, - version, - test, - arguments, - background, - silent, - tag, -): - try: - asyncio.run(warn_if_update(ctx.obj.console)) - if "jenkins" not in ctx.obj.config: - ctx.obj.console.print( - "No Jenkins configuration found in config file. " - "Please add a `jenkins` section to your MPyL config file." - ) - sys.exit(0) - jenkins_config = ctx.obj.config["jenkins"] - - selected_pipeline = pipeline if pipeline else jenkins_config["defaultPipeline"] - pipeline_parameters = ( - {"TEST": "true" if test else "false", "VERSION": version} if version else {} - ) - if arguments: - pipeline_parameters["BUILD_PARAMS"] = " ".join(arguments) - - targets = ( - select_targets() - if tag - else [Target.PULL_REQUEST.name] # pylint: disable=no-member - ) - for target in targets: - run_argument = JenkinsRunParameters( - jenkins_user=user, - jenkins_password=password, - config=ctx.obj.config, - pipeline=selected_pipeline, - pipeline_parameters=pipeline_parameters, - verbose=not silent or ctx.obj.verbose, - follow=not background, - tag=tag, - tag_target=getattr(Target, target) if tag else None, - ) - run_jenkins(run_argument) - except asyncio.exceptions.TimeoutError: - pass - - @build.command(help=f"Clean all MPyL metadata in `{RUN_ARTIFACTS_FOLDER}` folders") @click.option( "--filter", diff --git a/src/mpyl/cli/commands/build/jenkins.py b/src/mpyl/cli/commands/build/jenkins.py deleted file mode 100644 index 31a5de9c3..000000000 --- a/src/mpyl/cli/commands/build/jenkins.py +++ /dev/null @@ -1,137 +0,0 @@ -"""Jenkins multibranch pipeline build tool""" -import subprocess -from dataclasses import dataclass -from typing import Optional - -import requests -from github import Github -from jenkinsapi.jenkins import Jenkins -from rich.console import Console -from rich.markdown import Markdown -from rich.status import Status - -from . import play_sound, Sound -from ....project import Target -from ....utilities.github import GithubConfig, get_pr_for_branch -from ....utilities.jenkins import JenkinsConfig, Pipeline -from ....utilities.jenkins.runner import JenkinsRunner -from ....utilities.repo import RepoConfig, Repository - - -@dataclass(frozen=True) -class JenkinsRunParameters: - jenkins_user: str - jenkins_password: str - config: dict - pipeline: str - pipeline_parameters: dict - verbose: bool - follow: bool - tag: Optional[str] = None - tag_target: Target = Target.ACCEPTANCE - - -def get_token(github_config: GithubConfig): - if github_config.token: - return github_config.token - return ( - subprocess.run( - ["gh", "auth", "token"], - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - check=True, - ) - .stdout.decode("utf-8") - .strip() - ) - - -def __get_pr_pipeline( - config: dict, git_repo: Repository, pipeline: str, status: Status -) -> Optional[Pipeline]: - github_config = GithubConfig.from_config(config) - github = Github(login_or_token=get_token(github_config)) - - repo = github.get_repo(github_config.repository) - - branch = git_repo.get_branch - if not branch: - status.console.log("Could not determine current branch") - return None - - if git_repo.main_branch == branch: - status.console.log( - f"On main branch ({branch}), cannot determine which PR to build" - ) - return None - try: - pull = get_pr_for_branch(repo, branch) - return Pipeline( - target=Target.PULL_REQUEST, - tag=f"{pull.number}", - url=pull.html_url, - pipeline_name=pipeline, - body=pull.body, - jenkins_config=JenkinsConfig.from_config(config), - ) - except ValueError as exc: - status.console.log(exc) - return None - - -def run_jenkins(run_config: JenkinsRunParameters): - log_console = Console(log_path=False, log_time=False) - with log_console.status( - "Fetching Github info.. [bright_blue]>gh pr view[/bright_blue]" - ) as status: - config = run_config.config - - with Repository(RepoConfig.from_config(config)) as git_repo: - try: - pipeline_info = ( - Pipeline( - target=run_config.tag_target, - tag=run_config.tag, - url="https://tag-url", - pipeline_name=run_config.pipeline, - body="", - jenkins_config=JenkinsConfig.from_config(config), - ) - if run_config.tag - else __get_pr_pipeline( - config, git_repo, run_config.pipeline, status - ) - ) - if not pipeline_info: - return - - if run_config.tag: - run_config.pipeline_parameters[ - "DEPLOY_CHOICE" - ] = run_config.tag_target.value - - status.start() - status.update( - f"Fetching Jenkins info for {pipeline_info.human_readable()} ..." - ) - - runner = JenkinsRunner( - pipeline=pipeline_info, - jenkins=Jenkins( - baseurl=JenkinsConfig.from_config(config).url, - username=run_config.jenkins_user, - password=run_config.jenkins_password, - ), - status=status, - follow=run_config.follow, - verbose=run_config.verbose, - ) - runner.run(run_config.pipeline_parameters) - except requests.ConnectionError: - play_sound(Sound.FAILURE) - status.console.log("⚠️ Could not connect. Are you on VPN?") - except Exception as exc: - status.console.print(Markdown(f"Unexpected exception: {exc}")) - if run_config.verbose: - status.console.print_exception() - raise exc diff --git a/src/mpyl/cli/commands/health/checks.py b/src/mpyl/cli/commands/health/checks.py index bf3aa58ee..180fd7d96 100644 --- a/src/mpyl/cli/commands/health/checks.py +++ b/src/mpyl/cli/commands/health/checks.py @@ -3,10 +3,8 @@ import asyncio import os import pkgutil -import shutil import sys from pathlib import Path -from subprocess import CalledProcessError from typing import Optional import jsonschema @@ -15,7 +13,6 @@ from rich.markdown import Markdown from rich.prompt import Confirm -from ..build.jenkins import get_token from ....cli import get_latest_publication, get_meta_version from ....constants import ( DEFAULT_CONFIG_FILE_NAME, @@ -30,8 +27,6 @@ upgrade_file, PROPERTIES_UPGRADERS, ) -from ....utilities.github import GithubConfig -from ....utilities.jenkins import JenkinsConfig from ....utilities.pyaml_env import parse_config from ....validation import validate @@ -51,9 +46,7 @@ def print(self, text: str): self.console.print(Markdown(text)) -def perform_health_checks( - bare_console: Console, is_ci: bool = False, perform_upgrade: bool = False -): +def perform_health_checks(bare_console: Console, perform_upgrade: bool = False): console = HealthConsole(bare_console) load_dotenv(Path(".env")) @@ -104,72 +97,6 @@ def perform_health_checks( perform_upgrade=perform_upgrade, ) - if not is_ci: - console.title("Jenkins") - __check_jenkins(console) - - -def __check_jenkins(console: HealthConsole): - path = os.environ.get("MPYL_CONFIG_PATH", default=DEFAULT_CONFIG_FILE_NAME) - if not os.path.exists(path): - console.check(f"Configuration not found at: `{path}`", success=False) - return - - parsed = parse_config(Path(path)) - - try: - jenkins_conf = JenkinsConfig.from_config(parsed) - console.check( - f"Jenkins configured for pipeline `{jenkins_conf.default_pipeline}` " - f"at [{jenkins_conf.url}]({jenkins_conf.url})", - success=True, - ) - except KeyError as exc: - console.check(f"Jenkins not (correctly) configured: {exc}", success=False) - return - - gh_is_installed = shutil.which("gh") - if gh_is_installed: - console.check("Github cli client `gh` installed", success=True) - else: - console.check( - "Github cli client `gh` not found. Install via [https://cli.github.com/](https://cli.github.com/) " - "and run `gh auth login`", - success=False, - ) - - if gh_is_installed: - try: - get_token(GithubConfig.from_config(parsed)) - console.check("Github token found", success=True) - except KeyError: - console.check( - "Config invalid, cannot determine github configuration", success=False - ) - except CalledProcessError: - console.check( - "Github token not found. Log in with `gh auth login`", success=False - ) - - if os.environ.get("JENKINS_USER"): - console.check("Jenkins user set", success=True) - else: - jenkins_url = ( - f"{JenkinsConfig.from_config(parsed).url}user/me@vandebron.nl/configure" - ) - message = ( - f"Jenkins user not set via JENKINS_USER env var. Create a user API token in Jenkins" - f" (user:password) API token: {jenkins_url}" - ) - console.check(message, success=False) - - if os.environ.get("JENKINS_PASSWORD"): - console.check("Jenkins password set", success=True) - else: - console.check( - "Jenkins password not set via JENKINS_PASSWORD env var", success=False - ) - def __check_version(console): update = asyncio.get_event_loop().run_until_complete(get_latest_publication()) diff --git a/src/mpyl/cli/health.py b/src/mpyl/cli/health.py index 0583985c8..5e9dc40ce 100644 --- a/src/mpyl/cli/health.py +++ b/src/mpyl/cli/health.py @@ -7,13 +7,6 @@ @click.command("health") -@click.option( - "--ci", - "is_ci", - is_flag=True, - default=False, - help="Run health checks relevant only for CI builds.", -) @click.option( "--upgrade", "-u", @@ -21,7 +14,7 @@ default=False, help="Perform config upgrades if necessary", ) -def health(is_ci, upgrade): +def health(upgrade): """Health check""" console = create_console_logger(show_path=False, verbose=False, max_width=0) - perform_health_checks(console, is_ci, upgrade) + perform_health_checks(console, upgrade) diff --git a/src/mpyl/schema/mpyl_config.schema.yml b/src/mpyl/schema/mpyl_config.schema.yml index 5c96bd3e5..965a88ffb 100644 --- a/src/mpyl/schema/mpyl_config.schema.yml +++ b/src/mpyl/schema/mpyl_config.schema.yml @@ -22,8 +22,6 @@ definitions: "$ref": "#/definitions/Kubernetes" project: "$ref": "#/definitions/Project" - jenkins: - "$ref": "#/definitions/Jenkins" sbt: "$ref": "#/definitions/Sbt" slack: @@ -444,19 +442,6 @@ definitions: required: - botToken - icons - Jenkins: - type: object - additionalProperties: false - required: [ 'url' ] - properties: - url: - type: [ string ] - format: url - pipelines: - type: object - additionalProperties: { "type": "string" } - defaultPipeline: - type: string Jira: type: object additionalProperties: false diff --git a/src/mpyl/utilities/github/__init__.py b/src/mpyl/utilities/github/__init__.py index 46ea88df9..3db0dc351 100644 --- a/src/mpyl/utilities/github/__init__.py +++ b/src/mpyl/utilities/github/__init__.py @@ -1,4 +1,6 @@ -"""GitHub related utility methods""" +"""GitHub related utility methods.""" + +import subprocess from dataclasses import dataclass from typing import Optional @@ -64,3 +66,18 @@ def get_pr_for_branch(repo: Repository, branch: str) -> PullRequest: ) return pull_request + + +def get_token(github_config: GithubConfig): + if github_config.token: + return github_config.token + return ( + subprocess.run( + ["gh", "auth", "token"], + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + check=True, + ) + .stdout.decode("utf-8") + .strip() + ) diff --git a/src/mpyl/utilities/jenkins/__init__.py b/src/mpyl/utilities/jenkins/__init__.py deleted file mode 100644 index 334cfa9b4..000000000 --- a/src/mpyl/utilities/jenkins/__init__.py +++ /dev/null @@ -1,54 +0,0 @@ -"""Utility functions for Jenkins""" -from dataclasses import dataclass - -from ...project import Target - - -@dataclass(frozen=True) -class JenkinsConfig: - url: str - pipelines: dict[str, str] - default: str - - @staticmethod - def from_config(values: dict): - jenkins_config = values.get("jenkins") - if not jenkins_config: - raise KeyError("jenkins should be defined in config") - return JenkinsConfig( - url=jenkins_config["url"], - pipelines=jenkins_config["pipelines"], - default=jenkins_config["defaultPipeline"], - ) - - @property - def default_pipeline(self) -> str: - return self.pipelines[self.default] - - -@dataclass(frozen=True) -class Pipeline: - target: Target - tag: str - url: str - pipeline_name: str - body: str - jenkins_config: JenkinsConfig - - def _to_path(self): - return f"PR-{self.tag}" if self.target == Target.PULL_REQUEST else self.tag - - def pipeline_location(self) -> str: - return f'{self.jenkins_config.url}job/{self.jenkins_config.pipelines[self.pipeline_name].replace(" ", "%20")}/' - - def job_location(self) -> str: - return f"{self.pipeline_location}job/{self._to_path()}/" - - def job_name(self) -> str: - return f"{self.jenkins_config.pipelines[self.pipeline_name]}/{self._to_path()}" - - def build_location(self) -> str: - return f"{self.pipeline_location()}view/change-requests/job/{self._to_path()}/lastBuild/" - - def human_readable(self) -> str: - return f"[link={self.url}]#{self.tag}[/link]" diff --git a/src/mpyl/utilities/jenkins/runner.py b/src/mpyl/utilities/jenkins/runner.py deleted file mode 100644 index 497123b91..000000000 --- a/src/mpyl/utilities/jenkins/runner.py +++ /dev/null @@ -1,229 +0,0 @@ -"""Jenkins multi-branch pipeline runner""" -import datetime -import signal -import sys -import time -from dataclasses import dataclass - -import requests -from jenkinsapi.build import Build -from jenkinsapi.constants import STATUS_SUCCESS, STATUS_ABORTED -from jenkinsapi.custom_exceptions import JenkinsAPIException -from jenkinsapi.jenkins import Jenkins -from jenkinsapi.job import Job -from rich.console import Group -from rich.errors import MarkupError -from rich.live import Live -from rich.progress import ( - Progress, - TimeElapsedColumn, - TextColumn, - BarColumn, - TaskProgressColumn, - TimeRemainingColumn, -) -from rich.prompt import Confirm -from rich.status import Status -from rich.table import Column - -from . import Pipeline -from ...cli.commands.build import play_sound, Sound -from ..logging import try_parse_ansi - - -def stream_utf_8_logs(self, interval=0): - """ - Return generator which streams parts of text console. - Workaround for https://github.com/pycontribs/jenkinsapi/pull/843 - """ - url = f"{self.baseurl}/logText/progressiveText" - size = 0 - more_data = True - while more_data: - resp = self.job.jenkins.requester.get_url(url, params={"start": size}) - content = resp.content - if content: - if isinstance(content, str): - yield content - elif isinstance(content, bytes): - yield content.decode(resp.encoding) - else: - raise JenkinsAPIException("Unknown content type for console") - size = resp.headers["X-Text-Size"] - more_data = resp.headers.get("X-More-Data") - time.sleep(interval) - - -Build.stream_utf_8_logs = stream_utf_8_logs - - -@dataclass -class JenkinsRunner: - pipeline: Pipeline - jenkins: Jenkins - status: Status - follow: bool - verbose: bool - - def get_job(self, name: str) -> Job: - try: - return self.jenkins.get_job(name) - except KeyError: - self.status.update( - f"Job for {self.pipeline.human_readable()} not found. This could take a while. " - "Triggering build scan..." - ) - requests.post( - f"{self.pipeline.pipeline_location()}/build?delay=0#", - auth=(self.jenkins.username, self.jenkins.password), - timeout=10, - ) - - while True: - try: - self.jenkins.jobs_container = None # force update of job info - return self.jenkins.get_job(name) - except KeyError: - self.status.update( - f"Waiting for {self.pipeline.human_readable()} to appear..." - ) - time.sleep(1) - - def await_parameter_build(self, build_job: Job): - queue = build_job.invoke() - param_build = queue.block_until_building(delay=3) - self.status.console.log(f"Build in Jenkins {queue.get_build().get_build_url()}") - self.status.update( - "Running initial build to set parameters. This may take a minute.." - ) - while build_job.is_running(): - time.sleep(1) - self.status.console.log("Build parameters retrieved") - - if not param_build.is_good: - self.status.console.log( - f"⚠️ Failed to get parameters: {param_build.get_build_url()}" - ) - sys.exit() - - @staticmethod - def to_icon(build_result: Build) -> str: - status = build_result.get_status() - if status == STATUS_SUCCESS: - return "✅ " - if status == STATUS_ABORTED: - return "🚫 " - return "❌ " - - def follow_logs( - self, - job: Job, - build_number: int, - duration_estimation: int, - verbose: bool = False, - ): - build_to_follow: Build = job.get_build(build_number) - self.status.console.log(f"{build_to_follow} {self.pipeline.build_location()}") - - self._stream_logs(build_to_follow, duration_estimation, verbose) - - build_to_follow.block_until_complete() - finished_build = job.get_last_build() - self.status.console.log( - f"[link={finished_build.get_build_url()}][i]Build[/link] for {self.pipeline.human_readable()} " - f"ended with outcome {self.to_icon(finished_build)}", - markup=True, - ) - self.status.console.log() - - play_sound(Sound.SUCCESS if finished_build.is_good() else Sound.FAILURE) - - @staticmethod - def _stream_logs(build_to_follow, duration_estimation, verbose): - progress = Progress( - TimeElapsedColumn(), - BarColumn(bar_width=None), - TaskProgressColumn(), - TimeRemainingColumn(), - ) - log_line = Progress( - TextColumn( - "{task.description}", table_column=Column(overflow="crop", no_wrap=True) - ) - ) - live = Live(Group(log_line, progress) if not verbose else progress) - with live: - build_task_id = progress.add_task( - "", total=duration_estimation, visible=duration_estimation > 0 - ) - start_time = time.time() - label_task_id = log_line.add_task("status") - - def cancel_handler(_sig, _frame): - live.stop() - stop_build = Confirm.ask("Stop build?") - if stop_build: - build_to_follow.stop() - live.start() - else: - sys.exit() - - signal.signal(signal.SIGINT, cancel_handler) - for line in build_to_follow.stream_utf_8_logs(): - elapsed_time = time.time() - start_time - lines = line.rstrip().split("\n") - - try: - text = "".join(lines) - if verbose: - progress.log(try_parse_ansi(text)) - else: - log_line.update(label_task_id, description=text) - except MarkupError: - progress.log("Could not render log line") - progress.update(build_task_id, completed=elapsed_time) - progress.update(build_task_id, completed=duration_estimation) - - def run(self, pipeline_parameters: dict): - job: Job = self.get_job(self.pipeline.job_name()) - if not list(job.get_build_ids()): - self.await_parameter_build(job) - - build = job.get_last_build() - last_build_number = build.get_number() - if job.is_running(): - self.status.console.log( - f"Build {last_build_number} 🏗️ for {self.pipeline.human_readable()} is still running." - ) - self.status.console.log(f"{build.get_build_url()}") - self.follow_logs(job, last_build_number, 0, self.verbose) - - self.status.update("Starting build...") - - last_build = 0 - - self.jenkins.build_job(self.pipeline.job_name(), params=pipeline_parameters) - - if last_build_number > 1: - last_build = build.get_duration().seconds - self.status.console.log( - f"Last build {last_build_number} {self.to_icon(build)} took" - f" {str(datetime.timedelta(seconds=last_build))}" - ) - - new_build_number = last_build_number + 1 - - self.status.update("Waiting for build to start....") - while job.get_last_buildnumber() != new_build_number: - time.sleep(1) - self.status.stop() - - if self.follow: - self.follow_logs(job, new_build_number, last_build, self.verbose) - else: - self.status.console.log( - f"Build {new_build_number} started " - f"for {self.pipeline.human_readable()} at " - f"{job.get_build(new_build_number).get_build_url()}" - ) - self.status.stop() diff --git a/tests/cli/test_resources/build_help_text.txt b/tests/cli/test_resources/build_help_text.txt index 3c7fdf091..495a766ab 100644 --- a/tests/cli/test_resources/build_help_text.txt +++ b/tests/cli/test_resources/build_help_text.txt @@ -12,6 +12,5 @@ Options: Commands: artifacts Commands related to artifacts like build cache and k8s manifests clean Clean all MPyL metadata in `.mpyl` folders - jenkins Run a multi branch pipeline build on Jenkins run Run an MPyL build status The status of the current local branch from MPyL's perspective