mirror of
https://github.com/community-scripts/ProxmoxVE.git
synced 2026-06-16 20:41:19 +02:00
Compare commits
770 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b9a8993984 | |||
| 29c25a0ab8 | |||
| e60c1f31c2 | |||
| f13782704e | |||
| 7ee47be436 | |||
| 868b256603 | |||
| 16bd4f473b | |||
| 77eb109927 | |||
| 55703ab0ec | |||
| 3c42589ff0 | |||
| 0d271f55a6 | |||
| 6762208d66 | |||
| dee66b996e | |||
| 4b20b8dab5 | |||
| a2f987f07b | |||
| 96d828f379 | |||
| 293d4b73a1 | |||
| cfb84ae12d | |||
| f37bf50a47 | |||
| 4a09cac506 | |||
| 5831cc246a | |||
| bcea631c30 | |||
| d9e6e6ea3d | |||
| c48ece67f0 | |||
| 46f163c50c | |||
| 7dbee6cd83 | |||
| 4f97ac2090 | |||
| 054dd68c15 | |||
| 6c1024776d | |||
| d214627ca9 | |||
| d9b7255a0b | |||
| 9c88ef84a0 | |||
| d4b9bc86e8 | |||
| 07ab5dc16e | |||
| 9020fa88b8 | |||
| a5208b5564 | |||
| 9b5aab46bd | |||
| f321651d6b | |||
| bcd9678548 | |||
| a38da170da | |||
| 4cdb2b88f5 | |||
| 94442524f6 | |||
| 07a5b039be | |||
| e3624ee162 | |||
| 8b9b2399ba | |||
| f252ac7427 | |||
| 10acc2f591 | |||
| a2fe78c463 | |||
| 52cf5167c9 | |||
| 39af3f3966 | |||
| 79d2b09f56 | |||
| cc5b052660 | |||
| 914451ba66 | |||
| 956a5cc197 | |||
| 425e6bfd69 | |||
| ccdc4605fa | |||
| 707ba77006 | |||
| 477bd98269 | |||
| 3c9e90fdff | |||
| 5e5b2f6514 | |||
| 49c7e229c3 | |||
| 3518637bc9 | |||
| 2b87a54afb | |||
| fa054db892 | |||
| e5283edead | |||
| 51e8cab5d3 | |||
| 5ede4495f9 | |||
| 173f49a6f6 | |||
| 6851a02bdc | |||
| cd65eaedc0 | |||
| 8012553578 | |||
| da33106e59 | |||
| e4c320f4d1 | |||
| 2ce26925ea | |||
| 2cfd82f2d6 | |||
| c65f19bfc1 | |||
| a289140712 | |||
| a171dea170 | |||
| 8917549436 | |||
| 40f08f3f70 | |||
| 5fd6f67a58 | |||
| 8792b8037b | |||
| b9c115acca | |||
| 3f619e4286 | |||
| 0f37e30f28 | |||
| 34243ff62f | |||
| 131545081c | |||
| f98a64b632 | |||
| 56129f7833 | |||
| 68af0f5b41 | |||
| 0a21262cf1 | |||
| b3a2fbbf98 | |||
| 373b138fe0 | |||
| ed8b35f50b | |||
| eab30076ca | |||
| dc2193f4bb | |||
| 4dbefa70cd | |||
| 96c2032b60 | |||
| 125ff2b27e | |||
| 3382ec22f7 | |||
| 2c0ec7c64a | |||
| 64009bee05 | |||
| ca3f80ed07 | |||
| 0a061c09e7 | |||
| 7d3eb376d4 | |||
| 25b5fc8866 | |||
| 0deeccbce8 | |||
| 78852f6161 | |||
| 26c7ffbbea | |||
| 290df58f03 | |||
| 497591be6c | |||
| 5b11b6cf15 | |||
| bf319655e1 | |||
| 79ccc8ed6b | |||
| 416717eeb1 | |||
| 9bb6480135 | |||
| 34a3322544 | |||
| e280a2d8ba | |||
| f09b8ff9a8 | |||
| a6cb33e431 | |||
| 7099acc119 | |||
| 8f770b4dd2 | |||
| e160b22c81 | |||
| ccd36df35d | |||
| 5296626c57 | |||
| 370d164993 | |||
| 601912340f | |||
| ba3708a351 | |||
| d8bba89af2 | |||
| f8195a0052 | |||
| 3908218829 | |||
| 8532da6cb6 | |||
| bbd9b715e6 | |||
| 5380f72986 | |||
| 28411ecb5f | |||
| 27e051c493 | |||
| f1bc4f1922 | |||
| 4d28f22ed2 | |||
| 5ab98e446f | |||
| 32597584e2 | |||
| 131d521052 | |||
| f679553c0f | |||
| 6131060b19 | |||
| b978bd3499 | |||
| 23f6b8a158 | |||
| e77461942d | |||
| ef65fb396a | |||
| 6410586e2e | |||
| 0c4e5b5a63 | |||
| 354ceef128 | |||
| 1a6dbb0bf8 | |||
| f14eca3bc9 | |||
| d4b4880e0d | |||
| 9dc08aa8c1 | |||
| 06af8cca46 | |||
| 5668ad9a8d | |||
| bd9bae075d | |||
| 7cdb6c8133 | |||
| 6315547e65 | |||
| e9a9bf17ee | |||
| 40b86bef63 | |||
| a43ca27d2f | |||
| ee06ac1819 | |||
| 1a63343a17 | |||
| cd8a6f1de0 | |||
| da64475612 | |||
| a2aea34aa7 | |||
| 839fba1e0c | |||
| 83398645ca | |||
| 06cf2ec50d | |||
| bdc968e86d | |||
| 0b7d64b240 | |||
| e013403db1 | |||
| 465996653a | |||
| 6a7391f430 | |||
| aed34659c9 | |||
| cd4a3e854e | |||
| be46da731a | |||
| 58179050a8 | |||
| 955cb97a3b | |||
| 04e618798e | |||
| 4c358450d8 | |||
| fa238ddbdd | |||
| 0fe653f8de | |||
| 278e8315f3 | |||
| ded4bba04d | |||
| 5b6f8e2674 | |||
| 162cb9b887 | |||
| 5776f3fef5 | |||
| 26377b7a7f | |||
| 151cd6581f | |||
| 69641d322d | |||
| 6608deeb92 | |||
| de7c00e285 | |||
| eb74ba2edb | |||
| 203131d042 | |||
| 44db73c58d | |||
| d074d3f292 | |||
| 65f3a23cff | |||
| 4da4a47eb7 | |||
| cf3d8f902c | |||
| 8c0333151b | |||
| dc355d07bf | |||
| 4e51373669 | |||
| 256020b847 | |||
| 19cd2b3dad | |||
| 9c06910526 | |||
| d3feeb4900 | |||
| 4926d426a8 | |||
| 7fea6cc9eb | |||
| b59ab46000 | |||
| d41fd37f1a | |||
| b065c5e081 | |||
| 1f9c670648 | |||
| fdfb603930 | |||
| 9a05da0b60 | |||
| 38a14454c4 | |||
| c3294436b5 | |||
| 44a4c97a4c | |||
| 8c9477506c | |||
| f7224f3db8 | |||
| 03dd5e7e88 | |||
| 7b5e2f9656 | |||
| 7703edf4b6 | |||
| 32f1956023 | |||
| 49817d14f8 | |||
| d64b9f6878 | |||
| 1fde72e141 | |||
| ceb50e3528 | |||
| 287c60bc08 | |||
| 9764462f06 | |||
| dc7ea8f526 | |||
| 0c8c11f6b4 | |||
| b2bcffbb05 | |||
| 6a91a57cb2 | |||
| 7e5f7a329e | |||
| 80a73c0ec0 | |||
| d9f88aba7f | |||
| 8ed57f08bf | |||
| c6dcd986ce | |||
| a36b2c9be7 | |||
| e04a9dc13e | |||
| c6f2c2b7d0 | |||
| f78c2be766 | |||
| edfa7c8c45 | |||
| f378e76329 | |||
| faf073d3b5 | |||
| 43fc5c27e1 | |||
| 37649c1e0a | |||
| bb5f531761 | |||
| 48b34d4c2e | |||
| 54e13bca94 | |||
| 9aa76e8ea4 | |||
| 219c4e80b0 | |||
| 35cd953ed7 | |||
| f9f21c1b79 | |||
| 62a6122fa6 | |||
| 45953e857a | |||
| d984a5828d | |||
| 8492ca5805 | |||
| 9ec0864d32 | |||
| 6a9081726f | |||
| 514fece0df | |||
| 9c1f80e3c9 | |||
| 4dc5dfb366 | |||
| 4b2cacf78f | |||
| e5c66aa4d2 | |||
| b00ae8c350 | |||
| 7cfa47d138 | |||
| 639dc9efc4 | |||
| 5bf9cfb800 | |||
| 6c7e7ae1af | |||
| a73aefa8fd | |||
| 599e841e1a | |||
| cf5db6b687 | |||
| 26b1adfbcc | |||
| b97f8b9236 | |||
| de2806ca54 | |||
| a28fec825b | |||
| 69aa93a83a | |||
| fcd77d9332 | |||
| 202f1c7e84 | |||
| 274505536f | |||
| 563209cf87 | |||
| 465b4ea2a2 | |||
| d7c9065fc8 | |||
| 5f0914d32c | |||
| bacdd0b99f | |||
| 3a18573a6d | |||
| 8b80ab2534 | |||
| fa4fc95a74 | |||
| 2fa9ae03a1 | |||
| 83859e2219 | |||
| 82abeac9fb | |||
| 8aca89b8dc | |||
| 35953b6d51 | |||
| a80e215262 | |||
| 51468821f9 | |||
| 2c9f6c5305 | |||
| bc43c262a8 | |||
| 0e00444cb9 | |||
| 9d0c174de1 | |||
| 60d1998765 | |||
| 1cdfdea583 | |||
| 878b09f5ec | |||
| c17d376aae | |||
| d80d0fb285 | |||
| 62b4b5f260 | |||
| 56c97cdf80 | |||
| 9ac2eda0bb | |||
| f2266d8f53 | |||
| d6af82ff60 | |||
| d38c5ceb56 | |||
| c5aaf72c9b | |||
| f0b1afca69 | |||
| 3b142e5dc9 | |||
| b8822e9123 | |||
| a6533d2f2c | |||
| b65bd1a8cb | |||
| 2944aa9100 | |||
| afa59595f0 | |||
| ff4a9d423b | |||
| 59d4ab70c3 | |||
| 7ecb1eb305 | |||
| 7076d03ab3 | |||
| c874324f06 | |||
| 0cab1f7f89 | |||
| f7432990cf | |||
| 39e67bc874 | |||
| 4ffa551202 | |||
| 0374da39f7 | |||
| ade578edad | |||
| c33dd2ae39 | |||
| 3a5f4454e6 | |||
| c9d0196fee | |||
| 404463be21 | |||
| 5dc2b090d9 | |||
| 1c216fc582 | |||
| 1e795835fc | |||
| e234f411c7 | |||
| 89025c9f28 | |||
| 3b308af40a | |||
| 1a93de8674 | |||
| ebf755031b | |||
| 131a9d60f1 | |||
| f7a69ac92d | |||
| 8f1c4a27a6 | |||
| 16cc639e1e | |||
| 168894e6a9 | |||
| 2a86c7e54e | |||
| f16db2d515 | |||
| cf56af0834 | |||
| b05fd7889b | |||
| 369f901308 | |||
| 0d47f336b0 | |||
| 15377bb283 | |||
| 6f4cb4e9c9 | |||
| b707d6c05b | |||
| 1b285e9b6f | |||
| 38b664fa85 | |||
| e8b9d40b92 | |||
| 3b3ab1b8f9 | |||
| 6b60624b2d | |||
| df37781e9a | |||
| 2448723d19 | |||
| cfd9a8132b | |||
| 02f5589ff5 | |||
| e68ea29996 | |||
| 79926030ae | |||
| 4fde0c0427 | |||
| 0a81ff53fd | |||
| cd5816b263 | |||
| d18d473583 | |||
| af529716b1 | |||
| 2c950db3ac | |||
| 904f0bdd3c | |||
| de08fc45d4 | |||
| 9e009c1dfd | |||
| 03ca1543d9 | |||
| dd5ddb2b40 | |||
| 34edee92b2 | |||
| 355826a528 | |||
| a4bfe6a8e2 | |||
| 506c729667 | |||
| 9aee7bcbf4 | |||
| 251df84840 | |||
| 5a1053fe08 | |||
| 757acde352 | |||
| 1c7a925b31 | |||
| ce12ac0f71 | |||
| 8d706791ea | |||
| 3edaa3e3f2 | |||
| ad343c78cb | |||
| f4d50cac1a | |||
| 7b1c510b53 | |||
| 0a38dabb59 | |||
| e332d74536 | |||
| c0c34cc4c8 | |||
| a30c5f9ed4 | |||
| 41590d777e | |||
| a04983674a | |||
| 07abb105d0 | |||
| b15e84e2ba | |||
| 2fddbd9c67 | |||
| b6c78b7ff0 | |||
| 1abf0f8b6d | |||
| e05f2d94b4 | |||
| 8b57c42cb4 | |||
| ebaa526560 | |||
| bd6117eb6a | |||
| 26c94d8613 | |||
| 9dddf45a89 | |||
| e3b7f01056 | |||
| 8b387313cf | |||
| 806c68df91 | |||
| 3352c8a63e | |||
| 5c9facd1f1 | |||
| 5be86d4fdf | |||
| 719cbca50f | |||
| d7b0c2f4c6 | |||
| 86280881b4 | |||
| a2c2c0ff09 | |||
| 2b11d05e7d | |||
| 28311987ae | |||
| ae3b3eb3de | |||
| 6217669d66 | |||
| a13b28e714 | |||
| e0c7fa3295 | |||
| f07c463c88 | |||
| 7b7aecef02 | |||
| 24d7b943e9 | |||
| 36f8e1f320 | |||
| 90a8b450ed | |||
| 409c0aad1b | |||
| d3cdf27a77 | |||
| c09ac3fb31 | |||
| e39ce3285f | |||
| d996b5a719 | |||
| 3f445acf9a | |||
| 90bc1ae1e5 | |||
| 83575e5972 | |||
| 6329ad7fa2 | |||
| a450266925 | |||
| 02eaf288bf | |||
| 24fbf24c6d | |||
| 001bd8bf93 | |||
| 03bd701926 | |||
| 61f3e32827 | |||
| a3844707ad | |||
| 91fe10ec4b | |||
| cd21d98854 | |||
| cb7d9037fb | |||
| cd314ddb3f | |||
| 45b9103657 | |||
| 8a6655b7d1 | |||
| 32a4239f28 | |||
| 1fc7368ff9 | |||
| 9d9d763e63 | |||
| 28ae38e502 | |||
| be2e3a4a3a | |||
| 3c02868add | |||
| 07cd4c0c3e | |||
| f11edd21c9 | |||
| 9fc822d936 | |||
| bf1c32ace8 | |||
| 611021ae8c | |||
| 12eb19ae4c | |||
| c8dc0cffe0 | |||
| 95c7628362 | |||
| 50b3c3ae7f | |||
| 752fff3c8f | |||
| 129e221664 | |||
| 21c064464a | |||
| 6317e7a867 | |||
| 739e0aa41e | |||
| a3e147cf20 | |||
| 4e9352572f | |||
| 686657e8ec | |||
| 9b8302cba0 | |||
| 5a6392d95f | |||
| 160c198731 | |||
| b91ec6f7bc | |||
| a7ddc3502b | |||
| 9bf64f60b9 | |||
| 559cfff56a | |||
| b353063720 | |||
| 26b41d74ee | |||
| 812f8ed1c7 | |||
| 75c5aa3d5d | |||
| 12e7cb1777 | |||
| 7f9e1ce4d8 | |||
| d118f101d8 | |||
| 03a44a8c9c | |||
| 08b1398e7b | |||
| dca3fb40a8 | |||
| 37eafa199d | |||
| 6729fa2a87 | |||
| cd6bd154d9 | |||
| 92f2079a79 | |||
| 683231127c | |||
| 7733ac2806 | |||
| 1d83725249 | |||
| 980fa9fbb0 | |||
| 01d6df5903 | |||
| 3fce87b1d0 | |||
| f4a96e8b4d | |||
| 4d163aa8f8 | |||
| ec059f44ad | |||
| 52bed128f0 | |||
| ca409fc06b | |||
| 9503db319c | |||
| d56fa7ab50 | |||
| d4fd89931f | |||
| 5b7d65ce5c | |||
| 7e3d3d2cf4 | |||
| 2714d9fae4 | |||
| 7af8e907e4 | |||
| 0190f4e7f1 | |||
| 87fa14afaf | |||
| 546de16ef6 | |||
| 553925b8cc | |||
| 7fd0b9f35b | |||
| 6b8a606375 | |||
| 9033793a66 | |||
| ccc0ff7a2f | |||
| 218fd9060e | |||
| a48d400da5 | |||
| 208d34d7a6 | |||
| 9578c6fa91 | |||
| a7bcd44ae6 | |||
| 289708cc10 | |||
| 86293fda1b | |||
| cf391086e5 | |||
| bc72ce83ce | |||
| 9eee1a7f95 | |||
| ecd1e29df5 | |||
| b556b5f8c6 | |||
| 0dbee93410 | |||
| 1a7d1da029 | |||
| f6ccf8be5e | |||
| ec81640d67 | |||
| 03a301d736 | |||
| be81d6255e | |||
| c9da2daec2 | |||
| 9015023e8c | |||
| e2a51d4941 | |||
| b4e0bb0686 | |||
| 1109fe4b0d | |||
| a2daf7347f | |||
| 564aaf5a9c | |||
| 2edb231375 | |||
| e395e0d8ff | |||
| f10eef8243 | |||
| 50b2256b1d | |||
| 1bcc12af82 | |||
| 721667eaf3 | |||
| e9ae1bfde1 | |||
| 84a3138e7e | |||
| e79d37b032 | |||
| a47a425214 | |||
| 6c96d992d6 | |||
| c5cbb46743 | |||
| d134fa200c | |||
| 48774489f6 | |||
| 909e290d5e | |||
| 504ce22752 | |||
| 513e58b5d1 | |||
| 8da59d6133 | |||
| 1f6303c918 | |||
| d05305d4c4 | |||
| ed7156b89c | |||
| 4dc7418b3d | |||
| 608b77a662 | |||
| a7b8259022 | |||
| b226c87a00 | |||
| ea296b59f4 | |||
| 6ab9737137 | |||
| 6044637f12 | |||
| 93a53fe16e | |||
| 5cab784bcb | |||
| 585de1ba0c | |||
| c32ca537f1 | |||
| 424575d8c1 | |||
| 782420b4e4 | |||
| 9b8129abd3 | |||
| 1c169fc7e2 | |||
| f985d84952 | |||
| 88397b48dc | |||
| 91b03574e4 | |||
| ca915da8c1 | |||
| 95f2d24f53 | |||
| df9fa394b8 | |||
| 1e1e96b68e | |||
| 13bd09532a | |||
| b78cdb4008 | |||
| 4963385bf9 | |||
| 799f3bf0fb | |||
| 2f6f0880ac | |||
| b56e6f9e52 | |||
| 1c49bab0bc | |||
| 9a2e6551f1 | |||
| 0cfc6c89b2 | |||
| 19bae6935c | |||
| 347e0af359 | |||
| 615fc7d6ce | |||
| 186a03ccb2 | |||
| ddf05a1c2d | |||
| a43ac644da | |||
| 5d59291bb1 | |||
| f553329754 | |||
| 6ece8c4de9 | |||
| 581b332c66 | |||
| 0632f99343 | |||
| fecad57187 | |||
| bb7b612d5f | |||
| 2c22e03774 | |||
| 6ca9569dc3 | |||
| 562ae12972 | |||
| 47cb50e7cd | |||
| a8c1155cac | |||
| f4a141019e | |||
| 2b288ee617 | |||
| a36d0cb20c | |||
| d3efebce67 | |||
| 7a440679f5 | |||
| db2780ff44 | |||
| fdab25b098 | |||
| c3c544d5a4 | |||
| 3c38647055 | |||
| 7e1b2b4f92 | |||
| 145602a8c3 | |||
| 687e778460 | |||
| 1476849f3c | |||
| a2bf10d2f2 | |||
| 9c44055709 | |||
| 7141f89676 | |||
| 9f50496f8b | |||
| 01bbacec22 | |||
| 116253df1a | |||
| 8706cd3783 | |||
| 874d8f300c | |||
| aa54abcf50 | |||
| a37b36520c | |||
| 22d9eece6f | |||
| 518b6778e2 | |||
| 6da3a5f0e2 | |||
| d044dea89e | |||
| 54171b00e0 | |||
| 686b9aab81 | |||
| 4e5a45feb5 | |||
| 5141037504 | |||
| 29f2671e7a | |||
| 192c2d4fc8 | |||
| d34c88344e | |||
| 34928f8f1d | |||
| 759d0aacf0 | |||
| abac42ca13 | |||
| 14655ff6a4 | |||
| 9baed4b50e | |||
| 981c16dec5 | |||
| 8f97a4909d | |||
| ed496277fc | |||
| a2d94d6ebe | |||
| 2495469338 | |||
| 1221720b3b | |||
| 8fd8a6674e | |||
| 2aacb5c26a | |||
| 2a823151a9 | |||
| 9293dfaa82 | |||
| 323222a963 | |||
| 7666519557 | |||
| 43b0347446 | |||
| 55bad2aa40 | |||
| 4d2d6edefe | |||
| e2e7f0722f | |||
| b3c9f6e625 | |||
| ade3bde249 | |||
| 7cb40af4e6 | |||
| ce2b51a1a6 | |||
| 0986f485ee | |||
| cd1e584696 | |||
| cb156b6f85 | |||
| 06a676e6b0 | |||
| 3ac2ceda3d | |||
| 6082537f57 | |||
| bd3fbb3999 | |||
| 7e5e5be161 | |||
| 55c7549c3e | |||
| 4089fed9c9 | |||
| 325668d5c9 | |||
| 63296fc3e7 | |||
| e98fae3c54 | |||
| bf97029f57 | |||
| 5859c06715 | |||
| 9b4fc56de6 | |||
| 3a5244e285 | |||
| 1025715a74 | |||
| ec3b79bb61 | |||
| 37dfb58d29 | |||
| d95073f505 | |||
| b34e773cbb | |||
| 99782d0422 | |||
| 00e4a0a6b8 | |||
| 28b3b45fdb | |||
| eba01133f4 | |||
| 1f04bb5012 | |||
| d480a5c9b7 | |||
| 458402ea41 | |||
| 18cd4d401c | |||
| 91f5c3dfb0 | |||
| 9c604f624c | |||
| d5421486d8 | |||
| 19dabf4970 | |||
| 8aee0efa4d | |||
| 11fdfa549a | |||
| 0fc913478e | |||
| ada387f1a2 | |||
| 4fd80e3e60 | |||
| d19cc5b69c | |||
| 02c174c4a2 | |||
| fb9e8d90a7 | |||
| 501ea61d2e | |||
| 8656c94f6c | |||
| b92d73a63e | |||
| 8b3966cd31 | |||
| 0eb3259c4f | |||
| 453f73abcf | |||
| 030b28855f | |||
| a5fc040deb | |||
| 88264fea10 | |||
| ea633b138d | |||
| 6070e4fcd2 | |||
| 4e89480e8c | |||
| 214b0dbcc1 | |||
| 062a91d178 | |||
| 1f178f17fc | |||
| 77909d343b | |||
| fef659d26d | |||
| ca23d95226 | |||
| fd729f1f16 | |||
| 8044f075cd | |||
| 1d4d3f63d1 | |||
| 5fb70ea12b | |||
| 997e05dfb1 | |||
| b2c0d7646e | |||
| 903e9a7d16 | |||
| 01fe4179a0 | |||
| 8cccdf9fa5 | |||
| a7f815ef06 | |||
| 7790d73c53 | |||
| 8a243d2a2f | |||
| 04eb2ba9d1 | |||
| 4500d413a2 | |||
| da1fe82c71 | |||
| 7fa11aa6b5 | |||
| f06dedd872 | |||
| 18e09c26d9 | |||
| 209f92bf0f | |||
| a17ba89e7b | |||
| 08ee4699df | |||
| a49d9c5713 | |||
| 18fd0f2393 | |||
| 9b35339cbe | |||
| a9c2307b0e | |||
| 0e809c6ee9 | |||
| 64d000b73a | |||
| 65353d01e1 | |||
| 683be87e9e | |||
| 5894734857 | |||
| c881811499 |
+6
-12
@@ -4,35 +4,29 @@
|
||||
*.sh linguist-detectable=true
|
||||
*.bash linguist-language=Shell
|
||||
*.func linguist-language=Shell
|
||||
*.func linguist-detectable=true
|
||||
*.install linguist-language=Shell
|
||||
|
||||
# ---------------------------------------
|
||||
# Treat Golang files as Go (for /api/)
|
||||
api/**/*.go linguist-language=Go
|
||||
|
||||
# Exclude header art from stats
|
||||
# ---------------------------------------
|
||||
# Treat frontend as JavaScript/TypeScript (optional)
|
||||
frontend/**/*.ts linguist-language=TypeScript
|
||||
frontend/**/*.js linguist-language=JavaScript
|
||||
ct/headers/* linguist-documentation
|
||||
|
||||
# ---------------------------------------
|
||||
# Exclude documentation from stats
|
||||
# ---------------------------------------
|
||||
*.md linguist-documentation
|
||||
docs/** linguist-documentation
|
||||
README.md linguist-documentation
|
||||
CONTRIBUTING.md linguist-documentation
|
||||
SECURITY.md linguist-documentation
|
||||
|
||||
# ---------------------------------------
|
||||
# Exclude generated/config files
|
||||
*.json linguist-generated
|
||||
frontend/public/json/*.json linguist-generated=false
|
||||
*.lock linguist-generated
|
||||
*.yml linguist-generated
|
||||
*.yaml linguist-generated
|
||||
# ---------------------------------------
|
||||
.github/** linguist-generated
|
||||
.vscode/** linguist-generated
|
||||
|
||||
# ---------------------------------------
|
||||
# Standard text handling
|
||||
# ---------------------------------------
|
||||
* text=auto eol=lf
|
||||
|
||||
Generated
-3
@@ -12,6 +12,3 @@
|
||||
|
||||
# Set default reviewers
|
||||
* @community-scripts/Contributor
|
||||
|
||||
# All changes in frontend
|
||||
/frontend/ @community-scripts/Frontend-Dev
|
||||
|
||||
+106
-37
@@ -1,39 +1,108 @@
|
||||
title: "[Script request]: "
|
||||
labels: ["enhancement"]
|
||||
labels:
|
||||
- enhancement
|
||||
|
||||
body:
|
||||
- type: input
|
||||
attributes:
|
||||
label: Application Name
|
||||
description: Enter the application name.
|
||||
placeholder: "e.g., Home Assistant"
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
attributes:
|
||||
label: Website
|
||||
description: Official website or github page.
|
||||
placeholder: "e.g., https://www.home-assistant.io/"
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Description
|
||||
description: Explain what the application does and why it should be added to Proxmox VE Helper-Scripts.
|
||||
placeholder: "e.g., Home Assistant is a popular open-source platform that brings all your smart home devices together in one place. Adding it to Proxmox VE Helper-Scripts would make setup and management on Proxmox easy, letting users quickly get a powerful, self-hosted smart home system up and running."
|
||||
validations:
|
||||
required: true
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Due Diligence
|
||||
options:
|
||||
- label: "I have searched existing [scripts](https://community-scripts.github.io/Proxmox/scripts) and found no duplicates."
|
||||
required: true
|
||||
- label: "I have searched existing [discussions](https://github.com/community-scripts/ProxmoxVE/discussions?discussions_q=) and found no duplicate requests."
|
||||
required: true
|
||||
- label: "The application requested has 600+ stars on Github (if applicable), is older than 6 months, actively maintained and has release tarballs published."
|
||||
required: true
|
||||
- label: "I understand that not all applications will be accepted due to various reasons and criteria by the community-scripts ORG."
|
||||
required: true
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: "Thanks for submitting your request! The team will review it and reach out if we need more information."
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for suggesting a new script for Proxmox VE Helper-Scripts.
|
||||
|
||||
Please make sure the requested application fits the scope of this project.
|
||||
Requests may be closed if the application is out of scope, abandoned, too new, not publicly verifiable, or not suitable for a reliable Proxmox VE Helper-Scripts integration.
|
||||
|
||||
General requirements:
|
||||
- The application should be self-hosted.
|
||||
- The project should have an official public source repository.
|
||||
- The project should provide official releases, tags, or release tarballs.
|
||||
- The project should be actively maintained.
|
||||
- The project should generally have at least 1,000 stars or a comparable public adoption signal.
|
||||
- The latest official release or tag should not be older than 6 months.
|
||||
- The project itself should be at least 6 months old.
|
||||
|
||||
- type: input
|
||||
id: application-name
|
||||
attributes:
|
||||
label: Application Name
|
||||
description: Enter the official application name.
|
||||
placeholder: "e.g., Home Assistant"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: official-website
|
||||
attributes:
|
||||
label: Official Website
|
||||
description: Enter the official website, documentation page, or project homepage.
|
||||
placeholder: "e.g., https://www.home-assistant.io/"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: source-repository
|
||||
attributes:
|
||||
label: Source Repository
|
||||
description: Enter the official GitHub, GitLab, Forgejo, or other public source repository URL.
|
||||
placeholder: "e.g., https://github.com/home-assistant/core"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: app-description
|
||||
attributes:
|
||||
label: Description
|
||||
description: Explain what the application does.
|
||||
placeholder: |
|
||||
Example:
|
||||
Home Assistant is an open-source platform for managing smart home devices.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: reason
|
||||
attributes:
|
||||
label: Why should this be added?
|
||||
description: Explain why this application would be useful for Proxmox VE Helper-Scripts users.
|
||||
placeholder: |
|
||||
Example:
|
||||
It is a popular self-hosted application and would be useful for users who want to run it easily in a Proxmox LXC or VM.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: installation-notes
|
||||
attributes:
|
||||
label: Installation Notes
|
||||
description: Add any relevant installation details, dependencies, ports, databases, services, or known limitations.
|
||||
placeholder: |
|
||||
Example:
|
||||
- Requires PostgreSQL
|
||||
- Uses port 8123 by default
|
||||
- Runs as a systemd service
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: checkboxes
|
||||
id: due-diligence
|
||||
attributes:
|
||||
label: Due Diligence
|
||||
description: Please confirm the following before submitting your request.
|
||||
options:
|
||||
- label: I have searched existing scripts and found no duplicate.
|
||||
required: true
|
||||
- label: I have searched existing discussions and found no duplicate request.
|
||||
required: true
|
||||
- label: The application has an official public source repository.
|
||||
required: true
|
||||
- label: The application is self-hosted and suitable for Proxmox VE Helper-Scripts.
|
||||
required: true
|
||||
- label: The application appears to be actively maintained and provides official releases, tags, or release tarballs.
|
||||
required: true
|
||||
- label: I understand that requests outside the project scope may be closed without an extensive explanation.
|
||||
required: true
|
||||
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for submitting your request.
|
||||
The team will review it and may ask for more information if needed.
|
||||
|
||||
Generated
+12
@@ -79,6 +79,18 @@ body:
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: dropdown
|
||||
id: host_arm64
|
||||
attributes:
|
||||
label: 🧱 Is this Proxmox host running arm64?
|
||||
description: "Run `dpkg --print-architecture` on your Proxmox host if unsure."
|
||||
options:
|
||||
- ""
|
||||
- "No"
|
||||
- "Yes"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: pve_version
|
||||
attributes:
|
||||
|
||||
Generated
+393
@@ -1,3 +1,396 @@
|
||||
## 2026-04-30
|
||||
|
||||
### 🆕 New Scripts
|
||||
|
||||
- Nagios ([#14126](https://github.com/community-scripts/ProxmoxVE/pull/14126))
|
||||
- Neko ([#14121](https://github.com/community-scripts/ProxmoxVE/pull/14121))
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- alpine-docker: install openssl as core dependency | alpine-komodo: check & install openssl if missing [@MickLesk](https://github.com/MickLesk) ([#14134](https://github.com/community-scripts/ProxmoxVE/pull/14134))
|
||||
- endurain: update source references to Codeberg [@MickLesk](https://github.com/MickLesk) ([#14128](https://github.com/community-scripts/ProxmoxVE/pull/14128))
|
||||
|
||||
### 💾 Core
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- tools.func: Manage minor versions for MongoDB 8.x [@tremor021](https://github.com/tremor021) ([#14131](https://github.com/community-scripts/ProxmoxVE/pull/14131))
|
||||
|
||||
## 2026-04-29
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- GrayLog: MongoDB update to 8.2.x [@tremor021](https://github.com/tremor021) ([#14114](https://github.com/community-scripts/ProxmoxVE/pull/14114))
|
||||
- Graylog: Better information in the log file [@tremor021](https://github.com/tremor021) ([#14110](https://github.com/community-scripts/ProxmoxVE/pull/14110))
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- Refactor: checkMK [@MickLesk](https://github.com/MickLesk) ([#14105](https://github.com/community-scripts/ProxmoxVE/pull/14105))
|
||||
- PatchMon: Unpin release [@tremor021](https://github.com/tremor021) ([#14097](https://github.com/community-scripts/ProxmoxVE/pull/14097))
|
||||
|
||||
### 💾 Core
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- core: add guidance when storage lacks rootdir support [@MickLesk](https://github.com/MickLesk) ([#14108](https://github.com/community-scripts/ProxmoxVE/pull/14108))
|
||||
|
||||
## 2026-04-28
|
||||
|
||||
### 🆕 New Scripts
|
||||
|
||||
- StoryBook ([#14081](https://github.com/community-scripts/ProxmoxVE/pull/14081))
|
||||
- CoreDNS ([#14082](https://github.com/community-scripts/ProxmoxVE/pull/14082))
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- Fix Dawarich Install/Update [@Jerry1098](https://github.com/Jerry1098) ([#14078](https://github.com/community-scripts/ProxmoxVE/pull/14078))
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- PatchMon Version 2.0.2 Script update [@9technologygroup](https://github.com/9technologygroup) ([#14095](https://github.com/community-scripts/ProxmoxVE/pull/14095))
|
||||
|
||||
## 2026-04-27
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- Add pamUsername column to userOrgs table [@JVKeller](https://github.com/JVKeller) ([#14075](https://github.com/community-scripts/ProxmoxVE/pull/14075))
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- Dawarich: run db:migrate before assets:precompile [@MickLesk](https://github.com/MickLesk) ([#14051](https://github.com/community-scripts/ProxmoxVE/pull/14051))
|
||||
- TechnitiumDNS: always install .NET 10 if not already present [@MickLesk](https://github.com/MickLesk) ([#14049](https://github.com/community-scripts/ProxmoxVE/pull/14049))
|
||||
|
||||
- #### 💥 Breaking Changes
|
||||
|
||||
- PatchMon: v2.0.0 migration [@vhsdream](https://github.com/vhsdream) ([#14015](https://github.com/community-scripts/ProxmoxVE/pull/14015))
|
||||
|
||||
### 💾 Core
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- Update build.func - fixed spelling mistake [@m1ckywill](https://github.com/m1ckywill) ([#14047](https://github.com/community-scripts/ProxmoxVE/pull/14047))
|
||||
|
||||
### 🧰 Tools
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- update-lxcs/apps: avoid pct exec on containers mid-shutdown [@MickLesk](https://github.com/MickLesk) ([#14050](https://github.com/community-scripts/ProxmoxVE/pull/14050))
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- Add patchmon-agent report execution in update script [@heinemannj](https://github.com/heinemannj) ([#14054](https://github.com/community-scripts/ProxmoxVE/pull/14054))
|
||||
|
||||
## 2026-04-26
|
||||
|
||||
### 🆕 New Scripts
|
||||
|
||||
- TREK ([#14017](https://github.com/community-scripts/ProxmoxVE/pull/14017))
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- fix(2fauth): handle stale backup directory on update [@omertahaoztop](https://github.com/omertahaoztop) ([#14018](https://github.com/community-scripts/ProxmoxVE/pull/14018))
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- Increase Frigate default CPU cores from 4 to 8 [@MickLesk](https://github.com/MickLesk) ([#14039](https://github.com/community-scripts/ProxmoxVE/pull/14039))
|
||||
- Technitium DNS: Ensure directories exist before running service [@tremor021](https://github.com/tremor021) ([#14030](https://github.com/community-scripts/ProxmoxVE/pull/14030))
|
||||
|
||||
### 💾 Core
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- core: Correct deb822 repository flat path detection [@MickLesk](https://github.com/MickLesk) ([#14037](https://github.com/community-scripts/ProxmoxVE/pull/14037))
|
||||
|
||||
## 2026-04-25
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- VictoriaMetrics: Stop vmagent/vmalert before update [@irishpadres](https://github.com/irishpadres) ([#14016](https://github.com/community-scripts/ProxmoxVE/pull/14016))
|
||||
- Domain-Monitor: start apache2 after stop instead of reload [@omertahaoztop](https://github.com/omertahaoztop) ([#14019](https://github.com/community-scripts/ProxmoxVE/pull/14019))
|
||||
- Transmute: Fix ffmpeg detection [@tremor021](https://github.com/tremor021) ([#14008](https://github.com/community-scripts/ProxmoxVE/pull/14008))
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- Refactor: Technitium DNS [@tremor021](https://github.com/tremor021) ([#14013](https://github.com/community-scripts/ProxmoxVE/pull/14013))
|
||||
|
||||
## 2026-04-24
|
||||
|
||||
### 🆕 New Scripts
|
||||
|
||||
- Apprise-API ([#13934](https://github.com/community-scripts/ProxmoxVE/pull/13934))
|
||||
- fireshare ([#13995](https://github.com/community-scripts/ProxmoxVE/pull/13995))
|
||||
- Transmute ([#13935](https://github.com/community-scripts/ProxmoxVE/pull/13935))
|
||||
- Jitsi-Meet ([#13897](https://github.com/community-scripts/ProxmoxVE/pull/13897))
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- Update wger.sh [@Soppster1029](https://github.com/Soppster1029) ([#13977](https://github.com/community-scripts/ProxmoxVE/pull/13977))
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- Refactor: Ghostfolio [@MickLesk](https://github.com/MickLesk) ([#13990](https://github.com/community-scripts/ProxmoxVE/pull/13990))
|
||||
|
||||
## 2026-04-23
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- mealie: start.sh missing after failed update [@MickLesk](https://github.com/MickLesk) ([#13958](https://github.com/community-scripts/ProxmoxVE/pull/13958))
|
||||
- twingate-connector: perform real apt upgrade during update flow [@MickLesk](https://github.com/MickLesk) ([#13959](https://github.com/community-scripts/ProxmoxVE/pull/13959))
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- core: auto-size NODE_OPTIONS heap [@MickLesk](https://github.com/MickLesk) ([#13960](https://github.com/community-scripts/ProxmoxVE/pull/13960))
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- Update scripts to match standard [@tremor021](https://github.com/tremor021) ([#13956](https://github.com/community-scripts/ProxmoxVE/pull/13956))
|
||||
|
||||
### 💾 Core
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- tools.func: upgrade Node.js minor/patch on same major version [@MickLesk](https://github.com/MickLesk) ([#13957](https://github.com/community-scripts/ProxmoxVE/pull/13957))
|
||||
- core: hotfix - prefer silent mode on PHS env conflict [@MickLesk](https://github.com/MickLesk) ([#13951](https://github.com/community-scripts/ProxmoxVE/pull/13951))
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- core: improve system update information / lxc stack upgrade [@MickLesk](https://github.com/MickLesk) ([#13970](https://github.com/community-scripts/ProxmoxVE/pull/13970))
|
||||
|
||||
## 2026-04-22
|
||||
|
||||
### 🆕 New Scripts
|
||||
|
||||
- Dashy ([#13817](https://github.com/community-scripts/ProxmoxVE/pull/13817))
|
||||
- Mini-QR ([#13902](https://github.com/community-scripts/ProxmoxVE/pull/13902))
|
||||
- ownfoil ([#13904](https://github.com/community-scripts/ProxmoxVE/pull/13904))
|
||||
- ERPNext ([#13921](https://github.com/community-scripts/ProxmoxVE/pull/13921))
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- add --clear to uv venv in update_script() to prevent interactive prompt [@MickLesk](https://github.com/MickLesk) ([#13926](https://github.com/community-scripts/ProxmoxVE/pull/13926))
|
||||
|
||||
### 💾 Core
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- core: Add PHS_VERBOSE env var to skip verbose mode prompts [@gormanity](https://github.com/gormanity) ([#13797](https://github.com/community-scripts/ProxmoxVE/pull/13797))
|
||||
|
||||
## 2026-04-21
|
||||
|
||||
### 🆕 New Scripts
|
||||
|
||||
- gogs ([#13896](https://github.com/community-scripts/ProxmoxVE/pull/13896))
|
||||
- anchor ([#13895](https://github.com/community-scripts/ProxmoxVE/pull/13895))
|
||||
- minthcm ([#13903](https://github.com/community-scripts/ProxmoxVE/pull/13903))
|
||||
- foldergram ([#13900](https://github.com/community-scripts/ProxmoxVE/pull/13900))
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- OpenCloud: Pin version to 6.1.0 [@vhsdream](https://github.com/vhsdream) ([#13890](https://github.com/community-scripts/ProxmoxVE/pull/13890))
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- Domain-Locker: Update dependencies [@tremor021](https://github.com/tremor021) ([#13901](https://github.com/community-scripts/ProxmoxVE/pull/13901))
|
||||
- homelable: fix install failure by correcting password-reset chmod target [@Copilot](https://github.com/Copilot) ([#13894](https://github.com/community-scripts/ProxmoxVE/pull/13894))
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- FileFlows: Update dependencies [@tremor021](https://github.com/tremor021) ([#13917](https://github.com/community-scripts/ProxmoxVE/pull/13917))
|
||||
|
||||
## 2026-04-20
|
||||
|
||||
### 🆕 New Scripts
|
||||
|
||||
- WhoDB ([#13880](https://github.com/community-scripts/ProxmoxVE/pull/13880))
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- pangolin: create migration tables before data transfer to prevent role loss [@MickLesk](https://github.com/MickLesk) ([#13874](https://github.com/community-scripts/ProxmoxVE/pull/13874))
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- Pangolin: pre-apply schema migrations to prevent data loss [@MickLesk](https://github.com/MickLesk) ([#13861](https://github.com/community-scripts/ProxmoxVE/pull/13861))
|
||||
- ActualBudget: change migration messages to warnings [@MickLesk](https://github.com/MickLesk) ([#13860](https://github.com/community-scripts/ProxmoxVE/pull/13860))
|
||||
- slskd: migrate config keys for 0.25.0 breaking change [@MickLesk](https://github.com/MickLesk) ([#13862](https://github.com/community-scripts/ProxmoxVE/pull/13862))
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- Wanderer: add pocketbase CLI wrapper with env [@MickLesk](https://github.com/MickLesk) ([#13863](https://github.com/community-scripts/ProxmoxVE/pull/13863))
|
||||
- feat(homelable): add password reset utility script [@davidsoncabista](https://github.com/davidsoncabista) ([#13798](https://github.com/community-scripts/ProxmoxVE/pull/13798))
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- Several Scripts: Bump NodeJS to align Node.js versions with upstream for 5 scripts [@MickLesk](https://github.com/MickLesk) ([#13875](https://github.com/community-scripts/ProxmoxVE/pull/13875))
|
||||
- Refactor: PMG Post Install [@MickLesk](https://github.com/MickLesk) ([#13693](https://github.com/community-scripts/ProxmoxVE/pull/13693))
|
||||
|
||||
### 💾 Core
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- core: detect Perl breakage after LXC stack upgrade and improve storage validation [@MickLesk](https://github.com/MickLesk) ([#13879](https://github.com/community-scripts/ProxmoxVE/pull/13879))
|
||||
|
||||
## 2026-04-19
|
||||
|
||||
### 🆕 New Scripts
|
||||
|
||||
- nametag ([#13849](https://github.com/community-scripts/ProxmoxVE/pull/13849))
|
||||
|
||||
## 2026-04-18
|
||||
|
||||
### 🆕 New Scripts
|
||||
|
||||
- Dagu ([#13830](https://github.com/community-scripts/ProxmoxVE/pull/13830))
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- BabyBuddy: set DJANGO_SETTINGS_MODULE before migrate in update [@MickLesk](https://github.com/MickLesk) ([#13836](https://github.com/community-scripts/ProxmoxVE/pull/13836))
|
||||
- litellm: add prisma generate and use venv binary directly [@MickLesk](https://github.com/MickLesk) ([#13835](https://github.com/community-scripts/ProxmoxVE/pull/13835))
|
||||
- yamtrack: add missing nginx.conf sed edits to update script [@MickLesk](https://github.com/MickLesk) ([#13834](https://github.com/community-scripts/ProxmoxVE/pull/13834))
|
||||
|
||||
### 🧰 Tools
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- SparkyFitness Garmin Microservice: fix update function [@tomfrenzel](https://github.com/tomfrenzel) ([#13824](https://github.com/community-scripts/ProxmoxVE/pull/13824))
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- Clean-Orphan-LVM: check all cluster nodes for VM/CT configs [@MickLesk](https://github.com/MickLesk) ([#13837](https://github.com/community-scripts/ProxmoxVE/pull/13837))
|
||||
|
||||
## 2026-04-17
|
||||
|
||||
### 🆕 New Scripts
|
||||
|
||||
- step-ca ([#13775](https://github.com/community-scripts/ProxmoxVE/pull/13775))
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- core: pin IGC version to compute-runtime compatible tag (Intel GPU) [@MickLesk](https://github.com/MickLesk) ([#13814](https://github.com/community-scripts/ProxmoxVE/pull/13814))
|
||||
- Fix for bambuddy community script update [@abbasegbeyemi](https://github.com/abbasegbeyemi) ([#13816](https://github.com/community-scripts/ProxmoxVE/pull/13816))
|
||||
- Umami: Fix update procedure [@tremor021](https://github.com/tremor021) ([#13807](https://github.com/community-scripts/ProxmoxVE/pull/13807))
|
||||
|
||||
### 💾 Core
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- core: sanitize mount_fs input — strip spaces and trailing commas [@MickLesk](https://github.com/MickLesk) ([#13806](https://github.com/community-scripts/ProxmoxVE/pull/13806))
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- core: fix some pct create issues (telemetry) + cleanup [@MickLesk](https://github.com/MickLesk) ([#13810](https://github.com/community-scripts/ProxmoxVE/pull/13810))
|
||||
|
||||
## 2026-04-16
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- Add pnpm as a dependency to ghost-cli install [@YourFavoriteKyle](https://github.com/YourFavoriteKyle) ([#13789](https://github.com/community-scripts/ProxmoxVE/pull/13789))
|
||||
|
||||
### 💾 Core
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- core: wire ENABLE_MKNOD and ALLOW_MOUNT_FS into LXC features [@MickLesk](https://github.com/MickLesk) ([#13796](https://github.com/community-scripts/ProxmoxVE/pull/13796))
|
||||
|
||||
## 2026-04-15
|
||||
|
||||
### 🆕 New Scripts
|
||||
|
||||
- iGotify ([#13773](https://github.com/community-scripts/ProxmoxVE/pull/13773))
|
||||
- GitHub-Runner ([#13709](https://github.com/community-scripts/ProxmoxVE/pull/13709))
|
||||
- Revert "Remove low-install-count CT scripts and installers (#13570)" [@CrazyWolf13](https://github.com/CrazyWolf13) ([#13752](https://github.com/community-scripts/ProxmoxVE/pull/13752))
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- [alpine-nextcloud] Update Nginx MIME types to support .mjs files [@GuiltyFox](https://github.com/GuiltyFox) ([#13771](https://github.com/community-scripts/ProxmoxVE/pull/13771))
|
||||
- Domain Monitor: Fix file ownership after update [@tremor021](https://github.com/tremor021) ([#13759](https://github.com/community-scripts/ProxmoxVE/pull/13759))
|
||||
|
||||
- #### 💥 Breaking Changes
|
||||
|
||||
- Reitti: refactor scripts for v4 - remove RabbitMQ and Photon [@MickLesk](https://github.com/MickLesk) ([#13728](https://github.com/community-scripts/ProxmoxVE/pull/13728))
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- Semaphore: add BoltDB to SQLite migration [@tremor021](https://github.com/tremor021) ([#13779](https://github.com/community-scripts/ProxmoxVE/pull/13779))
|
||||
|
||||
### 📚 Documentation
|
||||
|
||||
- cleanup: remove docs/, update README & CONTRIBUTING, fix repo config [@MickLesk](https://github.com/MickLesk) ([#13770](https://github.com/community-scripts/ProxmoxVE/pull/13770))
|
||||
|
||||
## 2026-04-14
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- Immich: Pin photo-processing library revisions [@vhsdream](https://github.com/vhsdream) ([#13748](https://github.com/community-scripts/ProxmoxVE/pull/13748))
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- BentoPDF: Nginx fixes [@tremor021](https://github.com/tremor021) ([#13741](https://github.com/community-scripts/ProxmoxVE/pull/13741))
|
||||
- Zerobyte: add git to dependencies to fix bun install failure [@Copilot](https://github.com/Copilot) ([#13721](https://github.com/community-scripts/ProxmoxVE/pull/13721))
|
||||
- alpine-nextcloud-install: do not use deprecated nginx config [@AlexanderStein](https://github.com/AlexanderStein) ([#13726](https://github.com/community-scripts/ProxmoxVE/pull/13726))
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- Mealie: support v3.15+ Nuxt 4 migration [@MickLesk](https://github.com/MickLesk) ([#13731](https://github.com/community-scripts/ProxmoxVE/pull/13731))
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- Lyrion: correct service name and version file in update script [@MickLesk](https://github.com/MickLesk) ([#13734](https://github.com/community-scripts/ProxmoxVE/pull/13734))
|
||||
- Changedetection: move env vars from service file to .env [@tremor021](https://github.com/tremor021) ([#13732](https://github.com/community-scripts/ProxmoxVE/pull/13732))
|
||||
|
||||
## 2026-04-13
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- Slskd: Remove stale Soularr lock file on startup and redirect logs to stderr [@MickLesk](https://github.com/MickLesk) ([#13669](https://github.com/community-scripts/ProxmoxVE/pull/13669))
|
||||
- Bambuddy: preserve database and archive on update [@Copilot](https://github.com/Copilot) ([#13706](https://github.com/community-scripts/ProxmoxVE/pull/13706))
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- Immich: Pin version to 2.7.5 [@vhsdream](https://github.com/vhsdream) ([#13715](https://github.com/community-scripts/ProxmoxVE/pull/13715))
|
||||
- Bytestash: auto backup/restore data on update [@MickLesk](https://github.com/MickLesk) ([#13707](https://github.com/community-scripts/ProxmoxVE/pull/13707))
|
||||
- OpenCloud: pin version to 6.0.0 [@vhsdream](https://github.com/vhsdream) ([#13691](https://github.com/community-scripts/ProxmoxVE/pull/13691))
|
||||
|
||||
- #### 💥 Breaking Changes
|
||||
|
||||
- Mealie: pin version to v3.14.0 in install and update scripts [@Copilot](https://github.com/Copilot) ([#13724](https://github.com/community-scripts/ProxmoxVE/pull/13724))
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- core: remove unused TEMP_DIR mktemp leak in build_container / clean sonarqube [@MickLesk](https://github.com/MickLesk) ([#13708](https://github.com/community-scripts/ProxmoxVE/pull/13708))
|
||||
|
||||
## 2026-04-12
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- Alpine-Wakapi: Remove container checks in update_script function [@MickLesk](https://github.com/MickLesk) ([#13694](https://github.com/community-scripts/ProxmoxVE/pull/13694))
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- IronClaw: Install keychain dependencies and launch in a DBus session [@MickLesk](https://github.com/MickLesk) ([#13692](https://github.com/community-scripts/ProxmoxVE/pull/13692))
|
||||
- MeTube: Allow pnpm build scripts to fix ERR_PNPM_IGNORED_BUILDS [@MickLesk](https://github.com/MickLesk) ([#13668](https://github.com/community-scripts/ProxmoxVE/pull/13668))
|
||||
|
||||
## 2026-04-11
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
Generated
+582
@@ -0,0 +1,582 @@
|
||||
## 2026-05-31
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- Manyfold: regenerate Rails credentials on update to fix encryption mimatch [@MickLesk](https://github.com/MickLesk) ([#14817](https://github.com/community-scripts/ProxmoxVE/pull/14817))
|
||||
- OpenThread-BR: use correct ipv6 configuration [@tomfrenzel](https://github.com/tomfrenzel) ([#14829](https://github.com/community-scripts/ProxmoxVE/pull/14829))
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- Webtrees: use PHP CLI for initial setup instead of curl to setup wizard [@MickLesk](https://github.com/MickLesk) ([#14818](https://github.com/community-scripts/ProxmoxVE/pull/14818))
|
||||
- Kima-Hub: use curl_with_retry for ML model downloads to fix possible timeout issues [@MickLesk](https://github.com/MickLesk) ([#14816](https://github.com/community-scripts/ProxmoxVE/pull/14816))
|
||||
|
||||
### 🧰 Tools
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- PBS4-Upgrade: update current PBS3 packages before switching to Trixie repos [@MickLesk](https://github.com/MickLesk) ([#14815](https://github.com/community-scripts/ProxmoxVE/pull/14815))
|
||||
|
||||
## 2026-05-30
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- Flatnotes: fix empty package name in pyproject.toml [@MickLesk](https://github.com/MickLesk) ([#14814](https://github.com/community-scripts/ProxmoxVE/pull/14814))
|
||||
|
||||
## 2026-05-29
|
||||
|
||||
### 🆕 New Scripts
|
||||
|
||||
- Kan ([#14776](https://github.com/community-scripts/ProxmoxVE/pull/14776))
|
||||
- Dynacat ([#14777](https://github.com/community-scripts/ProxmoxVE/pull/14777))
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- Fix lobehub docker path [@dannyyy](https://github.com/dannyyy) ([#14793](https://github.com/community-scripts/ProxmoxVE/pull/14793))
|
||||
- karakeep: add more hdd space [@MickLesk](https://github.com/MickLesk) ([#14797](https://github.com/community-scripts/ProxmoxVE/pull/14797))
|
||||
- Grist: Revert installation of EE [@tremor021](https://github.com/tremor021) ([#14784](https://github.com/community-scripts/ProxmoxVE/pull/14784))
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- Sure: Remove `$STD` for `systemctl enable -q` [@tremor021](https://github.com/tremor021) ([#14801](https://github.com/community-scripts/ProxmoxVE/pull/14801))
|
||||
|
||||
## 2026-05-28
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- RomM: remove nginx default.conf during installation [@MickLesk](https://github.com/MickLesk) ([#14766](https://github.com/community-scripts/ProxmoxVE/pull/14766))
|
||||
- Open-Archiver: replace pnpm approve-builds --yes with --all [@MickLesk](https://github.com/MickLesk) ([#14765](https://github.com/community-scripts/ProxmoxVE/pull/14765))
|
||||
- fix(hermesagent): set npm_config_yes=true to suppress interactive pro… [@steveonjava](https://github.com/steveonjava) ([#14763](https://github.com/community-scripts/ProxmoxVE/pull/14763))
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- Yamtrack: migrate to uv [@MickLesk](https://github.com/MickLesk) ([#14767](https://github.com/community-scripts/ProxmoxVE/pull/14767))
|
||||
|
||||
### ❔ Uncategorized
|
||||
|
||||
- chore(ct): sync adventurelog defaults with PocketBase [@github-actions[bot]](https://github.com/github-actions[bot]) ([#14772](https://github.com/community-scripts/ProxmoxVE/pull/14772))
|
||||
|
||||
## 2026-05-27
|
||||
|
||||
### 🆕 New Scripts
|
||||
|
||||
- MusicSeerr ([#14746](https://github.com/community-scripts/ProxmoxVE/pull/14746))
|
||||
- Hermes Agent ([#14751](https://github.com/community-scripts/ProxmoxVE/pull/14751))
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- grist: restore install:ee step [@paulfitz](https://github.com/paulfitz) ([#14759](https://github.com/community-scripts/ProxmoxVE/pull/14759))
|
||||
|
||||
### 💾 Core
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- [tools.func]: `setup_gs()` fix getting dotted release format [@tremor021](https://github.com/tremor021) ([#14745](https://github.com/community-scripts/ProxmoxVE/pull/14745))
|
||||
|
||||
## 2026-05-26
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- Add directory creation to Profilarr update script [@ryansully](https://github.com/ryansully) ([#14740](https://github.com/community-scripts/ProxmoxVE/pull/14740))
|
||||
- profilarr: Fix ARCH assignment in profilarr.sh to support Profilarr build usage [@mpeleshenko](https://github.com/mpeleshenko) ([#14709](https://github.com/community-scripts/ProxmoxVE/pull/14709))
|
||||
- Jackett: Remove quotes in Service File [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#14729](https://github.com/community-scripts/ProxmoxVE/pull/14729))
|
||||
- Open-archiver: approve pnpm build scripts and run build:oss without subshell [@MickLesk](https://github.com/MickLesk) ([#14711](https://github.com/community-scripts/ProxmoxVE/pull/14711))
|
||||
- Docuseal: read Ruby version from Gemfile, upgrade on update if needed [@MickLesk](https://github.com/MickLesk) ([#14715](https://github.com/community-scripts/ProxmoxVE/pull/14715))
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- Birdnet-GO: install libonnxruntime.so from release tarball [@MickLesk](https://github.com/MickLesk) ([#14716](https://github.com/community-scripts/ProxmoxVE/pull/14716))
|
||||
|
||||
### 💾 Core
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- tools.func: better error diagnostics, consistent OS detection, setup function ordering [@MickLesk](https://github.com/MickLesk) ([#14692](https://github.com/community-scripts/ProxmoxVE/pull/14692))
|
||||
|
||||
### 🧰 Tools
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- IPTag-Tool: use qm set for VM tags to handle snapshot sections crrectly [@MickLesk](https://github.com/MickLesk) ([#14713](https://github.com/community-scripts/ProxmoxVE/pull/14713))
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- Netdata: extend PVE version support to 9.x [@MickLesk](https://github.com/MickLesk) ([#14714](https://github.com/community-scripts/ProxmoxVE/pull/14714))
|
||||
|
||||
## 2026-05-25
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- karakeep: fix: pip config [@CrazyWolf13](https://github.com/CrazyWolf13) ([#14703](https://github.com/community-scripts/ProxmoxVE/pull/14703))
|
||||
|
||||
### 💾 Core
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- tools.func: replace raw GitHub API curl calls with get_latest_github_release [@MickLesk](https://github.com/MickLesk) ([#14690](https://github.com/community-scripts/ProxmoxVE/pull/14690))
|
||||
|
||||
### 🧰 Tools
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- Kernel-Clean: detect meta-packages and fix silent removal failures [@MickLesk](https://github.com/MickLesk) ([#14674](https://github.com/community-scripts/ProxmoxVE/pull/14674))
|
||||
|
||||
## 2026-05-24
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- RomM: add installation steps for Nginx mod_zip module [@MickLesk](https://github.com/MickLesk) ([#14678](https://github.com/community-scripts/ProxmoxVE/pull/14678))
|
||||
- ISponsorblockTV: detect CPU capabilities to select compatible binary [@MickLesk](https://github.com/MickLesk) ([#14677](https://github.com/community-scripts/ProxmoxVE/pull/14677))
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- Refactor: MQTT [@tremor021](https://github.com/tremor021) ([#14673](https://github.com/community-scripts/ProxmoxVE/pull/14673))
|
||||
|
||||
## 2026-05-23
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- IronClaw: Extra configuration during install to ensure Web Gateway can run [@SystemIdleProcess](https://github.com/SystemIdleProcess) ([#14635](https://github.com/community-scripts/ProxmoxVE/pull/14635))
|
||||
- Tunarr: fix path to backup during update [@SystemIdleProcess](https://github.com/SystemIdleProcess) ([#14655](https://github.com/community-scripts/ProxmoxVE/pull/14655))
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- wealthfolio: add: prebuild [@CrazyWolf13](https://github.com/CrazyWolf13) ([#14658](https://github.com/community-scripts/ProxmoxVE/pull/14658))
|
||||
|
||||
### 🧰 Tools
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- kernel-clean: support range syntax in selection prompt [@djhojd](https://github.com/djhojd) ([#14656](https://github.com/community-scripts/ProxmoxVE/pull/14656))
|
||||
|
||||
## 2026-05-22
|
||||
|
||||
### 🆕 New Scripts
|
||||
|
||||
- bitfocus-companion ([#14603](https://github.com/community-scripts/ProxmoxVE/pull/14603))
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- fix(the-lounge): install Node.js 22 before deb package [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#14648](https://github.com/community-scripts/ProxmoxVE/pull/14648))
|
||||
- Docmost: Fix duplicate STORAGE_DRIVER [@MickLesk](https://github.com/MickLesk) ([#14645](https://github.com/community-scripts/ProxmoxVE/pull/14645))
|
||||
- Profilarr: pin Deno version to v2.7.5 [@MickLesk](https://github.com/MickLesk) ([#14632](https://github.com/community-scripts/ProxmoxVE/pull/14632))
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- add: karakeep cli wrapper [@CrazyWolf13](https://github.com/CrazyWolf13) ([#14618](https://github.com/community-scripts/ProxmoxVE/pull/14618))
|
||||
|
||||
- #### 💥 Breaking Changes
|
||||
|
||||
- OpenCloud: v7.0.0 changes [@vhsdream](https://github.com/vhsdream) ([#14650](https://github.com/community-scripts/ProxmoxVE/pull/14650))
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- workflows: update workflows, templates to support arm64. [@asylumexp](https://github.com/asylumexp) ([#14653](https://github.com/community-scripts/ProxmoxVE/pull/14653))
|
||||
- SoulSync: setup Node v22 and build WebUI [@MickLesk](https://github.com/MickLesk) ([#14639](https://github.com/community-scripts/ProxmoxVE/pull/14639))
|
||||
- Refactor: Dispatcharr [@MickLesk](https://github.com/MickLesk) ([#14313](https://github.com/community-scripts/ProxmoxVE/pull/14313))
|
||||
|
||||
### 💾 Core
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- fix: make LXC banner OS detection dynamic via /etc/os-release [@atahan99](https://github.com/atahan99) ([#14269](https://github.com/community-scripts/ProxmoxVE/pull/14269))
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- core: suppress MOTD for non-interactive shells [@MickLesk](https://github.com/MickLesk) ([#14638](https://github.com/community-scripts/ProxmoxVE/pull/14638))
|
||||
|
||||
## 2026-05-21
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- snowshare: use mv instead of cp for uploads backup to prevent disk fill [@TuroYT](https://github.com/TuroYT) ([#14558](https://github.com/community-scripts/ProxmoxVE/pull/14558))
|
||||
- Technitium DNS: download release before stopping the service on update [@w-gitops](https://github.com/w-gitops) ([#14616](https://github.com/community-scripts/ProxmoxVE/pull/14616))
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- Proxmox VE 9.2 support [@MickLesk](https://github.com/MickLesk) ([#14624](https://github.com/community-scripts/ProxmoxVE/pull/14624))
|
||||
|
||||
## 2026-05-20
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- Update mylar3 to point to new Repo [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#14606](https://github.com/community-scripts/ProxmoxVE/pull/14606))
|
||||
- Ollama: Fix for latest version [@tremor021](https://github.com/tremor021) ([#14596](https://github.com/community-scripts/ProxmoxVE/pull/14596))
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- Profilarr v2: Update and Refactor whole Script [@MickLesk](https://github.com/MickLesk) ([#14584](https://github.com/community-scripts/ProxmoxVE/pull/14584))
|
||||
|
||||
## 2026-05-19
|
||||
|
||||
### 🆕 New Scripts
|
||||
|
||||
- LobeHub ([#14441](https://github.com/community-scripts/ProxmoxVE/pull/14441))
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- Update nodejs Versions [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#14582](https://github.com/community-scripts/ProxmoxVE/pull/14582))
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- ESPConnect: Fix paths to SSL certificates [@tremor021](https://github.com/tremor021) ([#14591](https://github.com/community-scripts/ProxmoxVE/pull/14591))
|
||||
- ReactiveResume: set correct WorkingDirectory for systemd service [@MickLesk](https://github.com/MickLesk) ([#14579](https://github.com/community-scripts/ProxmoxVE/pull/14579))
|
||||
- Sparkyfitness: add missing nginx template variable substitutions [@MickLesk](https://github.com/MickLesk) ([#14578](https://github.com/community-scripts/ProxmoxVE/pull/14578))
|
||||
- Wanderer: include dev dependencies during build [@MickLesk](https://github.com/MickLesk) ([#14577](https://github.com/community-scripts/ProxmoxVE/pull/14577))
|
||||
- Whisparr: switch from nightly to stable GitHub release [@MickLesk](https://github.com/MickLesk) ([#14581](https://github.com/community-scripts/ProxmoxVE/pull/14581))
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- Refactor: SonarQube [@tremor021](https://github.com/tremor021) ([#14594](https://github.com/community-scripts/ProxmoxVE/pull/14594))
|
||||
|
||||
## 2026-05-18
|
||||
|
||||
### 🆕 New Scripts
|
||||
|
||||
- ESPconnect ([#14444](https://github.com/community-scripts/ProxmoxVE/pull/14444))
|
||||
- degoog ([#14533](https://github.com/community-scripts/ProxmoxVE/pull/14533))
|
||||
- Webtrees ([#14532](https://github.com/community-scripts/ProxmoxVE/pull/14532))
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- Bichon: Support v1 migration [@tomfrenzel](https://github.com/tomfrenzel) ([#14524](https://github.com/community-scripts/ProxmoxVE/pull/14524))
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- Pangolin: bump to 1.18.4, fix missing statusHistory migration [@MickLesk](https://github.com/MickLesk) ([#14566](https://github.com/community-scripts/ProxmoxVE/pull/14566))
|
||||
|
||||
## 2026-05-17
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- dashy: fix yarn-missing on update and back up full user-data [@lissy93](https://github.com/lissy93) ([#14548](https://github.com/community-scripts/ProxmoxVE/pull/14548))
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- tools.func: replace max-time with speed-limit stall detection in curl_download [@MickLesk](https://github.com/MickLesk) ([#14545](https://github.com/community-scripts/ProxmoxVE/pull/14545))
|
||||
|
||||
## 2026-05-16
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- Homelable: replace passlib with bcrypt for password hashing [@MickLesk](https://github.com/MickLesk) ([#14530](https://github.com/community-scripts/ProxmoxVE/pull/14530))
|
||||
- dashy: fix: restore [@CrazyWolf13](https://github.com/CrazyWolf13) ([#14527](https://github.com/community-scripts/ProxmoxVE/pull/14527))
|
||||
- Update Tinyauth source URL in installation script [@MehrunesSky](https://github.com/MehrunesSky) ([#14483](https://github.com/community-scripts/ProxmoxVE/pull/14483))
|
||||
- Excalidraw: Fix build [@tremor021](https://github.com/tremor021) ([#14509](https://github.com/community-scripts/ProxmoxVE/pull/14509))
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- Update authentik version to 2026.2.3 [@thieneret](https://github.com/thieneret) ([#14517](https://github.com/community-scripts/ProxmoxVE/pull/14517))
|
||||
|
||||
## 2026-05-15
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- OPNsense: replace undefined msg_warn with inline echo in alloc retry [@MickLesk](https://github.com/MickLesk) ([#14500](https://github.com/community-scripts/ProxmoxVE/pull/14500))
|
||||
- Checkmk: detect OMD version suffix dynamically on update [@MickLesk](https://github.com/MickLesk) ([#14496](https://github.com/community-scripts/ProxmoxVE/pull/14496))
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- SearXNG: enable JSON format by default for API integrations [@MickLesk](https://github.com/MickLesk) ([#14498](https://github.com/community-scripts/ProxmoxVE/pull/14498))
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- Refactor: Ollama use tools.func [@MickLesk](https://github.com/MickLesk) ([#14501](https://github.com/community-scripts/ProxmoxVE/pull/14501))
|
||||
|
||||
### 💾 Core
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- core: fall back to silent mode when no TTY or whiptail unavailable [@MickLesk](https://github.com/MickLesk) ([#14497](https://github.com/community-scripts/ProxmoxVE/pull/14497))
|
||||
|
||||
## 2026-05-14
|
||||
|
||||
### 🆕 New Scripts
|
||||
|
||||
- CLIProxyAPI ([#14443](https://github.com/community-scripts/ProxmoxVE/pull/14443))
|
||||
|
||||
## 2026-05-13
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- Fix: Broken Manifold update [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#14468](https://github.com/community-scripts/ProxmoxVE/pull/14468))
|
||||
- SoulSync: Fix update function [@tremor021](https://github.com/tremor021) ([#14465](https://github.com/community-scripts/ProxmoxVE/pull/14465))
|
||||
- Reactive-Resume: fix PDF generation timeout in LXC containers [@MickLesk](https://github.com/MickLesk) ([#14416](https://github.com/community-scripts/ProxmoxVE/pull/14416))
|
||||
- (calibre-web) Add --no-sandbox for PDF conversion [@jamesmyatt](https://github.com/jamesmyatt) ([#14461](https://github.com/community-scripts/ProxmoxVE/pull/14461))
|
||||
|
||||
### 💾 Core
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- tools.func: encode GitHub tag, refine pin logic, add Codeberg [@MickLesk](https://github.com/MickLesk) ([#14473](https://github.com/community-scripts/ProxmoxVE/pull/14473))
|
||||
|
||||
## 2026-05-12
|
||||
|
||||
### 🆕 New Scripts
|
||||
|
||||
- DocuSeal ([#14445](https://github.com/community-scripts/ProxmoxVE/pull/14445))
|
||||
- Authentik ([#14440](https://github.com/community-scripts/ProxmoxVE/pull/14440))
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- Save Omada version [@lucacome](https://github.com/lucacome) ([#14433](https://github.com/community-scripts/ProxmoxVE/pull/14433))
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- OpenCloud: bump version to 6.2.0 [@vhsdream](https://github.com/vhsdream) ([#14451](https://github.com/community-scripts/ProxmoxVE/pull/14451))
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- misc: bump node versions [@CrazyWolf13](https://github.com/CrazyWolf13) ([#14447](https://github.com/community-scripts/ProxmoxVE/pull/14447))
|
||||
|
||||
## 2026-05-11
|
||||
|
||||
### 🆕 New Scripts
|
||||
|
||||
- Lychee ([#14424](https://github.com/community-scripts/ProxmoxVE/pull/14424))
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- Termix: fix nginx pid path and log paths on update (#) [@MickLesk](https://github.com/MickLesk) ([#14419](https://github.com/community-scripts/ProxmoxVE/pull/14419))
|
||||
- Nginxproxymanager: restore NPM nginx.conf after OpenResty rebuid [@MickLesk](https://github.com/MickLesk) ([#14421](https://github.com/community-scripts/ProxmoxVE/pull/14421))
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- InvestBrain: add commented reverse proxy config hints to .env [@MickLesk](https://github.com/MickLesk) ([#14422](https://github.com/community-scripts/ProxmoxVE/pull/14422))
|
||||
|
||||
### 🧰 Tools
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- Cronmaster: fix unexpected EOF in update_cronmaster script [@MickLesk](https://github.com/MickLesk) ([#14420](https://github.com/community-scripts/ProxmoxVE/pull/14420))
|
||||
|
||||
## 2026-05-10
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- Save Beszel version [@lucacome](https://github.com/lucacome) ([#14389](https://github.com/community-scripts/ProxmoxVE/pull/14389))
|
||||
- karakeep: Fix SERVER_VERSION update [@MickLesk](https://github.com/MickLesk) ([#14378](https://github.com/community-scripts/ProxmoxVE/pull/14378))
|
||||
- inspIRCd: Fix service not autostarting [@tremor021](https://github.com/tremor021) ([#14368](https://github.com/community-scripts/ProxmoxVE/pull/14368))
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- refactor: webcheck [@CrazyWolf13](https://github.com/CrazyWolf13) ([#14391](https://github.com/community-scripts/ProxmoxVE/pull/14391))
|
||||
|
||||
### 💾 Core
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- [tools.func]: Pin `pnpm` version [@tremor021](https://github.com/tremor021) ([#14386](https://github.com/community-scripts/ProxmoxVE/pull/14386))
|
||||
|
||||
## 2026-05-09
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- FlowiseAI: Migrate to pnpm [@MickLesk](https://github.com/MickLesk) ([#14344](https://github.com/community-scripts/ProxmoxVE/pull/14344))
|
||||
- Purge openresty [@lucacome](https://github.com/lucacome) ([#14353](https://github.com/community-scripts/ProxmoxVE/pull/14353))
|
||||
- Check for release for Sonarr [@lucacome](https://github.com/lucacome) ([#14354](https://github.com/community-scripts/ProxmoxVE/pull/14354))
|
||||
- fix(termix-install.sh): add tmpfiles.d persistence and systemd PIDFile path [@runnylogan](https://github.com/runnylogan) ([#14350](https://github.com/community-scripts/ProxmoxVE/pull/14350))
|
||||
- ERPNext: start bench Redis services before bench new-site [@MickLesk](https://github.com/MickLesk) ([#14343](https://github.com/community-scripts/ProxmoxVE/pull/14343))
|
||||
- [Hotfix]Jotty: use absolute path when creating data dir [@vhsdream](https://github.com/vhsdream) ([#14355](https://github.com/community-scripts/ProxmoxVE/pull/14355))
|
||||
|
||||
## 2026-05-08
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- wishlist: pin pnpm to v10 to match engine requirements [@MickLesk](https://github.com/MickLesk) ([#14342](https://github.com/community-scripts/ProxmoxVE/pull/14342))
|
||||
- [pelican] fix env copy regression [@LetterN](https://github.com/LetterN) ([#14328](https://github.com/community-scripts/ProxmoxVE/pull/14328))
|
||||
- fix(homepage): fix ERR_PNPM_IGNORED_BUILDS error [@Sergih28](https://github.com/Sergih28) ([#14315](https://github.com/community-scripts/ProxmoxVE/pull/14315))
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- tools.func: add setup_nltk as new function [@MickLesk](https://github.com/MickLesk) ([#14314](https://github.com/community-scripts/ProxmoxVE/pull/14314))
|
||||
|
||||
### 💾 Core
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- tools.func: fix meilisearch import-dump background process handling [@MickLesk](https://github.com/MickLesk) ([#14341](https://github.com/community-scripts/ProxmoxVE/pull/14341))
|
||||
|
||||
## 2026-05-07
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- termix: create /tmp/nginx before nginx -t [@MickLesk](https://github.com/MickLesk) ([#14312](https://github.com/community-scripts/ProxmoxVE/pull/14312))
|
||||
- The Lounge: Fix service not starting automaticaly [@tremor021](https://github.com/tremor021) ([#14311](https://github.com/community-scripts/ProxmoxVE/pull/14311))
|
||||
- netbird-lxc: fix installation check [@MickLesk](https://github.com/MickLesk) ([#14309](https://github.com/community-scripts/ProxmoxVE/pull/14309))
|
||||
- databasus: Backup and secure configuration file [@MickLesk](https://github.com/MickLesk) ([#14308](https://github.com/community-scripts/ProxmoxVE/pull/14308))
|
||||
- vm: update disk image URL for Ubuntu 25.04 [@MickLesk](https://github.com/MickLesk) ([#14290](https://github.com/community-scripts/ProxmoxVE/pull/14290))
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- pangolin: bump version to 1.18.3 [@MickLesk](https://github.com/MickLesk) ([#14297](https://github.com/community-scripts/ProxmoxVE/pull/14297))
|
||||
|
||||
### 🗑️ Deleted Scripts
|
||||
|
||||
- Remove: LiteLLM [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#14294](https://github.com/community-scripts/ProxmoxVE/pull/14294))
|
||||
|
||||
### 💾 Core
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- update-apps: some improvements [@MickLesk](https://github.com/MickLesk) ([#14275](https://github.com/community-scripts/ProxmoxVE/pull/14275))
|
||||
|
||||
## 2026-05-06
|
||||
|
||||
### 🆕 New Scripts
|
||||
|
||||
- Hoodik ([#14279](https://github.com/community-scripts/ProxmoxVE/pull/14279))
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- Pelican-Panel: create backup subdirectory before copying storage [@MickLesk](https://github.com/MickLesk) ([#14274](https://github.com/community-scripts/ProxmoxVE/pull/14274))
|
||||
- Rustdeskserver: remove redundant else with undefined RELEASE var [@MickLesk](https://github.com/MickLesk) ([#14272](https://github.com/community-scripts/ProxmoxVE/pull/14272))
|
||||
|
||||
### 🧰 Tools
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- AdguardHome-Sync replace ifconfig with hostname -I for IP detection [@MickLesk](https://github.com/MickLesk) ([#14273](https://github.com/community-scripts/ProxmoxVE/pull/14273))
|
||||
|
||||
## 2026-05-05
|
||||
|
||||
### 🆕 New Scripts
|
||||
|
||||
- LibreChat ([#14247](https://github.com/community-scripts/ProxmoxVE/pull/14247))
|
||||
- Matomo ([#14248](https://github.com/community-scripts/ProxmoxVE/pull/14248))
|
||||
- Storyteller ([#14122](https://github.com/community-scripts/ProxmoxVE/pull/14122))
|
||||
|
||||
### 🧰 Tools
|
||||
|
||||
- Fix container count message in update-apps.sh [@Quotacious](https://github.com/Quotacious) ([#14265](https://github.com/community-scripts/ProxmoxVE/pull/14265))
|
||||
|
||||
## 2026-05-04
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- Databasus: move .env to filesystem root so service starts correctly [@Copilot](https://github.com/Copilot) ([#14252](https://github.com/community-scripts/ProxmoxVE/pull/14252))
|
||||
- Databasus: update mongo-tools fallback to 100.16.1 and use now pnpm instead of npm ci [@MickLesk](https://github.com/MickLesk) ([#14240](https://github.com/community-scripts/ProxmoxVE/pull/14240))
|
||||
|
||||
### 💾 Core
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- tools.func get_latest_gh_tag - add pagination to find prefixed tags beyond first 50 [@MickLesk](https://github.com/MickLesk) ([#14241](https://github.com/community-scripts/ProxmoxVE/pull/14241))
|
||||
- tools.func: add GitLab release check/fetch/deploy helpers [@MickLesk](https://github.com/MickLesk) ([#14242](https://github.com/community-scripts/ProxmoxVE/pull/14242))
|
||||
|
||||
## 2026-05-03
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- Hortusfox: fix update issues [@tomfrenzel](https://github.com/tomfrenzel) ([#14214](https://github.com/community-scripts/ProxmoxVE/pull/14214))
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- Refactor: PeaNUT for v6 [@MickLesk](https://github.com/MickLesk) ([#14224](https://github.com/community-scripts/ProxmoxVE/pull/14224))
|
||||
- pangolin: pin version, drop manual SQL, use upstream migrator [@MickLesk](https://github.com/MickLesk) ([#14223](https://github.com/community-scripts/ProxmoxVE/pull/14223))
|
||||
|
||||
### 💾 Core
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- core: fix validate_bridge function [@MichaelOultram](https://github.com/MichaelOultram) ([#14206](https://github.com/community-scripts/ProxmoxVE/pull/14206))
|
||||
|
||||
### 🧰 Tools
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- pve/pbs scripts: guard sed against missing /etc/apt/sources.list [@MickLesk](https://github.com/MickLesk) ([#14222](https://github.com/community-scripts/ProxmoxVE/pull/14222))
|
||||
|
||||
## 2026-05-02
|
||||
|
||||
### 🆕 New Scripts
|
||||
|
||||
- protonmail-bridge ([#14136](https://github.com/community-scripts/ProxmoxVE/pull/14136))
|
||||
- Tube Archivist ([#14123](https://github.com/community-scripts/ProxmoxVE/pull/14123))
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- Nagios: Ping fix [@tremor021](https://github.com/tremor021) ([#14186](https://github.com/community-scripts/ProxmoxVE/pull/14186))
|
||||
- opnsense-vm: retry pvesm alloc on transient zfs 'got timeout' errors [@MickLesk](https://github.com/MickLesk) ([#14157](https://github.com/community-scripts/ProxmoxVE/pull/14157))
|
||||
- ImmichFrame: fix update by reinstalling dotnet-sdk before publish [@MickLesk](https://github.com/MickLesk) ([#14158](https://github.com/community-scripts/ProxmoxVE/pull/14158))
|
||||
- [FIX]ShelfMark: Use UV sync for shelfmark backend build; update to Python 3.14 [@vhsdream](https://github.com/vhsdream) ([#14170](https://github.com/community-scripts/ProxmoxVE/pull/14170))
|
||||
- alpine: remove deb/ubuntu-only resource & storage checks from update-script [@MickLesk](https://github.com/MickLesk) ([#14166](https://github.com/community-scripts/ProxmoxVE/pull/14166))
|
||||
- Threadfin: use 'threadfin-app' as app name to avoid version-file clash [@MickLesk](https://github.com/MickLesk) ([#14159](https://github.com/community-scripts/ProxmoxVE/pull/14159))
|
||||
|
||||
### 💾 Core
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- core: prompt to also run installed addon update scripts (…/bin/update_*) after update_script [@MickLesk](https://github.com/MickLesk) ([#14162](https://github.com/community-scripts/ProxmoxVE/pull/14162))
|
||||
|
||||
## 2026-05-01
|
||||
|
||||
### 🆕 New Scripts
|
||||
|
||||
- SoulSync ([#14124](https://github.com/community-scripts/ProxmoxVE/pull/14124))
|
||||
- Teable ([#14125](https://github.com/community-scripts/ProxmoxVE/pull/14125))
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- Step ca update [@heinemannj](https://github.com/heinemannj) ([#14058](https://github.com/community-scripts/ProxmoxVE/pull/14058))
|
||||
- paperless-ngx: refresh NLTK data on update [@kurtislanderson](https://github.com/kurtislanderson) ([#14144](https://github.com/community-scripts/ProxmoxVE/pull/14144))
|
||||
- [Pelican Panel] stop deleting the public storage [@LetterN](https://github.com/LetterN) ([#14145](https://github.com/community-scripts/ProxmoxVE/pull/14145))
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- Mail-Archiver: update dependencies [@tremor021](https://github.com/tremor021) ([#14152](https://github.com/community-scripts/ProxmoxVE/pull/14152))
|
||||
Generated
+248
@@ -0,0 +1,248 @@
|
||||
## 2026-06-13
|
||||
|
||||
### 🆕 New Scripts
|
||||
|
||||
- BookOrbit ([#15080](https://github.com/community-scripts/ProxmoxVE/pull/15080))
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- Update authentik version to 2026.5.3 [@thieneret](https://github.com/thieneret) ([#15093](https://github.com/community-scripts/ProxmoxVE/pull/15093))
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- Immich: Update image-processing libraries [@vhsdream](https://github.com/vhsdream) ([#15082](https://github.com/community-scripts/ProxmoxVE/pull/15082))
|
||||
- HomeBox: Support v0.26.0 [@tomfrenzel](https://github.com/tomfrenzel) ([#15086](https://github.com/community-scripts/ProxmoxVE/pull/15086))
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- Refactor: Implement backup functions for scripts A-B [@tremor021](https://github.com/tremor021) ([#15075](https://github.com/community-scripts/ProxmoxVE/pull/15075))
|
||||
|
||||
## 2026-06-12
|
||||
|
||||
### 🆕 New Scripts
|
||||
|
||||
- Twenty ([#15047](https://github.com/community-scripts/ProxmoxVE/pull/15047))
|
||||
- Alpine-Cinny ([#15044](https://github.com/community-scripts/ProxmoxVE/pull/15044))
|
||||
|
||||
### 💾 Core
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- [core] Implement backup and restore functions [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15067](https://github.com/community-scripts/ProxmoxVE/pull/15067))
|
||||
|
||||
## 2026-06-11
|
||||
|
||||
### 🆕 New Scripts
|
||||
|
||||
- Clickhouse ([#15045](https://github.com/community-scripts/ProxmoxVE/pull/15045))
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- Manyfold: add new dependency [@MickLesk](https://github.com/MickLesk) ([#15040](https://github.com/community-scripts/ProxmoxVE/pull/15040))
|
||||
- OpenArchiver: switch Rebuild Function [@MickLesk](https://github.com/MickLesk) ([#15042](https://github.com/community-scripts/ProxmoxVE/pull/15042))
|
||||
- CLIProxyAPI: Save management password to creds file [@tremor021](https://github.com/tremor021) ([#15051](https://github.com/community-scripts/ProxmoxVE/pull/15051))
|
||||
- Jotty: Fix wrong path test in config restore [@vhsdream](https://github.com/vhsdream) ([#15038](https://github.com/community-scripts/ProxmoxVE/pull/15038))
|
||||
- Fix for cross-seed after node upgrade [@TorinFrancis](https://github.com/TorinFrancis) ([#15025](https://github.com/community-scripts/ProxmoxVE/pull/15025))
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- Alpine-Nextcloud: Upgrade PHP and dependencies in installation script [@MickLesk](https://github.com/MickLesk) ([#15039](https://github.com/community-scripts/ProxmoxVE/pull/15039))
|
||||
- [arm64] porting stage 1: set script arm64 statuses to yes [@asylumexp](https://github.com/asylumexp) ([#15052](https://github.com/community-scripts/ProxmoxVE/pull/15052))
|
||||
|
||||
### 💾 Core
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- misc scripts: add support for arm64 [@asylumexp](https://github.com/asylumexp) ([#12639](https://github.com/community-scripts/ProxmoxVE/pull/12639))
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- [arm64] remove logic for custom debian arm64 template [@asylumexp](https://github.com/asylumexp) ([#15050](https://github.com/community-scripts/ProxmoxVE/pull/15050))
|
||||
|
||||
### 📚 Documentation
|
||||
|
||||
- (github): Revise script request template [@MickLesk](https://github.com/MickLesk) ([#15058](https://github.com/community-scripts/ProxmoxVE/pull/15058))
|
||||
|
||||
## 2026-06-10
|
||||
|
||||
### 🆕 New Scripts
|
||||
|
||||
- Baserow ([#14968](https://github.com/community-scripts/ProxmoxVE/pull/14968))
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- Koillection: Fix update procedure [@tremor021](https://github.com/tremor021) ([#15033](https://github.com/community-scripts/ProxmoxVE/pull/15033))
|
||||
|
||||
## 2026-06-09
|
||||
|
||||
### 🆕 New Scripts
|
||||
|
||||
- paperclip ([#14990](https://github.com/community-scripts/ProxmoxVE/pull/14990))
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- endurain: Install pytz package during backend setup [@MickLesk](https://github.com/MickLesk) ([#15014](https://github.com/community-scripts/ProxmoxVE/pull/15014))
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- Refactor: Proxmox Backup Server - use deb822 [@MickLesk](https://github.com/MickLesk) ([#15013](https://github.com/community-scripts/ProxmoxVE/pull/15013))
|
||||
|
||||
## 2026-06-08
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- security: Fix HTTP to HTTPS for all package and repository downloads [@MickLesk](https://github.com/MickLesk) ([#15009](https://github.com/community-scripts/ProxmoxVE/pull/15009))
|
||||
- homelable: preserve MCP server config across updates [@ferr079](https://github.com/ferr079) ([#14996](https://github.com/community-scripts/ProxmoxVE/pull/14996))
|
||||
- changedetection: migrate Python install to uv venv [@ferr079](https://github.com/ferr079) ([#14995](https://github.com/community-scripts/ProxmoxVE/pull/14995))
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- Update Flowwiseai to node 24 [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#14999](https://github.com/community-scripts/ProxmoxVE/pull/14999))
|
||||
|
||||
### 🧰 Tools
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- security: Fix MITM RCE vulnerability in microcode scripts (CVE) [@MickLesk](https://github.com/MickLesk) ([#15007](https://github.com/community-scripts/ProxmoxVE/pull/15007))
|
||||
|
||||
## 2026-06-07
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- Immich: use actual installed PostgreSQL version for vchord package [@MickLesk](https://github.com/MickLesk) ([#14989](https://github.com/community-scripts/ProxmoxVE/pull/14989))
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- Navidrome: remove genereic filebrowser addon setup [@MickLesk](https://github.com/MickLesk) ([#14991](https://github.com/community-scripts/ProxmoxVE/pull/14991))
|
||||
|
||||
## 2026-06-06
|
||||
|
||||
### 🆕 New Scripts
|
||||
|
||||
- Spliit ([#14966](https://github.com/community-scripts/ProxmoxVE/pull/14966))
|
||||
- Tolgee ([#14965](https://github.com/community-scripts/ProxmoxVE/pull/14965))
|
||||
- XYOps ([#14967](https://github.com/community-scripts/ProxmoxVE/pull/14967))
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- Photoprism: Allow env variables with spaces [@Badintral](https://github.com/Badintral) ([#14969](https://github.com/community-scripts/ProxmoxVE/pull/14969))
|
||||
|
||||
## 2026-06-05
|
||||
|
||||
### 🆕 New Scripts
|
||||
|
||||
- MatterJS-Server ([#14951](https://github.com/community-scripts/ProxmoxVE/pull/14951))
|
||||
- CyberChef ([#14952](https://github.com/community-scripts/ProxmoxVE/pull/14952))
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- Jackett: Create missing .env file [@tremor021](https://github.com/tremor021) ([#14959](https://github.com/community-scripts/ProxmoxVE/pull/14959))
|
||||
- OpenThread-BR: use systemd instead of init.d [@tomfrenzel](https://github.com/tomfrenzel) ([#14942](https://github.com/community-scripts/ProxmoxVE/pull/14942))
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- AMD IGPU support [@Learath](https://github.com/Learath) ([#14944](https://github.com/community-scripts/ProxmoxVE/pull/14944))
|
||||
|
||||
- #### 💥 Breaking Changes
|
||||
|
||||
- update authentik to 2026.5.2 [@thieneret](https://github.com/thieneret) ([#14846](https://github.com/community-scripts/ProxmoxVE/pull/14846))
|
||||
|
||||
## 2026-06-04
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- Fix status messages for several alpine scripts [@tremor021](https://github.com/tremor021) ([#14911](https://github.com/community-scripts/ProxmoxVE/pull/14911))
|
||||
- ReactiveResume: Fix Service Path [@MickLesk](https://github.com/MickLesk) ([#14926](https://github.com/community-scripts/ProxmoxVE/pull/14926))
|
||||
- Jellyfin: install intel-igc deps before intel-opencl-icd to fix dependency order [@MickLesk](https://github.com/MickLesk) ([#14927](https://github.com/community-scripts/ProxmoxVE/pull/14927))
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- OpenThread-BR: use official GitHub releases [@tomfrenzel](https://github.com/tomfrenzel) ([#14916](https://github.com/community-scripts/ProxmoxVE/pull/14916))
|
||||
- Grist: remove extra text at the end of installation [@tremor021](https://github.com/tremor021) ([#14905](https://github.com/community-scripts/ProxmoxVE/pull/14905))
|
||||
|
||||
### ❔ Uncategorized
|
||||
|
||||
- chore(ct): sync sparkyfitness defaults with PocketBase [@github-actions[bot]](https://github.com/github-actions[bot]) ([#14925](https://github.com/community-scripts/ProxmoxVE/pull/14925))
|
||||
|
||||
## 2026-06-03
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- Glance: Use separate directory for configuration files [@tremor021](https://github.com/tremor021) ([#14906](https://github.com/community-scripts/ProxmoxVE/pull/14906))
|
||||
|
||||
### 💾 Core
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- [core]: Fix alignment for `msg_` functions [@tremor021](https://github.com/tremor021) ([#14908](https://github.com/community-scripts/ProxmoxVE/pull/14908))
|
||||
|
||||
## 2026-06-02
|
||||
|
||||
### 🆕 New Scripts
|
||||
|
||||
- DDNS-Updater ([#14883](https://github.com/community-scripts/ProxmoxVE/pull/14883))
|
||||
- InvoiceShelf ([#14882](https://github.com/community-scripts/ProxmoxVE/pull/14882))
|
||||
- Certimate ([#14881](https://github.com/community-scripts/ProxmoxVE/pull/14881))
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- OpenThread-BR: preserve config during update [@tomfrenzel](https://github.com/tomfrenzel) ([#14893](https://github.com/community-scripts/ProxmoxVE/pull/14893))
|
||||
- infisical: fix update abort due to creds field mismatch (#14868) [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#14870](https://github.com/community-scripts/ProxmoxVE/pull/14870))
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- feat(degoog): enable default valkey cache integration [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#14871](https://github.com/community-scripts/ProxmoxVE/pull/14871))
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- chore: bump Node version in selected scripts [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#14873](https://github.com/community-scripts/ProxmoxVE/pull/14873))
|
||||
|
||||
### 💾 Core
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- tools.func: add support for Rust installation profile in setup_rust [@MickLesk](https://github.com/MickLesk) ([#14872](https://github.com/community-scripts/ProxmoxVE/pull/14872))
|
||||
|
||||
### 📂 Github
|
||||
|
||||
- fix(workflow): only flag node drift when local is behind upstream [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#14874](https://github.com/community-scripts/ProxmoxVE/pull/14874))
|
||||
|
||||
## 2026-06-01
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- fix(dispatcharr): forward nginx port for M3U URLs on new installs [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#14862](https://github.com/community-scripts/ProxmoxVE/pull/14862))
|
||||
- Set environment paths in service for apprise-api-install.sh [@SystemIdleProcess](https://github.com/SystemIdleProcess) ([#14805](https://github.com/community-scripts/ProxmoxVE/pull/14805))
|
||||
- fix(fireshare): rebuild client on update to fix nginx 500 [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#14848](https://github.com/community-scripts/ProxmoxVE/pull/14848))
|
||||
- Fix Kan build failure (TS7016 nodemailer) [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#14856](https://github.com/community-scripts/ProxmoxVE/pull/14856))
|
||||
- fix(firefly): set Data Importer APP_URL for subdirectory install [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#14847](https://github.com/community-scripts/ProxmoxVE/pull/14847))
|
||||
- kan: extend fetch_and_deploy_gh_tag to use 'latest' tag [@MickLesk](https://github.com/MickLesk) ([#14853](https://github.com/community-scripts/ProxmoxVE/pull/14853))
|
||||
- Glance: preserve glance.yml across updates [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#14845](https://github.com/community-scripts/ProxmoxVE/pull/14845))
|
||||
- NginxProxymanager: set Certbot version in npm.service environment variable (2.15.0) [@MickLesk](https://github.com/MickLesk) ([#14843](https://github.com/community-scripts/ProxmoxVE/pull/14843))
|
||||
- [FileFlows] Fix service handling by using systemctl --all with quoted glob [@adrianmusante](https://github.com/adrianmusante) ([#14838](https://github.com/community-scripts/ProxmoxVE/pull/14838))
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- Kometa: also update Quickstart in update_script [@MickLesk](https://github.com/MickLesk) ([#14529](https://github.com/community-scripts/ProxmoxVE/pull/14529))
|
||||
Generated
+1
-1
@@ -22,6 +22,6 @@ Fixes #
|
||||
- [ ] ✨ **New feature** – Adds new, non-breaking functionality.
|
||||
- [ ] 💥 **Breaking change** – Alters existing functionality in a way that may require updates.
|
||||
- [ ] 🆕 **New script** – A fully functional and tested script or script set.
|
||||
- [ ] 🌍 **Website update** – Changes to website-related JSON files or metadata.
|
||||
- [ ] 🌍 **Website update** – Changes to script metadata (PocketBase/website data).
|
||||
- [ ] 🔧 **Refactoring / Code Cleanup** – Improves readability or maintainability without changing functionality.
|
||||
- [ ] 📝 **Documentation update** – Changes to `README`, `AppName.md`, `CONTRIBUTING.md`, or other docs.
|
||||
|
||||
+29
-17
@@ -49,18 +49,26 @@ jobs:
|
||||
return
|
||||
fi
|
||||
|
||||
local url="https://pkgs.alpinelinux.org/package/v${alpine_ver}/main/x86_64/nodejs"
|
||||
local page
|
||||
page=$(curl -sf "$url" 2>/dev/null || echo "")
|
||||
local full_ver=""
|
||||
if [[ -n "$page" ]]; then
|
||||
# Parse: "Version | 24.13.0-r1" or similar table row
|
||||
full_ver=$(echo "$page" | grep -oP 'Version\s*\|\s*\K[0-9]+\.[0-9]+\.[0-9]+' | head -1 || echo "")
|
||||
if [[ -z "$full_ver" ]]; then
|
||||
# Fallback: look for version pattern after "Version"
|
||||
full_ver=$(echo "$page" | grep -oP '(?<=Version</td><td>)[0-9]+\.[0-9]+\.[0-9]+' | head -1 || echo "")
|
||||
local arch_label url_arch url page
|
||||
for arch_pair in "amd64:x86_64" "arm64:aarch64"; do
|
||||
arch_label="${arch_pair%%:*}"
|
||||
url_arch="${arch_pair#*:}"
|
||||
url="https://pkgs.alpinelinux.org/package/v${alpine_ver}/main/${url_arch}/nodejs"
|
||||
page=$(curl -sf "$url" 2>/dev/null || echo "")
|
||||
if [[ -n "$page" ]]; then
|
||||
# Parse: "Version | 24.13.0-r1" or similar table row.
|
||||
full_ver=$(echo "$page" | grep -oP 'Version\s*\|\s*\K[0-9]+\.[0-9]+\.[0-9]+' | head -1 || echo "")
|
||||
if [[ -z "$full_ver" ]]; then
|
||||
# Fallback: look for version pattern after "Version".
|
||||
full_ver=$(echo "$page" | grep -oP '(?<=Version</td><td>)[0-9]+\.[0-9]+\.[0-9]+' | head -1 || echo "")
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
if [[ -n "$full_ver" ]]; then
|
||||
echo "Resolved Alpine ${alpine_ver} nodejs via ${arch_label}"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
local major=""
|
||||
if [[ -n "$full_ver" ]]; then
|
||||
@@ -328,14 +336,18 @@ jobs:
|
||||
issue_scripts+=("$slug|$our_version|$upstream_major|$upstream_hint|$repo")
|
||||
drift_count=$((drift_count + 1))
|
||||
elif [[ -n "$upstream_major" && "$our_version" != "$upstream_major" ]]; then
|
||||
# Check if engines.node is a minimum constraint that our version satisfies
|
||||
if [[ -z "$DF_NODE_MAJOR" && "$ENGINES_IS_MINIMUM" == "true" ]] && \
|
||||
version_satisfies_engines "$our_version" "$ENGINES_MIN_MAJOR" "$ENGINES_IS_MINIMUM"; then
|
||||
status="✅ (engines: $ENGINES_NODE_RAW — ours: $our_version satisfies)"
|
||||
if (( our_version < upstream_major )); then
|
||||
# Check if engines.node is a minimum constraint that our version satisfies
|
||||
if [[ -z "$DF_NODE_MAJOR" && "$ENGINES_IS_MINIMUM" == "true" ]] && \
|
||||
version_satisfies_engines "$our_version" "$ENGINES_MIN_MAJOR" "$ENGINES_IS_MINIMUM"; then
|
||||
status="✅ (engines: $ENGINES_NODE_RAW — ours: $our_version satisfies)"
|
||||
else
|
||||
status="🔸 Drift → upstream=$upstream_major ($upstream_hint)"
|
||||
issue_scripts+=("$slug|$our_version|$upstream_major|$upstream_hint|$repo")
|
||||
drift_count=$((drift_count + 1))
|
||||
fi
|
||||
else
|
||||
status="🔸 Drift → upstream=$upstream_major ($upstream_hint)"
|
||||
issue_scripts+=("$slug|$our_version|$upstream_major|$upstream_hint|$repo")
|
||||
drift_count=$((drift_count + 1))
|
||||
status="✅ Ahead of upstream ($upstream_major via $upstream_hint)"
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
+34
-38
@@ -3,7 +3,7 @@ name: Close Unauthorized New Script PRs
|
||||
on:
|
||||
pull_request_target:
|
||||
branches: ["main"]
|
||||
types: [opened, labeled]
|
||||
types: [opened, labeled, reopened, synchronize]
|
||||
|
||||
jobs:
|
||||
check-new-script:
|
||||
@@ -24,17 +24,11 @@ jobs:
|
||||
const owner = context.repo.owner;
|
||||
const repo = context.repo.repo;
|
||||
|
||||
// --- Only act on PRs with the "new script" label ---
|
||||
const labels = pr.labels.map(l => l.name);
|
||||
if (!labels.includes("new script")) {
|
||||
core.info(`PR #${prNumber} does not have "new script" label — skipping.`);
|
||||
return;
|
||||
}
|
||||
|
||||
// --- Allow our bots ---
|
||||
const allowedBots = [
|
||||
"push-app-to-main[bot]",
|
||||
"push-app-to-main",
|
||||
"community-scripts-pr-app"
|
||||
];
|
||||
|
||||
if (allowedBots.includes(author)) {
|
||||
@@ -42,38 +36,40 @@ jobs:
|
||||
return;
|
||||
}
|
||||
|
||||
// --- Check if author is a member of the contributor team ---
|
||||
const teamSlug = "contributor";
|
||||
let isMember = false;
|
||||
|
||||
try {
|
||||
const { status } = await github.rest.teams.getMembershipForUserInOrg({
|
||||
org: owner,
|
||||
team_slug: teamSlug,
|
||||
username: author,
|
||||
});
|
||||
// status 200 means the user is a member (active or pending)
|
||||
isMember = true;
|
||||
} catch (error) {
|
||||
if (error.status === 404) {
|
||||
isMember = false;
|
||||
} else {
|
||||
core.warning(`Could not check team membership for ${author}: ${error.message}`);
|
||||
// Fallback: check org membership
|
||||
try {
|
||||
await github.rest.orgs.checkMembershipForUser({
|
||||
org: owner,
|
||||
username: author,
|
||||
});
|
||||
isMember = true;
|
||||
} catch {
|
||||
isMember = false;
|
||||
}
|
||||
}
|
||||
// --- Exempt contributors via author_association ---
|
||||
// OWNER/MEMBER/COLLABORATOR are trusted; CONTRIBUTOR ("has merged before")
|
||||
// and NONE are not — their new-script PRs are still closed.
|
||||
const association = pr.author_association;
|
||||
const exempt = ["OWNER", "MEMBER", "COLLABORATOR"];
|
||||
if (exempt.includes(association)) {
|
||||
core.info(`PR #${prNumber} by ${association} "${author}" — skipping.`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isMember) {
|
||||
core.info(`PR #${prNumber} by contributor "${author}" — skipping.`);
|
||||
// --- Detect a new-script PR: "new script" label OR a newly-added
|
||||
// script file under ct/ install/ turnkey/ vm/ (mirrors
|
||||
// autolabeler-config.json). Removes the label-timing dependency. ---
|
||||
const labels = pr.labels.map(l => l.name);
|
||||
const hasNewScriptLabel = labels.includes("new script");
|
||||
|
||||
const scriptPrefixes = ["ct/", "install/", "turnkey/", "vm/"];
|
||||
let hasAddedScriptFile = false;
|
||||
try {
|
||||
const files = await github.paginate(github.rest.pulls.listFiles, {
|
||||
owner,
|
||||
repo,
|
||||
pull_number: prNumber,
|
||||
per_page: 100,
|
||||
});
|
||||
hasAddedScriptFile = files.some(
|
||||
f => f.status === "added" && scriptPrefixes.some(p => f.filename.startsWith(p))
|
||||
);
|
||||
} catch (error) {
|
||||
core.warning(`Could not list files for PR #${prNumber}: ${error.message}`);
|
||||
}
|
||||
|
||||
if (!hasNewScriptLabel && !hasAddedScriptFile) {
|
||||
core.info(`PR #${prNumber} is not a new-script submission (no label, no added script file) — skipping.`);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
+56
-31
@@ -56,46 +56,57 @@ jobs:
|
||||
echo "$slugs" > pocketbase_slugs.txt
|
||||
echo "count=$(echo $slugs | wc -w)" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Search for Issues with Similar Titles
|
||||
- name: Find matching issues in ProxmoxVED by slug
|
||||
id: find_issue
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
issues=$(gh issue list --repo community-scripts/ProxmoxVED --json number,title --jq '.[] | {number, title}')
|
||||
|
||||
best_match_score=0
|
||||
best_match_number=0
|
||||
|
||||
for issue in $(echo "$issues" | jq -r '. | @base64'); do
|
||||
_jq() {
|
||||
echo ${issue} | base64 --decode | jq -r ${1}
|
||||
}
|
||||
|
||||
issue_title=$(_jq '.title' | tr '[:upper:]' '[:lower:]' | sed 's/ //g' | sed 's/-//g')
|
||||
issue_number=$(_jq '.number')
|
||||
|
||||
match_score=$(echo "$title" | grep -o "$issue_title" | wc -l)
|
||||
|
||||
if [ "$match_score" -gt "$best_match_score" ]; then
|
||||
best_match_score=$match_score
|
||||
best_match_number=$issue_number
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$best_match_number" != "0" ]; then
|
||||
echo "issue_number=$best_match_number" >> $GITHUB_ENV
|
||||
else
|
||||
echo "No matching issue found."
|
||||
if [[ ! -s pocketbase_slugs.txt ]]; then
|
||||
echo "No slugs derived from PR — nothing to match."
|
||||
echo "issue_numbers=" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
slugs=$(cat pocketbase_slugs.txt)
|
||||
|
||||
- name: Comment on the Best-Matching Issue and Close It
|
||||
if: env.issue_number != ''
|
||||
# Normalize: lowercase, strip spaces and hyphens (same shape as the slug derivation)
|
||||
norm() { echo "$1" | tr '[:upper:]' '[:lower:]' | sed 's/[[:space:]]//g; s/-//g'; }
|
||||
|
||||
issues=$(gh issue list --repo community-scripts/ProxmoxVED --state open --limit 1000 --json number,title,body)
|
||||
|
||||
matched=""
|
||||
for slug in $slugs; do
|
||||
nslug=$(norm "$slug")
|
||||
[[ -z "$nslug" ]] && continue
|
||||
while IFS= read -r row; do
|
||||
num=$(echo "$row" | jq -r '.number')
|
||||
ntitle=$(norm "$(echo "$row" | jq -r '.title')")
|
||||
body=$(echo "$row" | jq -r '.body // ""' | tr '[:upper:]' '[:lower:]')
|
||||
# Match when the issue title contains the slug, or the body mentions it verbatim
|
||||
if [[ "$ntitle" == *"$nslug"* ]] || [[ "$body" == *"$slug"* ]]; then
|
||||
matched="$matched $num"
|
||||
fi
|
||||
done < <(echo "$issues" | jq -c '.[]')
|
||||
done
|
||||
|
||||
matched=$(echo $matched | xargs -n1 2>/dev/null | sort -un | tr '\n' ' ')
|
||||
if [[ -z "$matched" ]]; then
|
||||
echo "No matching ProxmoxVED issues found for slugs: $slugs"
|
||||
echo "issue_numbers=" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
echo "Matched ProxmoxVED issues: $matched"
|
||||
echo "issue_numbers=$matched" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Comment on and close matching ProxmoxVED issues
|
||||
if: steps.find_issue.outputs.issue_numbers != ''
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.PAT_MICHEL }}
|
||||
run: |
|
||||
gh issue comment $issue_number --repo community-scripts/ProxmoxVED --body "Merged with #${{ github.event.pull_request.number }} in ProxmoxVE"
|
||||
gh issue close $issue_number --repo community-scripts/ProxmoxVED
|
||||
for issue_number in ${{ steps.find_issue.outputs.issue_numbers }}; do
|
||||
echo "Closing ProxmoxVED issue #$issue_number"
|
||||
gh issue comment "$issue_number" --repo community-scripts/ProxmoxVED --body "Merged with #${{ github.event.pull_request.number }} in ProxmoxVE"
|
||||
gh issue close "$issue_number" --repo community-scripts/ProxmoxVED
|
||||
done
|
||||
|
||||
- name: Set is_dev to false in PocketBase
|
||||
if: steps.get_slugs.outputs.count != '0'
|
||||
@@ -113,7 +124,8 @@ jobs:
|
||||
const http = require('http');
|
||||
const url = require('url');
|
||||
|
||||
function request(fullUrl, opts) {
|
||||
function request(fullUrl, opts, redirectsLeft) {
|
||||
if (redirectsLeft === undefined) redirectsLeft = 5;
|
||||
return new Promise(function(resolve, reject) {
|
||||
const u = url.parse(fullUrl);
|
||||
const isHttps = u.protocol === 'https:';
|
||||
@@ -128,6 +140,19 @@ jobs:
|
||||
if (body) options.headers['Content-Length'] = Buffer.byteLength(body);
|
||||
const lib = isHttps ? https : http;
|
||||
const req = lib.request(options, function(res) {
|
||||
// Follow redirects (301/302/307/308)
|
||||
if ([301, 302, 307, 308].indexOf(res.statusCode) !== -1 && res.headers.location && redirectsLeft > 0) {
|
||||
res.resume();
|
||||
const nextUrl = url.resolve(fullUrl, res.headers.location);
|
||||
// For 301/302, browsers historically downgrade to GET; preserve method for 307/308.
|
||||
const nextOpts = Object.assign({}, opts);
|
||||
if (res.statusCode === 301 || res.statusCode === 302) {
|
||||
nextOpts.method = 'GET';
|
||||
delete nextOpts.body;
|
||||
}
|
||||
resolve(request(nextUrl, nextOpts, redirectsLeft - 1));
|
||||
return;
|
||||
}
|
||||
let data = '';
|
||||
res.on('data', function(chunk) { data += chunk; });
|
||||
res.on('end', function() {
|
||||
|
||||
+134
@@ -0,0 +1,134 @@
|
||||
name: Delete merged branches
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 2 * * *" # Run daily at 02:00 UTC
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
dry_run:
|
||||
description: "Only log branches that would be deleted (no deletion)"
|
||||
type: boolean
|
||||
default: true
|
||||
|
||||
permissions:
|
||||
contents: write # required to delete branch refs
|
||||
pull-requests: read
|
||||
|
||||
jobs:
|
||||
delete-merged-branches:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Delete branches of merged PRs
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const owner = context.repo.owner;
|
||||
const repo = context.repo.repo;
|
||||
|
||||
// dry_run is only set on workflow_dispatch; scheduled runs delete for real.
|
||||
const dryRun = context.eventName === "workflow_dispatch"
|
||||
? context.payload.inputs?.dry_run === "true" || context.payload.inputs?.dry_run === true
|
||||
: false;
|
||||
|
||||
// Only look at PRs updated within this window on scheduled runs, so we don't
|
||||
// re-scan the entire history every day. Raise this for an initial cleanup.
|
||||
const lookbackDays = 30;
|
||||
const cutoff = new Date();
|
||||
cutoff.setDate(cutoff.getDate() - lookbackDays);
|
||||
|
||||
// Long-lived branches that must never be deleted (besides the default branch).
|
||||
const protectedNames = new Set();
|
||||
|
||||
// Resolve the default branch once.
|
||||
const { data: repoData } = await github.rest.repos.get({ owner, repo });
|
||||
const defaultBranch = repoData.default_branch;
|
||||
protectedNames.add(defaultBranch);
|
||||
|
||||
console.log(`Mode: ${dryRun ? "DRY RUN (no deletion)" : "LIVE"}`);
|
||||
console.log(`Default branch: ${defaultBranch}`);
|
||||
|
||||
const candidates = new Set();
|
||||
let page = 1;
|
||||
let stop = false;
|
||||
|
||||
while (!stop) {
|
||||
const { data: prs } = await github.rest.pulls.list({
|
||||
owner,
|
||||
repo,
|
||||
state: "closed",
|
||||
sort: "updated",
|
||||
direction: "desc",
|
||||
per_page: 100,
|
||||
page,
|
||||
});
|
||||
|
||||
if (prs.length === 0) break;
|
||||
|
||||
for (const pr of prs) {
|
||||
// Sorted by updated desc: once we pass the cutoff we can stop paginating.
|
||||
if (new Date(pr.updated_at) < cutoff) {
|
||||
stop = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!pr.merged_at) continue; // only merged PRs
|
||||
if (!pr.head.repo) continue; // head fork was deleted
|
||||
if (pr.head.repo.full_name !== pr.base.repo.full_name) continue; // skip forks
|
||||
|
||||
const branch = pr.head.ref;
|
||||
if (protectedNames.has(branch)) continue; // default / kept branches
|
||||
|
||||
candidates.add(branch);
|
||||
}
|
||||
|
||||
page++;
|
||||
if (page > 50) break; // safety cap
|
||||
}
|
||||
|
||||
console.log(`Found ${candidates.size} unique candidate branch(es) from merged PRs.`);
|
||||
|
||||
let deleted = 0;
|
||||
let skipped = 0;
|
||||
|
||||
for (const branch of candidates) {
|
||||
// Confirm the branch still exists and isn't protected.
|
||||
let branchData;
|
||||
try {
|
||||
const res = await github.rest.repos.getBranch({ owner, repo, branch });
|
||||
branchData = res.data;
|
||||
} catch (error) {
|
||||
if (error.status === 404) {
|
||||
// Already deleted (e.g. auto-delete head branch) — nothing to do.
|
||||
continue;
|
||||
}
|
||||
console.log(`Failed to inspect "${branch}": ${error.message}`);
|
||||
skipped++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (branchData.protected) {
|
||||
console.log(`Skipped "${branch}" (protected branch)`);
|
||||
skipped++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dryRun) {
|
||||
console.log(`[dry-run] Would delete "${branch}"`);
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
await github.rest.git.deleteRef({ owner, repo, ref: `heads/${branch}` });
|
||||
console.log(`Deleted "${branch}"`);
|
||||
deleted++;
|
||||
} catch (error) {
|
||||
console.log(`Failed to delete "${branch}": ${error.message}`);
|
||||
skipped++;
|
||||
}
|
||||
}
|
||||
|
||||
console.log(
|
||||
dryRun
|
||||
? `Dry run complete. ${candidates.size} candidate(s) would be processed.`
|
||||
: `Done. Deleted ${deleted} branch(es), skipped ${skipped}.`
|
||||
);
|
||||
@@ -27,6 +27,7 @@ jobs:
|
||||
BEFORE="${{ github.event.before }}"
|
||||
AFTER="${{ github.event.after }}"
|
||||
slugs=""
|
||||
ct_slugs=""
|
||||
|
||||
# Deleted JSON files: get slug from previous commit
|
||||
deleted_json=$(git diff --name-only --diff-filter=D "$BEFORE" "$AFTER" -- json/ | grep '\.json$' || true)
|
||||
@@ -37,6 +38,14 @@ jobs:
|
||||
done
|
||||
|
||||
# Deleted script files: derive slug from path
|
||||
deleted_ct=$(git diff --name-only --diff-filter=D "$BEFORE" "$AFTER" -- ct/ | grep '\.sh$' || true)
|
||||
for f in $deleted_ct; do
|
||||
[[ -z "$f" ]] && continue
|
||||
base="${f##*/}"
|
||||
base="${base%.sh}"
|
||||
[[ -n "$base" ]] && ct_slugs="$ct_slugs $base"
|
||||
done
|
||||
|
||||
deleted_sh=$(git diff --name-only --diff-filter=D "$BEFORE" "$AFTER" -- ct/ install/ tools/ turnkey/ vm/ | grep '\.sh$' || true)
|
||||
for f in $deleted_sh; do
|
||||
[[ -z "$f" ]] && continue
|
||||
@@ -51,14 +60,17 @@ jobs:
|
||||
done
|
||||
|
||||
slugs=$(echo $slugs | xargs -n1 | sort -u | tr '\n' ' ')
|
||||
ct_slugs=$(echo $ct_slugs | xargs -n1 2>/dev/null | sort -u | tr '\n' ' ')
|
||||
if [[ -z "$slugs" ]]; then
|
||||
echo "No deleted JSON or script files to mark as deleted in PocketBase."
|
||||
echo "count=0" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
echo "$slugs" > slugs_to_delete.txt
|
||||
echo "$ct_slugs" > ct_slugs_to_stub.txt
|
||||
echo "count=$(echo $slugs | wc -w)" >> "$GITHUB_OUTPUT"
|
||||
echo "Slugs to mark as deleted: $slugs"
|
||||
[[ -n "$ct_slugs" ]] && echo "CT stubs to generate: $ct_slugs"
|
||||
|
||||
- name: Mark as deleted in PocketBase
|
||||
if: steps.slugs.outputs.count != '0'
|
||||
@@ -159,3 +171,134 @@ jobs:
|
||||
})().catch(e => { console.error(e); process.exit(1); });
|
||||
ENDSCRIPT
|
||||
shell: bash
|
||||
|
||||
- name: Generate CT stubs for deleted scripts
|
||||
if: steps.slugs.outputs.count != '0'
|
||||
env:
|
||||
POCKETBASE_URL: ${{ secrets.POCKETBASE_URL }}
|
||||
POCKETBASE_COLLECTION: ${{ secrets.POCKETBASE_COLLECTION }}
|
||||
POCKETBASE_ADMIN_EMAIL: ${{ secrets.POCKETBASE_ADMIN_EMAIL }}
|
||||
POCKETBASE_ADMIN_PASSWORD: ${{ secrets.POCKETBASE_ADMIN_PASSWORD }}
|
||||
run: |
|
||||
if [[ ! -s ct_slugs_to_stub.txt ]]; then
|
||||
echo "No deleted ct/*.sh files; skipping stub generation."
|
||||
exit 0
|
||||
fi
|
||||
node << 'ENDSCRIPT'
|
||||
(async function() {
|
||||
const fs = require('fs');
|
||||
const https = require('https');
|
||||
const http = require('http');
|
||||
const path = require('path');
|
||||
const url = require('url');
|
||||
|
||||
function request(fullUrl, opts, redirectCount) {
|
||||
redirectCount = redirectCount || 0;
|
||||
return new Promise(function(resolve, reject) {
|
||||
const u = url.parse(fullUrl);
|
||||
const isHttps = u.protocol === 'https:';
|
||||
const body = opts.body;
|
||||
const options = {
|
||||
hostname: u.hostname,
|
||||
port: u.port || (isHttps ? 443 : 80),
|
||||
path: u.path,
|
||||
method: opts.method || 'GET',
|
||||
headers: opts.headers || {}
|
||||
};
|
||||
if (body) options.headers['Content-Length'] = Buffer.byteLength(body);
|
||||
const lib = isHttps ? https : http;
|
||||
const req = lib.request(options, function(res) {
|
||||
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
||||
if (redirectCount >= 5) return reject(new Error('Too many redirects from ' + fullUrl));
|
||||
const redirectUrl = url.resolve(fullUrl, res.headers.location);
|
||||
res.resume();
|
||||
resolve(request(redirectUrl, opts, redirectCount + 1));
|
||||
return;
|
||||
}
|
||||
let data = '';
|
||||
res.on('data', function(chunk) { data += chunk; });
|
||||
res.on('end', function() {
|
||||
resolve({ ok: res.statusCode >= 200 && res.statusCode < 300, statusCode: res.statusCode, body: data });
|
||||
});
|
||||
});
|
||||
req.on('error', reject);
|
||||
if (body) req.write(body);
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
|
||||
const raw = process.env.POCKETBASE_URL.replace(/\/$/, '');
|
||||
const apiBase = /\/api$/i.test(raw) ? raw : raw + '/api';
|
||||
const coll = process.env.POCKETBASE_COLLECTION;
|
||||
const ctSlugs = fs.readFileSync('ct_slugs_to_stub.txt', 'utf8').trim().split(/\s+/).filter(Boolean);
|
||||
if (!ctSlugs.length) {
|
||||
console.log('No ct slugs to process.');
|
||||
return;
|
||||
}
|
||||
|
||||
const authRes = await request(apiBase + '/collections/users/auth-with-password', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
identity: process.env.POCKETBASE_ADMIN_EMAIL,
|
||||
password: process.env.POCKETBASE_ADMIN_PASSWORD
|
||||
})
|
||||
});
|
||||
if (!authRes.ok) throw new Error('Auth failed: ' + authRes.body);
|
||||
const token = JSON.parse(authRes.body).token;
|
||||
const recordsUrl = apiBase + '/collections/' + encodeURIComponent(coll) + '/records';
|
||||
|
||||
for (const slug of ctSlugs) {
|
||||
const filter = "(slug='" + slug + "')";
|
||||
const listRes = await request(recordsUrl + '?filter=' + encodeURIComponent(filter) + '&perPage=1&fields=slug,name,deleted_message', {
|
||||
headers: { 'Authorization': token }
|
||||
});
|
||||
if (!listRes.ok) {
|
||||
console.warn('Failed to fetch record for slug "' + slug + '"');
|
||||
continue;
|
||||
}
|
||||
const list = JSON.parse(listRes.body);
|
||||
const rec = list.items && list.items[0];
|
||||
const appName = (rec && rec.name) ? rec.name : slug;
|
||||
const deletedMessage = (rec && rec.deleted_message && rec.deleted_message.trim())
|
||||
? rec.deleted_message.trim()
|
||||
: 'This script was removed and cannot be installed or updated.';
|
||||
|
||||
const stubPath = path.join('ct', slug + '.sh');
|
||||
const content =
|
||||
`#!/usr/bin/env bash
|
||||
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
|
||||
# Copyright (c) 2021-2026 community-scripts ORG
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||
|
||||
APP="${appName.replace(/"/g, '\\"')}"
|
||||
|
||||
header_info "$APP"
|
||||
variables
|
||||
color
|
||||
|
||||
msg_error "This script is no longer available in community-scripts."
|
||||
msg_error "${deletedMessage.replace(/"/g, '\\"')}"
|
||||
msg_warn "More info: https://community-scripts.org/scripts/${slug}"
|
||||
exit 1
|
||||
`;
|
||||
fs.writeFileSync(stubPath, content);
|
||||
console.log('Generated stub: ' + stubPath);
|
||||
}
|
||||
})().catch(e => { console.error(e); process.exit(1); });
|
||||
ENDSCRIPT
|
||||
shell: bash
|
||||
|
||||
- name: Commit generated stubs
|
||||
if: steps.slugs.outputs.count != '0'
|
||||
run: |
|
||||
if git diff --quiet -- ct; then
|
||||
echo "No generated ct stubs to commit."
|
||||
exit 0
|
||||
fi
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||
git add ct/*.sh
|
||||
git commit -m "chore: add deleted script stubs"
|
||||
git push
|
||||
shell: bash
|
||||
|
||||
Generated
+2
-2
@@ -17,7 +17,7 @@ jobs:
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const daysBeforeLock = 3;
|
||||
const daysBeforeLock = 7;
|
||||
const lockDate = new Date();
|
||||
lockDate.setDate(lockDate.getDate() - daysBeforeLock);
|
||||
|
||||
@@ -28,7 +28,7 @@ jobs:
|
||||
/dependabot/i
|
||||
];
|
||||
|
||||
// Search for closed, unlocked issues older than 3 days (paginated, oldest first)
|
||||
// Search for closed, unlocked issues older than 7 days (paginated, oldest first)
|
||||
let page = 1;
|
||||
let totalLocked = 0;
|
||||
|
||||
|
||||
Generated
+610
@@ -0,0 +1,610 @@
|
||||
name: PocketBase AI Bot
|
||||
|
||||
# Natural-language companion to pocketbase-bot.yml.
|
||||
# Mention the bot in plain English, e.g.:
|
||||
# @pocketbase-bot change RAM to 4096 on zigbee2mqtt
|
||||
# @pocketbase-bot disable script Nextcloud because upstream is broken
|
||||
# The bot parses the request with GitHub Models, replies with the exact change(s)
|
||||
# it understood, and only applies them after you reply "@pocketbase-bot confirm".
|
||||
# The slash-command bot (/pocketbase ...) is unaffected; triggers do not overlap.
|
||||
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
|
||||
permissions:
|
||||
models: read # lets the built-in GITHUB_TOKEN call GitHub Models inference
|
||||
contents: write # built-in token opens the CT-defaults sync PR (like the slash bot)
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
ai-bot:
|
||||
runs-on: self-hosted
|
||||
# Broad gate; the script does precise keyword + self-author checks.
|
||||
if: contains(github.event.comment.body, '@pocketbase-bot')
|
||||
|
||||
steps:
|
||||
- name: Mint GitHub App token (bot identity)
|
||||
id: app-token
|
||||
uses: actions/create-github-app-token@v1
|
||||
with:
|
||||
app-id: ${{ secrets.PB_BOT_APP_ID }}
|
||||
private-key: ${{ secrets.PB_BOT_APP_PRIVATE_KEY }}
|
||||
|
||||
- name: Run PocketBase AI bot
|
||||
env:
|
||||
# GitHub REST as the bot identity
|
||||
GH_APP_TOKEN: ${{ steps.app-token.outputs.token }}
|
||||
PB_BOT_APP_ID: ${{ secrets.PB_BOT_APP_ID }}
|
||||
# GitHub Models inference uses the built-in token (needs models: read)
|
||||
MODELS_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
# Built-in token for git/PR ops (CT-defaults sync), mirroring the slash bot
|
||||
GH_DEFAULT_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
AI_MODEL: openai/gpt-4o
|
||||
# PocketBase
|
||||
POCKETBASE_URL: ${{ secrets.POCKETBASE_URL }}
|
||||
POCKETBASE_COLLECTION: ${{ secrets.POCKETBASE_COLLECTION }}
|
||||
POCKETBASE_ADMIN_EMAIL: ${{ secrets.POCKETBASE_ADMIN_EMAIL }}
|
||||
POCKETBASE_ADMIN_PASSWORD: ${{ secrets.POCKETBASE_ADMIN_PASSWORD }}
|
||||
FRONTEND_URL: ${{ secrets.FRONTEND_URL }}
|
||||
REVALIDATE_SECRET: ${{ secrets.REVALIDATE_SECRET }}
|
||||
# Event context
|
||||
COMMENT_BODY: ${{ github.event.comment.body }}
|
||||
COMMENT_ID: ${{ github.event.comment.id }}
|
||||
COMMENT_AUTHOR_TYPE: ${{ github.event.comment.user.type }}
|
||||
ISSUE_NUMBER: ${{ github.event.issue.number }}
|
||||
REPO_OWNER: ${{ github.repository_owner }}
|
||||
REPO_NAME: ${{ github.event.repository.name }}
|
||||
ACTOR: ${{ github.event.comment.user.login }}
|
||||
ACTOR_ASSOCIATION: ${{ github.event.comment.author_association }}
|
||||
run: |
|
||||
node << 'ENDSCRIPT'
|
||||
(async function () {
|
||||
const https = require('https');
|
||||
const http = require('http');
|
||||
const url = require('url');
|
||||
|
||||
// ── HTTP helper with redirect following ────────────────────────────
|
||||
function request(fullUrl, opts, redirectCount) {
|
||||
redirectCount = redirectCount || 0;
|
||||
return new Promise(function (resolve, reject) {
|
||||
const u = url.parse(fullUrl);
|
||||
const isHttps = u.protocol === 'https:';
|
||||
const body = opts.body;
|
||||
const options = {
|
||||
hostname: u.hostname,
|
||||
port: u.port || (isHttps ? 443 : 80),
|
||||
path: u.path,
|
||||
method: opts.method || 'GET',
|
||||
headers: opts.headers || {}
|
||||
};
|
||||
if (body) options.headers['Content-Length'] = Buffer.byteLength(body);
|
||||
const lib = isHttps ? https : http;
|
||||
const req = lib.request(options, function (res) {
|
||||
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
||||
if (redirectCount >= 5) return reject(new Error('Too many redirects from ' + fullUrl));
|
||||
const redirectUrl = url.resolve(fullUrl, res.headers.location);
|
||||
res.resume();
|
||||
resolve(request(redirectUrl, opts, redirectCount + 1));
|
||||
return;
|
||||
}
|
||||
let data = '';
|
||||
res.on('data', function (chunk) { data += chunk; });
|
||||
res.on('end', function () {
|
||||
resolve({ ok: res.statusCode >= 200 && res.statusCode < 300, statusCode: res.statusCode, body: data });
|
||||
});
|
||||
});
|
||||
req.on('error', reject);
|
||||
if (body) req.write(body);
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
|
||||
// ── GitHub REST (as the bot app) ───────────────────────────────────
|
||||
const owner = process.env.REPO_OWNER;
|
||||
const repo = process.env.REPO_NAME;
|
||||
const issueNumber = parseInt(process.env.ISSUE_NUMBER, 10);
|
||||
const commentId = parseInt(process.env.COMMENT_ID, 10);
|
||||
const actor = process.env.ACTOR;
|
||||
|
||||
function ghRequest(path, method, body) {
|
||||
const headers = {
|
||||
'Authorization': 'Bearer ' + process.env.GH_APP_TOKEN,
|
||||
'Accept': 'application/vnd.github+json',
|
||||
'X-GitHub-Api-Version': '2022-11-28',
|
||||
'User-Agent': 'PocketBase-AI-Bot'
|
||||
};
|
||||
const bodyStr = body ? JSON.stringify(body) : undefined;
|
||||
if (bodyStr) headers['Content-Type'] = 'application/json';
|
||||
return request('https://api.github.com' + path, { method: method || 'GET', headers, body: bodyStr });
|
||||
}
|
||||
|
||||
// Same as ghRequest but authenticated with the built-in GITHUB_TOKEN.
|
||||
// Used for the CT-defaults sync branch/PR (the App token lacks contents:write).
|
||||
function ghDefault(path, method, body) {
|
||||
const headers = {
|
||||
'Authorization': 'Bearer ' + process.env.GH_DEFAULT_TOKEN,
|
||||
'Accept': 'application/vnd.github+json',
|
||||
'X-GitHub-Api-Version': '2022-11-28',
|
||||
'User-Agent': 'PocketBase-AI-Bot'
|
||||
};
|
||||
const bodyStr = body ? JSON.stringify(body) : undefined;
|
||||
if (bodyStr) headers['Content-Type'] = 'application/json';
|
||||
return request('https://api.github.com' + path, { method: method || 'GET', headers, body: bodyStr });
|
||||
}
|
||||
|
||||
async function addReaction(content) {
|
||||
try {
|
||||
await ghRequest('/repos/' + owner + '/' + repo + '/issues/comments/' + commentId + '/reactions', 'POST', { content });
|
||||
} catch (e) { console.warn('Could not add reaction:', e.message); }
|
||||
}
|
||||
async function postComment(text) {
|
||||
const res = await ghRequest('/repos/' + owner + '/' + repo + '/issues/' + issueNumber + '/comments', 'POST', { body: text });
|
||||
if (!res.ok) console.warn('Could not post comment:', res.body);
|
||||
return res.ok ? JSON.parse(res.body) : null;
|
||||
}
|
||||
async function updateComment(id, text) {
|
||||
const res = await ghRequest('/repos/' + owner + '/' + repo + '/issues/comments/' + id, 'PATCH', { body: text });
|
||||
if (!res.ok) console.warn('Could not update comment:', res.body);
|
||||
}
|
||||
async function listIssueComments() {
|
||||
const all = [];
|
||||
let page = 1;
|
||||
while (page <= 10) {
|
||||
const res = await ghRequest('/repos/' + owner + '/' + repo + '/issues/' + issueNumber + '/comments?per_page=100&page=' + page);
|
||||
if (!res.ok) break;
|
||||
const batch = JSON.parse(res.body);
|
||||
all.push.apply(all, batch);
|
||||
if (batch.length < 100) break;
|
||||
page++;
|
||||
}
|
||||
return all;
|
||||
}
|
||||
|
||||
// ── 1. Self-trigger guard (App-token comments DO re-fire this event) ─
|
||||
if (process.env.COMMENT_AUTHOR_TYPE === 'Bot') {
|
||||
console.log('Comment authored by a bot — skipping to avoid loops.');
|
||||
return;
|
||||
}
|
||||
|
||||
// ── 2. Permission gate (mirrors the slash bot) ─────────────────────
|
||||
const association = process.env.ACTOR_ASSOCIATION;
|
||||
if (association !== 'OWNER' && association !== 'MEMBER') {
|
||||
await addReaction('-1');
|
||||
await postComment(
|
||||
'❌ **PocketBase AI Bot**: @' + actor + ' is not authorized to use this command.\n' +
|
||||
'Only org members (Contributors team) can use `@pocketbase-bot`.'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// ── 3. Extract the instruction after the @pocketbase-bot handle ────
|
||||
const commentBody = process.env.COMMENT_BODY || '';
|
||||
const handleMatch = commentBody.match(/@pocketbase-bot(\[bot\])?/i);
|
||||
if (!handleMatch) {
|
||||
console.log('No @pocketbase-bot handle found — ignoring.');
|
||||
return;
|
||||
}
|
||||
const instruction = commentBody.slice(handleMatch.index + handleMatch[0].length).trim();
|
||||
if (!instruction) {
|
||||
await addReaction('-1');
|
||||
await postComment(
|
||||
'ℹ️ **PocketBase AI Bot**: Tell me what to do, e.g.\n' +
|
||||
'`@pocketbase-bot change RAM to 4096 on zigbee2mqtt` or `@pocketbase-bot disable script Nextcloud`.'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// ── PocketBase auth + low-level helpers ────────────────────────────
|
||||
const pbRaw = process.env.POCKETBASE_URL.replace(/\/$/, '');
|
||||
const apiBase = /\/api$/i.test(pbRaw) ? pbRaw : pbRaw + '/api';
|
||||
const coll = process.env.POCKETBASE_COLLECTION;
|
||||
const recordsUrl = apiBase + '/collections/' + encodeURIComponent(coll) + '/records';
|
||||
|
||||
async function pbAuth() {
|
||||
const res = await request(apiBase + '/collections/users/auth-with-password', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ identity: process.env.POCKETBASE_ADMIN_EMAIL, password: process.env.POCKETBASE_ADMIN_PASSWORD })
|
||||
});
|
||||
if (!res.ok) throw new Error('PocketBase auth failed: ' + res.body);
|
||||
return JSON.parse(res.body).token;
|
||||
}
|
||||
async function pbFindRecord(token, slug) {
|
||||
const filter = "(slug='" + String(slug).replace(/'/g, "''") + "')";
|
||||
const res = await request(recordsUrl + '?filter=' + encodeURIComponent(filter) + '&perPage=1', { headers: { 'Authorization': token } });
|
||||
const list = JSON.parse(res.body);
|
||||
return list.items && list.items[0];
|
||||
}
|
||||
async function pbPatch(token, id, payload) {
|
||||
return request(recordsUrl + '/' + id, {
|
||||
method: 'PATCH',
|
||||
headers: { 'Authorization': token, 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(payload)
|
||||
});
|
||||
}
|
||||
function readJsonBlob(val) {
|
||||
if (Array.isArray(val)) return val;
|
||||
try { return JSON.parse(val || '[]'); } catch (e) { return []; }
|
||||
}
|
||||
async function revalidate(s) {
|
||||
const frontendUrl = process.env.FRONTEND_URL;
|
||||
const secret = process.env.REVALIDATE_SECRET;
|
||||
if (!frontendUrl || !secret) return;
|
||||
try {
|
||||
await request(frontendUrl.replace(/\/$/, '') + '/api/revalidate', {
|
||||
method: 'POST',
|
||||
headers: { 'Authorization': 'Bearer ' + secret, 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ tags: ['scripts', 'script-' + s] })
|
||||
});
|
||||
} catch (e) { console.warn('Revalidation skipped:', e.message); }
|
||||
}
|
||||
|
||||
// ── CT-defaults sync PR (copied from slash bot) ────────────────────
|
||||
function encodeContentPath(filePath) { return filePath.split('/').map(encodeURIComponent).join('/'); }
|
||||
function decodeGitHubContent(content) { return Buffer.from((content || '').replace(/\n/g, ''), 'base64').toString('utf8'); }
|
||||
function sanitizeBranchPart(value) {
|
||||
return (value || '').toLowerCase().replace(/[^a-z0-9._/-]+/g, '-').replace(/\/+/g, '/').replace(/^-+|-+$/g, '');
|
||||
}
|
||||
function applyCtDefaultChanges(scriptText, varChanges) {
|
||||
let nextText = scriptText;
|
||||
const updatedVars = [], unchangedVars = [];
|
||||
for (const [varName, rawValue] of Object.entries(varChanges)) {
|
||||
const newValue = String(rawValue);
|
||||
const pattern = new RegExp('(^\\s*' + varName + '="\\$\\{' + varName + ':-)([^"}]*)(\\}"\\s*$)', 'm');
|
||||
const match = nextText.match(pattern);
|
||||
if (!match) continue;
|
||||
if (match[2] === newValue) { unchangedVars.push(varName); continue; }
|
||||
nextText = nextText.replace(pattern, '$1' + newValue + '$3');
|
||||
updatedVars.push(varName);
|
||||
}
|
||||
return { nextText, updatedVars, unchangedVars };
|
||||
}
|
||||
async function ensureBranch(defaultBranch, branchName) {
|
||||
const ghRequest = ghDefault; // git ops run as the built-in token
|
||||
const branchRefRes = await ghRequest('/repos/' + owner + '/' + repo + '/git/ref/heads/' + encodeURIComponent(branchName));
|
||||
if (branchRefRes.ok) return;
|
||||
const defaultRefRes = await ghRequest('/repos/' + owner + '/' + repo + '/git/ref/heads/' + encodeURIComponent(defaultBranch));
|
||||
if (!defaultRefRes.ok) throw new Error('Could not read default branch ref: ' + defaultRefRes.body);
|
||||
const defaultRef = JSON.parse(defaultRefRes.body);
|
||||
const createBranchRes = await ghRequest('/repos/' + owner + '/' + repo + '/git/refs', 'POST', { ref: 'refs/heads/' + branchName, sha: defaultRef.object.sha });
|
||||
if (!createBranchRes.ok) throw new Error('Could not create branch: ' + createBranchRes.body);
|
||||
}
|
||||
async function upsertCtDefaultsPr(slugValue, varChanges) {
|
||||
const ghRequest = ghDefault; // contents/PR ops run as the built-in token
|
||||
const wantedEntries = Object.entries(varChanges || {}).filter(function ([, v]) { return v !== undefined && v !== null && String(v) !== ''; });
|
||||
if (wantedEntries.length === 0) return { status: 'skipped', reason: 'No mapped CT defaults changed.' };
|
||||
const repoRes = await ghRequest('/repos/' + owner + '/' + repo);
|
||||
if (!repoRes.ok) throw new Error('Could not read repository metadata: ' + repoRes.body);
|
||||
const defaultBranch = JSON.parse(repoRes.body).default_branch;
|
||||
const ctPath = 'ct/' + slugValue + '.sh';
|
||||
const encodedCtPath = encodeContentPath(ctPath);
|
||||
const defaultFileRes = await ghRequest('/repos/' + owner + '/' + repo + '/contents/' + encodedCtPath + '?ref=' + encodeURIComponent(defaultBranch));
|
||||
if (defaultFileRes.statusCode === 404) return { status: 'skipped', reason: 'No matching CT file found at `' + ctPath + '`.' };
|
||||
if (!defaultFileRes.ok) throw new Error('Could not read CT file from default branch: ' + defaultFileRes.body);
|
||||
const branchName = 'pocketbase-sync/' + sanitizeBranchPart(slugValue || 'unknown');
|
||||
await ensureBranch(defaultBranch, branchName);
|
||||
const branchFileRes = await ghRequest('/repos/' + owner + '/' + repo + '/contents/' + encodedCtPath + '?ref=' + encodeURIComponent(branchName));
|
||||
if (!branchFileRes.ok) throw new Error('Could not read CT file from sync branch: ' + branchFileRes.body);
|
||||
const branchFile = JSON.parse(branchFileRes.body);
|
||||
const currentBranchText = decodeGitHubContent(branchFile.content);
|
||||
const updateResult = applyCtDefaultChanges(currentBranchText, Object.fromEntries(wantedEntries));
|
||||
if (updateResult.updatedVars.length === 0) return { status: 'skipped', reason: 'CT defaults already up to date.' };
|
||||
const putRes = await ghRequest('/repos/' + owner + '/' + repo + '/contents/' + encodedCtPath, 'PUT', {
|
||||
message: 'chore(ct): sync ' + slugValue + ' defaults from PocketBase',
|
||||
content: Buffer.from(updateResult.nextText, 'utf8').toString('base64'),
|
||||
sha: branchFile.sha,
|
||||
branch: branchName
|
||||
});
|
||||
if (!putRes.ok) throw new Error('Could not update CT file: ' + putRes.body);
|
||||
const openPrRes = await ghRequest('/repos/' + owner + '/' + repo + '/pulls?state=open&head=' + encodeURIComponent(owner + ':' + branchName) + '&base=' + encodeURIComponent(defaultBranch));
|
||||
if (!openPrRes.ok) throw new Error('Could not query existing PRs: ' + openPrRes.body);
|
||||
const openPrs = JSON.parse(openPrRes.body);
|
||||
if (openPrs.length > 0) return { status: 'updated', prUrl: openPrs[0].html_url, updatedVars: updateResult.updatedVars };
|
||||
const createPrRes = await ghRequest('/repos/' + owner + '/' + repo + '/pulls', 'POST', {
|
||||
title: 'chore(ct): sync ' + slugValue + ' defaults with PocketBase',
|
||||
body: '## Summary\n- Sync default CT variables for `' + slugValue + '` after an `@pocketbase-bot` update.\n- Updated vars: `' + updateResult.updatedVars.join('`, `') + '`.\n\n## Source\n- Triggered by @' + actor + ' via PocketBase AI bot.\n',
|
||||
head: branchName,
|
||||
base: defaultBranch
|
||||
});
|
||||
if (!createPrRes.ok) throw new Error('Could not create PR: ' + createPrRes.body);
|
||||
return { status: 'created', prUrl: JSON.parse(createPrRes.body).html_url, updatedVars: updateResult.updatedVars };
|
||||
}
|
||||
|
||||
// ── Allow-lists (mirror the slash bot) ─────────────────────────────
|
||||
const ALLOWED_FIELDS = {
|
||||
name: 'string', description: 'string', logo: 'string', documentation: 'string',
|
||||
website: 'string', project_url: 'string', github: 'string', config_path: 'string',
|
||||
tags: 'string', port: 'number', default_user: 'nullable_string', default_passwd: 'nullable_string',
|
||||
unprivileged: 'number', updateable: 'boolean', privileged: 'boolean', has_arm: 'boolean',
|
||||
is_dev: 'boolean', is_disabled: 'boolean', disable_message: 'string',
|
||||
is_deleted: 'boolean', deleted_message: 'string'
|
||||
};
|
||||
const FIELD_TO_CT_VAR = { tags: 'var_tags', unprivileged: 'var_unprivileged' };
|
||||
const RESOURCE_KEYS = { cpu: 'number', ram: 'number', hdd: 'number', os: 'string', version: 'string' };
|
||||
const METHOD_KEYS = { config_path: 'string', script: 'string' };
|
||||
const ALL_METHOD_KEYS = Object.assign({}, RESOURCE_KEYS, METHOD_KEYS);
|
||||
const RESOURCE_TO_CT_VAR = { cpu: 'var_cpu', ram: 'var_ram', hdd: 'var_disk', os: 'var_os', version: 'var_version' };
|
||||
|
||||
function castFieldValue(key, rawVal) {
|
||||
const type = ALLOWED_FIELDS[key];
|
||||
if (!type) return { error: 'Unknown field `' + key + '`' };
|
||||
if (type === 'boolean') {
|
||||
if (rawVal === true || rawVal === 'true') return { value: true };
|
||||
if (rawVal === false || rawVal === 'false') return { value: false };
|
||||
return { error: '`' + key + '` must be true/false' };
|
||||
}
|
||||
if (type === 'number') {
|
||||
const n = parseInt(rawVal, 10);
|
||||
if (isNaN(n)) return { error: '`' + key + '` must be a number' };
|
||||
return { value: n };
|
||||
}
|
||||
if (type === 'nullable_string') return { value: rawVal === '' || rawVal == null ? null : String(rawVal) };
|
||||
return { value: String(rawVal) };
|
||||
}
|
||||
|
||||
// ── Operation validation (used at propose AND confirm time) ────────
|
||||
// Never trust raw operations: enforce the field/op allow-lists and
|
||||
// re-cast values. Returns only well-formed, allowed operations.
|
||||
function sanitizeOperations(ops) {
|
||||
const validOps = [], problems = [];
|
||||
for (const op of (Array.isArray(ops) ? ops : [])) {
|
||||
if (op && op.kind === 'field') {
|
||||
const cast = castFieldValue(op.field, op.value);
|
||||
if (cast.error) { problems.push(cast.error); continue; }
|
||||
validOps.push({ kind: 'field', field: op.field, value: cast.value });
|
||||
} else if (op && op.kind === 'note' && ['add', 'edit', 'remove'].includes(op.action)) {
|
||||
validOps.push({ kind: 'note', action: op.action, type: String(op.type || ''), text: op.text, newText: op.newText });
|
||||
} else if (op && op.kind === 'method' && ['add', 'edit', 'remove'].includes(op.action)) {
|
||||
const changes = {};
|
||||
for (const [k, v] of Object.entries(op.changes || {})) { if (ALL_METHOD_KEYS[k]) changes[k] = v; }
|
||||
validOps.push({ kind: 'method', action: op.action, type: String(op.type || 'default'), changes });
|
||||
} else {
|
||||
problems.push('Unsupported operation: `' + JSON.stringify(op) + '`');
|
||||
}
|
||||
}
|
||||
return { validOps, problems };
|
||||
}
|
||||
|
||||
// ── Executor: apply a validated {slug, operations} set ─────────────
|
||||
async function applyOperations(action) {
|
||||
const token = await pbAuth();
|
||||
const record = await pbFindRecord(token, action.slug);
|
||||
if (!record) return { ok: false, summary: '❌ No PocketBase record for slug `' + action.slug + '`.' };
|
||||
|
||||
const fieldPayload = {};
|
||||
let notesArr = readJsonBlob(record.notes);
|
||||
let methodsArr = readJsonBlob(record.install_methods);
|
||||
let notesChanged = false, methodsChanged = false;
|
||||
const ctChanges = {};
|
||||
const lines = [];
|
||||
|
||||
for (const op of action.operations) {
|
||||
if (op.kind === 'field') {
|
||||
const cast = castFieldValue(op.field, op.value);
|
||||
if (cast.error) { lines.push('- ⚠️ skipped field: ' + cast.error); continue; }
|
||||
fieldPayload[op.field] = cast.value;
|
||||
if (FIELD_TO_CT_VAR[op.field]) ctChanges[FIELD_TO_CT_VAR[op.field]] = cast.value;
|
||||
lines.push('- `' + op.field + '` → `' + JSON.stringify(cast.value) + '`');
|
||||
} else if (op.kind === 'note') {
|
||||
const type = String(op.type || '').toLowerCase();
|
||||
if (op.action === 'add') {
|
||||
notesArr.push({ type, text: String(op.text || '') });
|
||||
notesChanged = true; lines.push('- note add `' + type + '`: ' + op.text);
|
||||
} else if (op.action === 'remove') {
|
||||
const before = notesArr.length;
|
||||
notesArr = notesArr.filter(function (n) { return !(String(n.type).toLowerCase() === type && n.text === op.text); });
|
||||
if (notesArr.length !== before) { notesChanged = true; lines.push('- note remove `' + type + '`: ' + op.text); }
|
||||
else lines.push('- ⚠️ note remove: no `' + type + '` note matched');
|
||||
} else if (op.action === 'edit') {
|
||||
const idx = notesArr.findIndex(function (n) { return String(n.type).toLowerCase() === type && n.text === op.text; });
|
||||
if (idx !== -1) { notesArr[idx].text = String(op.newText || ''); notesChanged = true; lines.push('- note edit `' + type + '`'); }
|
||||
else lines.push('- ⚠️ note edit: no `' + type + '` note matched');
|
||||
}
|
||||
} else if (op.kind === 'method') {
|
||||
const type = String(op.type || '').toLowerCase();
|
||||
const changes = op.changes || {};
|
||||
if (op.action === 'remove') {
|
||||
const before = methodsArr.length;
|
||||
methodsArr = methodsArr.filter(function (im) { return String(im.type || '').toLowerCase() !== type; });
|
||||
if (methodsArr.length !== before) { methodsChanged = true; lines.push('- method remove `' + type + '`'); }
|
||||
else lines.push('- ⚠️ method remove: `' + type + '` not found');
|
||||
} else {
|
||||
let method = methodsArr.find(function (im) { return String(im.type || '').toLowerCase() === type; });
|
||||
if (!method && op.action === 'add') { method = { type, resources: { cpu: 1, ram: 512, hdd: 4, os: 'debian', version: '13' } }; methodsArr.push(method); }
|
||||
if (!method) { lines.push('- ⚠️ method edit: `' + type + '` not found'); continue; }
|
||||
if (!method.resources) method.resources = {};
|
||||
for (const [k, v] of Object.entries(changes)) {
|
||||
if (RESOURCE_KEYS[k]) {
|
||||
method.resources[k] = RESOURCE_KEYS[k] === 'number' ? parseInt(v, 10) : String(v);
|
||||
if (RESOURCE_TO_CT_VAR[k]) ctChanges[RESOURCE_TO_CT_VAR[k]] = method.resources[k];
|
||||
} else if (METHOD_KEYS[k]) {
|
||||
method[k] = v === '' ? null : String(v);
|
||||
}
|
||||
}
|
||||
methodsChanged = true;
|
||||
lines.push('- method `' + (op.action === 'add' ? 'add' : 'edit') + '` `' + type + '`: ' + JSON.stringify(changes));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.keys(fieldPayload).length) {
|
||||
const r = await pbPatch(token, record.id, fieldPayload);
|
||||
if (!r.ok) return { ok: false, summary: '❌ Field update failed:\n```\n' + r.body + '\n```' };
|
||||
}
|
||||
if (notesChanged) {
|
||||
const r = await pbPatch(token, record.id, { notes: notesArr });
|
||||
if (!r.ok) return { ok: false, summary: '❌ Notes update failed:\n```\n' + r.body + '\n```' };
|
||||
}
|
||||
if (methodsChanged) {
|
||||
const r = await pbPatch(token, record.id, { install_methods: methodsArr });
|
||||
if (!r.ok) return { ok: false, summary: '❌ Install-method update failed:\n```\n' + r.body + '\n```' };
|
||||
}
|
||||
await revalidate(action.slug);
|
||||
|
||||
let ctNote = '';
|
||||
if (Object.keys(ctChanges).length) {
|
||||
try {
|
||||
const sync = await upsertCtDefaultsPr(action.slug, ctChanges);
|
||||
if (sync.status === 'created') ctNote = '\n\n**CT sync PR:** ' + sync.prUrl;
|
||||
else if (sync.status === 'updated') ctNote = '\n\n**CT sync PR updated:** ' + sync.prUrl;
|
||||
else if (sync.status === 'skipped') ctNote = '\n\n**CT sync skipped:** ' + sync.reason;
|
||||
} catch (e) { ctNote = '\n\n**CT sync failed:** ' + e.message; }
|
||||
}
|
||||
return { ok: true, summary: lines.join('\n') + ctNote };
|
||||
}
|
||||
|
||||
// ── 4. Confirm branch ──────────────────────────────────────────────
|
||||
const PENDING_RE = /<!--\s*pocketbase-pending:\s*([A-Za-z0-9+/=]+)\s*-->/;
|
||||
const isConfirm = /^(confirm|yes|apply|do it|y)\b/i.test(instruction);
|
||||
|
||||
if (isConfirm) {
|
||||
const comments = await listIssueComments();
|
||||
const appId = String(process.env.PB_BOT_APP_ID || '');
|
||||
let pending = null, pendingComment = null;
|
||||
for (let i = comments.length - 1; i >= 0; i--) {
|
||||
const c = comments[i];
|
||||
// Only trust a marker in a comment THIS bot app authored — otherwise a
|
||||
// user could hand-craft a forged pocketbase-pending marker and confirm it.
|
||||
const byBotApp = c.user && c.user.type === 'Bot' &&
|
||||
c.performed_via_github_app && String(c.performed_via_github_app.id) === appId;
|
||||
if (!byBotApp) continue;
|
||||
const m = c.body && c.body.match(PENDING_RE);
|
||||
if (m) { pending = m[1]; pendingComment = c; break; }
|
||||
}
|
||||
if (!pending) {
|
||||
await addReaction('confused');
|
||||
await postComment('🤔 **PocketBase AI Bot**: I have no pending change to confirm in this thread.');
|
||||
return;
|
||||
}
|
||||
let action;
|
||||
try { action = JSON.parse(Buffer.from(pending, 'base64').toString('utf8')); }
|
||||
catch (e) { await postComment('❌ **PocketBase AI Bot**: Could not decode the pending change.'); return; }
|
||||
|
||||
// Re-validate the decoded operations before applying (defense-in-depth).
|
||||
const recheck = sanitizeOperations(action.operations);
|
||||
if (!action.slug || recheck.validOps.length === 0) {
|
||||
await addReaction('-1');
|
||||
await postComment('❌ **PocketBase AI Bot**: The pending change is no longer valid. Please restate the request.');
|
||||
return;
|
||||
}
|
||||
action.operations = recheck.validOps;
|
||||
|
||||
let result;
|
||||
try { result = await applyOperations(action); }
|
||||
catch (e) { await addReaction('-1'); await postComment('❌ **PocketBase AI Bot**: ' + e.message); return; }
|
||||
|
||||
if (!result.ok) { await addReaction('-1'); await postComment(result.summary); return; }
|
||||
await updateComment(pendingComment.id, pendingComment.body.replace(PENDING_RE, '<!-- pocketbase-applied -->'));
|
||||
await addReaction('+1');
|
||||
await postComment(
|
||||
'✅ **PocketBase AI Bot**: Applied to **`' + action.slug + '`**\n\n' + result.summary +
|
||||
'\n\n*Confirmed by @' + actor + '*'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// ── 5. New request: acknowledge, fetch script list, call the model ─
|
||||
await addReaction('eyes');
|
||||
|
||||
const token0 = await pbAuth();
|
||||
const scripts = [];
|
||||
let page = 1;
|
||||
while (page <= 5) {
|
||||
const res = await request(recordsUrl + '?fields=slug,name&perPage=500&page=' + page, { headers: { 'Authorization': token0 } });
|
||||
if (!res.ok) break;
|
||||
const data = JSON.parse(res.body);
|
||||
(data.items || []).forEach(function (it) { if (it.slug) scripts.push({ slug: it.slug, name: it.name || it.slug }); });
|
||||
if (!data.items || data.items.length < 500) break;
|
||||
page++;
|
||||
}
|
||||
|
||||
const SYSTEM_PROMPT =
|
||||
'You translate a maintainer\'s natural-language request into a STRICT JSON change-set for a ' +
|
||||
'script catalog (PocketBase). Respond with a SINGLE JSON object and nothing else.\n\n' +
|
||||
'Schema:\n' +
|
||||
'{\n' +
|
||||
' "slug": string|null, // MUST be one of the known slugs below, chosen from the request\n' +
|
||||
' "operations": [ ... ], // [] if you cannot determine concrete changes\n' +
|
||||
' "human_summary": string, // short plain-English description\n' +
|
||||
' "clarification": string|null // a question to ask if ambiguous/unsupported; else null\n' +
|
||||
'}\n\n' +
|
||||
'Operation kinds:\n' +
|
||||
'- {"kind":"field","field":<one of: ' + Object.keys(ALLOWED_FIELDS).join(', ') + '>,"value":<bool|number|string>}\n' +
|
||||
' (booleans true/false; "is_disabled"/"is_deleted"/"is_dev" are booleans; "port"/"unprivileged" are numbers; rest strings.)\n' +
|
||||
'- {"kind":"note","action":"add"|"edit"|"remove","type":string,"text":string,"newText":string?}\n' +
|
||||
'- {"kind":"method","action":"add"|"edit"|"remove","type":string,"changes":{cpu?:number,ram?:number,hdd?:number,os?:string,version?:string,config_path?:string,script?:string}}\n' +
|
||||
' (RAM/HDD are in MB/GB; method "type" defaults to "default" if the user does not name one.)\n\n' +
|
||||
'Rules:\n' +
|
||||
'- Only use fields/operations listed above. If the request needs something else, set clarification and operations=[].\n' +
|
||||
'- "disable"/"enable" map to is_disabled true/false. If disabling and the user gave a reason, also set disable_message.\n' +
|
||||
'- Resolve the target script to a slug from the list. If you cannot confidently match exactly one, set slug=null and ask via clarification.\n\n' +
|
||||
'Known scripts (slug — name):\n' +
|
||||
scripts.map(function (s) { return s.slug + ' — ' + s.name; }).join('\n');
|
||||
|
||||
const modelRes = await request('https://models.github.ai/inference/chat/completions', {
|
||||
method: 'POST',
|
||||
headers: { 'Authorization': 'Bearer ' + process.env.MODELS_TOKEN, 'Content-Type': 'application/json', 'Accept': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
model: process.env.AI_MODEL || 'openai/gpt-4o',
|
||||
temperature: 0.1,
|
||||
response_format: { type: 'json_object' },
|
||||
messages: [{ role: 'system', content: SYSTEM_PROMPT }, { role: 'user', content: instruction }]
|
||||
})
|
||||
});
|
||||
if (!modelRes.ok) {
|
||||
await addReaction('-1');
|
||||
await postComment('❌ **PocketBase AI Bot**: Model request failed (' + modelRes.statusCode + ').\n```\n' + modelRes.body.slice(0, 500) + '\n```');
|
||||
return;
|
||||
}
|
||||
|
||||
let parsed;
|
||||
try {
|
||||
const content = JSON.parse(modelRes.body).choices[0].message.content;
|
||||
const cleaned = content.replace(/^```(?:json)?\s*/i, '').replace(/```\s*$/i, '').trim();
|
||||
parsed = JSON.parse(cleaned);
|
||||
} catch (e) {
|
||||
await addReaction('-1');
|
||||
await postComment('❌ **PocketBase AI Bot**: Could not parse the model response. Please rephrase.');
|
||||
return;
|
||||
}
|
||||
|
||||
// ── 6. Validate ────────────────────────────────────────────────────
|
||||
const knownSlugs = new Set(scripts.map(function (s) { return s.slug; }));
|
||||
const problems = [];
|
||||
if (parsed.clarification) problems.push(parsed.clarification);
|
||||
if (!parsed.slug || !knownSlugs.has(parsed.slug)) problems.push('I could not match the request to a known script.');
|
||||
const sanitized = sanitizeOperations(parsed.operations);
|
||||
const validOps = sanitized.validOps;
|
||||
problems.push.apply(problems, sanitized.problems);
|
||||
if (validOps.length === 0) problems.push('No concrete, supported change was found.');
|
||||
|
||||
if (problems.length) {
|
||||
await addReaction('confused');
|
||||
await postComment(
|
||||
'🤔 **PocketBase AI Bot**: I need a bit more to act on that.\n\n- ' + problems.join('\n- ') +
|
||||
'\n\nTry naming the script and the exact change, e.g. `@pocketbase-bot set RAM to 4096 on zigbee2mqtt`.'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// ── 7. Propose (do NOT apply yet) ──────────────────────────────────
|
||||
const action = { slug: parsed.slug, operations: validOps };
|
||||
const bullets = validOps.map(function (op) {
|
||||
if (op.kind === 'field') return '- `' + op.field + '` → `' + JSON.stringify(op.value) + '`';
|
||||
if (op.kind === 'note') return '- note ' + op.action + ' `' + op.type + '`' + (op.text ? ': ' + op.text : '');
|
||||
return '- method ' + op.action + ' `' + op.type + '`: ' + JSON.stringify(op.changes);
|
||||
}).join('\n');
|
||||
const marker = '<!-- pocketbase-pending: ' + Buffer.from(JSON.stringify(action), 'utf8').toString('base64') + ' -->';
|
||||
await addReaction('+1');
|
||||
await postComment(
|
||||
'🤖 **PocketBase AI Bot** — please confirm\n\n' +
|
||||
(parsed.human_summary ? '> ' + parsed.human_summary + '\n\n' : '') +
|
||||
'**Target:** `' + action.slug + '`\n**Proposed changes:**\n' + bullets + '\n\n' +
|
||||
'Reply **`@pocketbase-bot confirm`** to apply, or restate the request to adjust.\n' + marker
|
||||
);
|
||||
})().catch(function (e) {
|
||||
console.error('Fatal error:', e && (e.message || e));
|
||||
process.exit(1);
|
||||
});
|
||||
ENDSCRIPT
|
||||
Generated
+500
-182
@@ -7,14 +7,14 @@ on:
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
contents: read
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
pocketbase-bot:
|
||||
runs-on: self-hosted
|
||||
|
||||
# Only act on /pocketbase commands
|
||||
if: startsWith(github.event.comment.body, '/pocketbase')
|
||||
# Act on comments that contain a /pocketbase command line (precise line check happens in-script)
|
||||
if: contains(github.event.comment.body, '/pocketbase')
|
||||
|
||||
steps:
|
||||
- name: Execute PocketBase bot command
|
||||
@@ -31,6 +31,8 @@ jobs:
|
||||
ACTOR: ${{ github.event.comment.user.login }}
|
||||
ACTOR_ASSOCIATION: ${{ github.event.comment.author_association }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
FRONTEND_URL: ${{ secrets.FRONTEND_URL }}
|
||||
REVALIDATE_SECRET: ${{ secrets.REVALIDATE_SECRET }}
|
||||
run: |
|
||||
node << 'ENDSCRIPT'
|
||||
(async function () {
|
||||
@@ -93,6 +95,149 @@ jobs:
|
||||
return request('https://api.github.com' + path, { method: method || 'GET', headers, body: bodyStr });
|
||||
}
|
||||
|
||||
function encodeContentPath(filePath) {
|
||||
return filePath.split('/').map(encodeURIComponent).join('/');
|
||||
}
|
||||
|
||||
function decodeGitHubContent(content) {
|
||||
return Buffer.from((content || '').replace(/\n/g, ''), 'base64').toString('utf8');
|
||||
}
|
||||
|
||||
function sanitizeBranchPart(value) {
|
||||
return (value || '')
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9._/-]+/g, '-')
|
||||
.replace(/\/+/g, '/')
|
||||
.replace(/^-+|-+$/g, '');
|
||||
}
|
||||
|
||||
function applyCtDefaultChanges(scriptText, varChanges) {
|
||||
let nextText = scriptText;
|
||||
const updatedVars = [];
|
||||
const unchangedVars = [];
|
||||
for (const [varName, rawValue] of Object.entries(varChanges)) {
|
||||
const newValue = String(rawValue);
|
||||
const pattern = new RegExp('(^\\s*' + varName + '="\\$\\{' + varName + ':-)([^"}]*)(\\}"\\s*$)', 'm');
|
||||
const match = nextText.match(pattern);
|
||||
if (!match) continue;
|
||||
if (match[2] === newValue) {
|
||||
unchangedVars.push(varName);
|
||||
continue;
|
||||
}
|
||||
nextText = nextText.replace(pattern, '$1' + newValue + '$3');
|
||||
updatedVars.push(varName);
|
||||
}
|
||||
return { nextText, updatedVars, unchangedVars };
|
||||
}
|
||||
|
||||
async function ensureBranch(defaultBranch, branchName) {
|
||||
const branchRefRes = await ghRequest('/repos/' + owner + '/' + repo + '/git/ref/heads/' + encodeURIComponent(branchName));
|
||||
if (branchRefRes.ok) return;
|
||||
|
||||
const defaultRefRes = await ghRequest('/repos/' + owner + '/' + repo + '/git/ref/heads/' + encodeURIComponent(defaultBranch));
|
||||
if (!defaultRefRes.ok) {
|
||||
throw new Error('Could not read default branch ref: ' + defaultRefRes.body);
|
||||
}
|
||||
const defaultRef = JSON.parse(defaultRefRes.body);
|
||||
const createBranchRes = await ghRequest('/repos/' + owner + '/' + repo + '/git/refs', 'POST', {
|
||||
ref: 'refs/heads/' + branchName,
|
||||
sha: defaultRef.object.sha
|
||||
});
|
||||
if (!createBranchRes.ok) {
|
||||
throw new Error('Could not create branch: ' + createBranchRes.body);
|
||||
}
|
||||
}
|
||||
|
||||
async function upsertCtDefaultsPr(slugValue, varChanges) {
|
||||
const wantedEntries = Object.entries(varChanges || {}).filter(function ([, v]) {
|
||||
return v !== undefined && v !== null && String(v) !== '';
|
||||
});
|
||||
if (wantedEntries.length === 0) {
|
||||
return { status: 'skipped', reason: 'No mapped CT defaults changed.' };
|
||||
}
|
||||
|
||||
const repoRes = await ghRequest('/repos/' + owner + '/' + repo);
|
||||
if (!repoRes.ok) {
|
||||
throw new Error('Could not read repository metadata: ' + repoRes.body);
|
||||
}
|
||||
const repoInfo = JSON.parse(repoRes.body);
|
||||
const defaultBranch = repoInfo.default_branch;
|
||||
|
||||
const ctPath = 'ct/' + slugValue + '.sh';
|
||||
const encodedCtPath = encodeContentPath(ctPath);
|
||||
const defaultFileRes = await ghRequest('/repos/' + owner + '/' + repo + '/contents/' + encodedCtPath + '?ref=' + encodeURIComponent(defaultBranch));
|
||||
if (defaultFileRes.statusCode === 404) {
|
||||
return { status: 'skipped', reason: 'No matching CT file found at `' + ctPath + '`.' };
|
||||
}
|
||||
if (!defaultFileRes.ok) {
|
||||
throw new Error('Could not read CT file from default branch: ' + defaultFileRes.body);
|
||||
}
|
||||
|
||||
const branchName = 'pocketbase-sync/' + sanitizeBranchPart(slugValue || 'unknown');
|
||||
await ensureBranch(defaultBranch, branchName);
|
||||
|
||||
const branchFileRes = await ghRequest('/repos/' + owner + '/' + repo + '/contents/' + encodedCtPath + '?ref=' + encodeURIComponent(branchName));
|
||||
if (!branchFileRes.ok) {
|
||||
throw new Error('Could not read CT file from sync branch: ' + branchFileRes.body);
|
||||
}
|
||||
const branchFile = JSON.parse(branchFileRes.body);
|
||||
const currentBranchText = decodeGitHubContent(branchFile.content);
|
||||
|
||||
const updateResult = applyCtDefaultChanges(currentBranchText, Object.fromEntries(wantedEntries));
|
||||
if (updateResult.updatedVars.length === 0) {
|
||||
return { status: 'skipped', reason: 'CT defaults already up to date.', unchangedVars: updateResult.unchangedVars };
|
||||
}
|
||||
|
||||
const commitMessage = 'chore(ct): sync ' + slugValue + ' defaults from PocketBase';
|
||||
const putRes = await ghRequest('/repos/' + owner + '/' + repo + '/contents/' + encodedCtPath, 'PUT', {
|
||||
message: commitMessage,
|
||||
content: Buffer.from(updateResult.nextText, 'utf8').toString('base64'),
|
||||
sha: branchFile.sha,
|
||||
branch: branchName
|
||||
});
|
||||
if (!putRes.ok) {
|
||||
throw new Error('Could not update CT file: ' + putRes.body);
|
||||
}
|
||||
|
||||
const openPrRes = await ghRequest(
|
||||
'/repos/' + owner + '/' + repo + '/pulls?state=open&head=' + encodeURIComponent(owner + ':' + branchName) + '&base=' + encodeURIComponent(defaultBranch)
|
||||
);
|
||||
if (!openPrRes.ok) {
|
||||
throw new Error('Could not query existing PRs: ' + openPrRes.body);
|
||||
}
|
||||
const openPrs = JSON.parse(openPrRes.body);
|
||||
if (openPrs.length > 0) {
|
||||
return { status: 'updated', prUrl: openPrs[0].html_url, updatedVars: updateResult.updatedVars };
|
||||
}
|
||||
|
||||
const prTitle = 'chore(ct): sync ' + slugValue + ' defaults with PocketBase';
|
||||
const prBody =
|
||||
'## Summary\n' +
|
||||
'- Sync default CT variables for `' + slugValue + '` after `/pocketbase` update.\n' +
|
||||
'- Updated vars: `' + updateResult.updatedVars.join('`, `') + '`.\n\n' +
|
||||
'## Source\n' +
|
||||
'- Triggered by @' + actor + ' via PocketBase bot.\n';
|
||||
const createPrRes = await ghRequest('/repos/' + owner + '/' + repo + '/pulls', 'POST', {
|
||||
title: prTitle,
|
||||
body: prBody,
|
||||
head: branchName,
|
||||
base: defaultBranch
|
||||
});
|
||||
if (!createPrRes.ok) {
|
||||
throw new Error('Could not create PR: ' + createPrRes.body);
|
||||
}
|
||||
const pr = JSON.parse(createPrRes.body);
|
||||
return { status: 'created', prUrl: pr.html_url, updatedVars: updateResult.updatedVars };
|
||||
}
|
||||
|
||||
function formatCtSyncResult(syncResult) {
|
||||
if (!syncResult) return '';
|
||||
if (syncResult.status === 'created') return '\n\n**CT sync PR:** ' + syncResult.prUrl;
|
||||
if (syncResult.status === 'updated') return '\n\n**CT sync PR updated:** ' + syncResult.prUrl;
|
||||
if (syncResult.status === 'skipped') return '\n\n**CT sync skipped:** ' + syncResult.reason;
|
||||
return '';
|
||||
}
|
||||
|
||||
async function addReaction(content) {
|
||||
try {
|
||||
await ghRequest(
|
||||
@@ -112,8 +257,23 @@ jobs:
|
||||
if (!res.ok) console.warn('Could not post comment:', res.body);
|
||||
}
|
||||
|
||||
// ── Locate the command line ────────────────────────────────────────
|
||||
// Accept /pocketbase at the start of ANY line (leading whitespace ok),
|
||||
// so the command works even when preceded by other text. Mid-sentence
|
||||
// mentions and blockquoted ("> ...") examples are ignored.
|
||||
const commentBody = process.env.COMMENT_BODY || '';
|
||||
const cmdLine = commentBody
|
||||
.split('\n')
|
||||
.map(l => l.trim())
|
||||
.find(l => l.startsWith('/pocketbase'));
|
||||
|
||||
if (!cmdLine) {
|
||||
console.log('No /pocketbase command line found — ignoring comment.');
|
||||
process.exit(0);
|
||||
}
|
||||
const withoutCmd = cmdLine.replace(/^\/pocketbase\s*/, '').trim();
|
||||
|
||||
// ── Permission check ───────────────────────────────────────────────
|
||||
// author_association: OWNER = repo/org owner, MEMBER = org member (includes Contributors team)
|
||||
const association = process.env.ACTOR_ASSOCIATION;
|
||||
if (association !== 'OWNER' && association !== 'MEMBER') {
|
||||
await addReaction('-1');
|
||||
@@ -128,18 +288,7 @@ jobs:
|
||||
await addReaction('eyes');
|
||||
|
||||
// ── Parse command ──────────────────────────────────────────────────
|
||||
// Formats (first line of comment):
|
||||
// /pocketbase <slug> field=value [field=value ...] ← field updates (simple values)
|
||||
// /pocketbase <slug> set <field> ← value from code block below
|
||||
// /pocketbase <slug> note list|add|edit|remove ... ← note management
|
||||
// /pocketbase <slug> method list ← list install methods
|
||||
// /pocketbase <slug> method <type> cpu=N ram=N hdd=N ← edit install method resources
|
||||
const commentBody = process.env.COMMENT_BODY || '';
|
||||
const lines = commentBody.trim().split('\n');
|
||||
const firstLine = lines[0].trim();
|
||||
const withoutCmd = firstLine.replace(/^\/pocketbase\s+/, '').trim();
|
||||
|
||||
// Extract code block content from comment body (```...``` or ```lang\n...```)
|
||||
function extractCodeBlock(body) {
|
||||
const m = body.match(/```[^\n]*\n([\s\S]*?)```/);
|
||||
return m ? m[1].trim() : null;
|
||||
@@ -147,6 +296,8 @@ jobs:
|
||||
const codeBlockValue = extractCodeBlock(commentBody);
|
||||
|
||||
const HELP_TEXT =
|
||||
'**Show current state:**\n' +
|
||||
'```\n/pocketbase <slug> info\n```\n\n' +
|
||||
'**Field update (simple):** `/pocketbase <slug> field=value [field=value ...]`\n\n' +
|
||||
'**Field update (HTML/multiline) — value from code block:**\n' +
|
||||
'````\n' +
|
||||
@@ -162,12 +313,16 @@ jobs:
|
||||
'/pocketbase <slug> note edit <type> "<old text>" "<new text>"\n' +
|
||||
'/pocketbase <slug> note remove <type> "<text>"\n' +
|
||||
'```\n\n' +
|
||||
'**Install method resources:**\n' +
|
||||
'**Install method management:**\n' +
|
||||
'```\n' +
|
||||
'/pocketbase <slug> method list\n' +
|
||||
'/pocketbase <slug> method <type> hdd=10\n' +
|
||||
'/pocketbase <slug> method <type> cpu=4 ram=2048 hdd=20\n' +
|
||||
'```\n\n' +
|
||||
'/pocketbase <slug> method <type> config_path="/opt/app/.env"\n' +
|
||||
'/pocketbase <slug> method <type> os=debian version=13\n' +
|
||||
'/pocketbase <slug> method add <type> cpu=2 ram=2048 hdd=8 os=debian version=13\n' +
|
||||
'/pocketbase <slug> method remove <type>\n' +
|
||||
'```\n' +
|
||||
'Method fields: `cpu` `ram` `hdd` `os` `version` `config_path` `script`\n\n' +
|
||||
'**Editable fields:** `name` `description` `logo` `documentation` `website` `project_url` `github` ' +
|
||||
'`config_path` `port` `default_user` `default_passwd` ' +
|
||||
'`updateable` `privileged` `has_arm` `is_dev` ' +
|
||||
@@ -189,8 +344,7 @@ jobs:
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// ── Allowed fields and their types ─────────────────────────────────
|
||||
// ── PocketBase: authenticate (shared by all paths) ─────────────────
|
||||
// ── PocketBase: authenticate ───────────────────────────────────────
|
||||
const raw = process.env.POCKETBASE_URL.replace(/\/$/, '');
|
||||
const apiBase = /\/api$/i.test(raw) ? raw : raw + '/api';
|
||||
const coll = process.env.POCKETBASE_COLLECTION;
|
||||
@@ -210,7 +364,7 @@ jobs:
|
||||
}
|
||||
const token = JSON.parse(authRes.body).token;
|
||||
|
||||
// ── PocketBase: find record by slug (shared by all paths) ──────────
|
||||
// ── PocketBase: find record by slug ────────────────────────────────
|
||||
const recordsUrl = apiBase + '/collections/' + encodeURIComponent(coll) + '/records';
|
||||
const filter = "(slug='" + slug.replace(/'/g, "''") + "')";
|
||||
const listRes = await request(recordsUrl + '?filter=' + encodeURIComponent(filter) + '&perPage=1', {
|
||||
@@ -228,65 +382,172 @@ jobs:
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// ── Shared helpers ─────────────────────────────────────────────────
|
||||
|
||||
// Key=value parser: handles unquoted and "quoted" values
|
||||
function parseKVPairs(str) {
|
||||
const fields = {};
|
||||
let pos = 0;
|
||||
while (pos < str.length) {
|
||||
while (pos < str.length && /\s/.test(str[pos])) pos++;
|
||||
if (pos >= str.length) break;
|
||||
let keyStart = pos;
|
||||
while (pos < str.length && str[pos] !== '=' && !/\s/.test(str[pos])) pos++;
|
||||
const key = str.substring(keyStart, pos).trim();
|
||||
if (!key || pos >= str.length || str[pos] !== '=') { pos++; continue; }
|
||||
pos++;
|
||||
let value;
|
||||
if (pos < str.length && str[pos] === '"') {
|
||||
pos++;
|
||||
let valStart = pos;
|
||||
while (pos < str.length && str[pos] !== '"') {
|
||||
if (str[pos] === '\\') pos++;
|
||||
pos++;
|
||||
}
|
||||
value = str.substring(valStart, pos).replace(/\\"/g, '"');
|
||||
if (pos < str.length) pos++;
|
||||
} else {
|
||||
let valStart = pos;
|
||||
while (pos < str.length && !/\s/.test(str[pos])) pos++;
|
||||
value = str.substring(valStart, pos);
|
||||
}
|
||||
fields[key] = value;
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
|
||||
// Token parser for note commands: unquoted-word OR "quoted string"
|
||||
function parseTokens(str) {
|
||||
const tokens = [];
|
||||
let pos = 0;
|
||||
while (pos < str.length) {
|
||||
while (pos < str.length && /\s/.test(str[pos])) pos++;
|
||||
if (pos >= str.length) break;
|
||||
if (str[pos] === '"') {
|
||||
pos++;
|
||||
let start = pos;
|
||||
while (pos < str.length && str[pos] !== '"') {
|
||||
if (str[pos] === '\\') pos++;
|
||||
pos++;
|
||||
}
|
||||
tokens.push(str.substring(start, pos).replace(/\\"/g, '"'));
|
||||
if (pos < str.length) pos++;
|
||||
} else {
|
||||
let start = pos;
|
||||
while (pos < str.length && !/\s/.test(str[pos])) pos++;
|
||||
tokens.push(str.substring(start, pos));
|
||||
}
|
||||
}
|
||||
return tokens;
|
||||
}
|
||||
|
||||
// Read JSON blob from record (handles parsed objects and strings)
|
||||
function readJsonBlob(val) {
|
||||
if (Array.isArray(val)) return val;
|
||||
try { return JSON.parse(val || '[]'); } catch (e) { return []; }
|
||||
}
|
||||
|
||||
// Frontend cache revalidation (silent, best-effort)
|
||||
async function revalidate(s) {
|
||||
const frontendUrl = process.env.FRONTEND_URL;
|
||||
const secret = process.env.REVALIDATE_SECRET;
|
||||
if (!frontendUrl || !secret) return;
|
||||
try {
|
||||
await request(frontendUrl.replace(/\/$/, '') + '/api/revalidate', {
|
||||
method: 'POST',
|
||||
headers: { 'Authorization': 'Bearer ' + secret, 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ tags: ['scripts', 'script-' + s] })
|
||||
});
|
||||
} catch (e) { console.warn('Revalidation skipped:', e.message); }
|
||||
}
|
||||
|
||||
// Format notes list for display
|
||||
function formatNotesList(arr) {
|
||||
if (arr.length === 0) return '*None*';
|
||||
return arr.map(function (n, i) {
|
||||
return (i + 1) + '. **`' + (n.type || '?') + '`**: ' + (n.text || '');
|
||||
}).join('\n');
|
||||
}
|
||||
|
||||
// Format install methods list for display
|
||||
function formatMethodsList(arr) {
|
||||
if (arr.length === 0) return '*None*';
|
||||
return arr.map(function (im, i) {
|
||||
const r = im.resources || {};
|
||||
const parts = [
|
||||
(r.os || '?') + ' ' + (r.version || '?'),
|
||||
(r.cpu != null ? r.cpu : '?') + 'C / ' + (r.ram != null ? r.ram : '?') + ' MB / ' + (r.hdd != null ? r.hdd : '?') + ' GB'
|
||||
];
|
||||
if (im.config_path) parts.push('config: `' + im.config_path + '`');
|
||||
if (im.script) parts.push('script: `' + im.script + '`');
|
||||
return (i + 1) + '. **`' + (im.type || '?') + '`** — ' + parts.join(', ');
|
||||
}).join('\n');
|
||||
}
|
||||
|
||||
// ── Route: dispatch to subcommand handler ──────────────────────────
|
||||
const infoMatch = rest.match(/^info$/i);
|
||||
const noteMatch = rest.match(/^note\s+(list|add|edit|remove)\b/i);
|
||||
const methodMatch = rest.match(/^method\b/i);
|
||||
const setMatch = rest.match(/^set\s+(\S+)/i);
|
||||
|
||||
if (noteMatch) {
|
||||
// ── NOTE SUBCOMMAND (reads/writes notes_json on script record) ────
|
||||
if (infoMatch) {
|
||||
// ── INFO SUBCOMMAND ──────────────────────────────────────────────
|
||||
const notesArr = readJsonBlob(record.notes);
|
||||
const methodsArr = readJsonBlob(record.install_methods);
|
||||
|
||||
const out = [];
|
||||
out.push('ℹ️ **PocketBase Bot**: Info for **`' + slug + '`**\n');
|
||||
|
||||
out.push('**Basic info:**');
|
||||
out.push('- **Name:** ' + (record.name || '—'));
|
||||
out.push('- **Slug:** `' + slug + '`');
|
||||
out.push('- **Port:** ' + (record.port != null ? '`' + record.port + '`' : '—'));
|
||||
out.push('- **Updateable:** ' + (record.updateable ? 'Yes' : 'No'));
|
||||
out.push('- **Privileged:** ' + (record.privileged ? 'Yes' : 'No'));
|
||||
out.push('- **ARM:** ' + (record.has_arm ? 'Yes' : 'No'));
|
||||
if (record.is_dev) out.push('- **Dev:** Yes');
|
||||
if (record.is_disabled) out.push('- **Disabled:** Yes' + (record.disable_message ? ' — ' + record.disable_message : ''));
|
||||
if (record.is_deleted) out.push('- **Deleted:** Yes' + (record.deleted_message ? ' — ' + record.deleted_message : ''));
|
||||
out.push('');
|
||||
|
||||
out.push('**Links:**');
|
||||
out.push('- **Website:** ' + (record.website || '—'));
|
||||
out.push('- **Docs:** ' + (record.documentation || '—'));
|
||||
out.push('- **Logo:** ' + (record.logo ? '[link](' + record.logo + ')' : '—'));
|
||||
out.push('- **GitHub:** ' + (record.github || '—'));
|
||||
if (record.config_path) out.push('- **Config:** `' + record.config_path + '`');
|
||||
out.push('');
|
||||
|
||||
out.push('**Credentials:**');
|
||||
out.push('- **User:** ' + (record.default_user || '—'));
|
||||
out.push('- **Password:** ' + (record.default_passwd ? '*(set)*' : '—'));
|
||||
out.push('');
|
||||
|
||||
out.push('**Install methods** (' + methodsArr.length + '):');
|
||||
out.push(formatMethodsList(methodsArr));
|
||||
out.push('');
|
||||
|
||||
out.push('**Notes** (' + notesArr.length + '):');
|
||||
out.push(formatNotesList(notesArr));
|
||||
|
||||
await addReaction('+1');
|
||||
await postComment(out.join('\n'));
|
||||
|
||||
} else if (noteMatch) {
|
||||
// ── NOTE SUBCOMMAND ──────────────────────────────────────────────
|
||||
const noteAction = noteMatch[1].toLowerCase();
|
||||
const noteArgsStr = rest.substring(noteMatch[0].length).trim();
|
||||
let notesArr = readJsonBlob(record.notes);
|
||||
|
||||
// Parse notes_json from the already-fetched script record
|
||||
// PocketBase may return JSON fields as already-parsed objects
|
||||
let notesArr = [];
|
||||
try {
|
||||
const rawNotes = record.notes_json;
|
||||
notesArr = Array.isArray(rawNotes) ? rawNotes : JSON.parse(rawNotes || '[]');
|
||||
} catch (e) { notesArr = []; }
|
||||
|
||||
// Token parser: unquoted-word OR "quoted string" (supports \" escapes)
|
||||
function parseNoteTokens(str) {
|
||||
const tokens = [];
|
||||
let pos = 0;
|
||||
while (pos < str.length) {
|
||||
while (pos < str.length && /\s/.test(str[pos])) pos++;
|
||||
if (pos >= str.length) break;
|
||||
if (str[pos] === '"') {
|
||||
pos++;
|
||||
let start = pos;
|
||||
while (pos < str.length && str[pos] !== '"') {
|
||||
if (str[pos] === '\\') pos++;
|
||||
pos++;
|
||||
}
|
||||
tokens.push(str.substring(start, pos).replace(/\\"/g, '"'));
|
||||
if (pos < str.length) pos++;
|
||||
} else {
|
||||
let start = pos;
|
||||
while (pos < str.length && !/\s/.test(str[pos])) pos++;
|
||||
tokens.push(str.substring(start, pos));
|
||||
}
|
||||
}
|
||||
return tokens;
|
||||
}
|
||||
|
||||
function formatNotesList(arr) {
|
||||
if (arr.length === 0) return '*None*';
|
||||
return arr.map(function (n, i) {
|
||||
return (i + 1) + '. **`' + (n.type || '?') + '`**: ' + (n.text || '');
|
||||
}).join('\n');
|
||||
}
|
||||
|
||||
async function patchNotesJson(arr) {
|
||||
async function patchNotes(arr) {
|
||||
const res = await request(recordsUrl + '/' + record.id, {
|
||||
method: 'PATCH',
|
||||
headers: { 'Authorization': token, 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ notes_json: JSON.stringify(arr) })
|
||||
body: JSON.stringify({ notes: arr })
|
||||
});
|
||||
if (!res.ok) {
|
||||
await addReaction('-1');
|
||||
await postComment('❌ **PocketBase Bot**: Failed to update `notes_json`:\n```\n' + res.body + '\n```');
|
||||
await postComment('❌ **PocketBase Bot**: Failed to update notes:\n```\n' + res.body + '\n```');
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
@@ -299,7 +560,7 @@ jobs:
|
||||
);
|
||||
|
||||
} else if (noteAction === 'add') {
|
||||
const tokens = parseNoteTokens(noteArgsStr);
|
||||
const tokens = parseTokens(noteArgsStr);
|
||||
if (tokens.length < 2) {
|
||||
await addReaction('-1');
|
||||
await postComment(
|
||||
@@ -311,7 +572,8 @@ jobs:
|
||||
const noteType = tokens[0].toLowerCase();
|
||||
const noteText = tokens.slice(1).join(' ');
|
||||
notesArr.push({ type: noteType, text: noteText });
|
||||
await patchNotesJson(notesArr);
|
||||
await patchNotes(notesArr);
|
||||
await revalidate(slug);
|
||||
await addReaction('+1');
|
||||
await postComment(
|
||||
'✅ **PocketBase Bot**: Added note to **`' + slug + '`**\n\n' +
|
||||
@@ -321,7 +583,7 @@ jobs:
|
||||
);
|
||||
|
||||
} else if (noteAction === 'edit') {
|
||||
const tokens = parseNoteTokens(noteArgsStr);
|
||||
const tokens = parseTokens(noteArgsStr);
|
||||
if (tokens.length < 3) {
|
||||
await addReaction('-1');
|
||||
await postComment(
|
||||
@@ -346,7 +608,8 @@ jobs:
|
||||
process.exit(0);
|
||||
}
|
||||
notesArr[idx].text = newText;
|
||||
await patchNotesJson(notesArr);
|
||||
await patchNotes(notesArr);
|
||||
await revalidate(slug);
|
||||
await addReaction('+1');
|
||||
await postComment(
|
||||
'✅ **PocketBase Bot**: Edited note in **`' + slug + '`**\n\n' +
|
||||
@@ -357,7 +620,7 @@ jobs:
|
||||
);
|
||||
|
||||
} else if (noteAction === 'remove') {
|
||||
const tokens = parseNoteTokens(noteArgsStr);
|
||||
const tokens = parseTokens(noteArgsStr);
|
||||
if (tokens.length < 2) {
|
||||
await addReaction('-1');
|
||||
await postComment(
|
||||
@@ -381,7 +644,8 @@ jobs:
|
||||
);
|
||||
process.exit(0);
|
||||
}
|
||||
await patchNotesJson(notesArr);
|
||||
await patchNotes(notesArr);
|
||||
await revalidate(slug);
|
||||
await addReaction('+1');
|
||||
await postComment(
|
||||
'✅ **PocketBase Bot**: Removed note from **`' + slug + '`**\n\n' +
|
||||
@@ -392,36 +656,37 @@ jobs:
|
||||
}
|
||||
|
||||
} else if (methodMatch) {
|
||||
// ── METHOD SUBCOMMAND (reads/writes install_methods_json on script record) ──
|
||||
// ── METHOD SUBCOMMAND ────────────────────────────────────────────
|
||||
const methodArgs = rest.replace(/^method\s*/i, '').trim();
|
||||
const methodListMode = !methodArgs || methodArgs.toLowerCase() === 'list';
|
||||
let methodsArr = readJsonBlob(record.install_methods);
|
||||
|
||||
// Parse install_methods_json from the already-fetched script record
|
||||
// PocketBase may return JSON fields as already-parsed objects
|
||||
let methodsArr = [];
|
||||
try {
|
||||
const rawMethods = record.install_methods_json;
|
||||
methodsArr = Array.isArray(rawMethods) ? rawMethods : JSON.parse(rawMethods || '[]');
|
||||
} catch (e) { methodsArr = []; }
|
||||
// Method field classification
|
||||
const RESOURCE_KEYS = { cpu: 'number', ram: 'number', hdd: 'number', os: 'string', version: 'string' };
|
||||
const METHOD_KEYS = { config_path: 'string', script: 'string' };
|
||||
const ALL_METHOD_KEYS = Object.assign({}, RESOURCE_KEYS, METHOD_KEYS);
|
||||
const RESOURCE_TO_CT_VAR = { cpu: 'var_cpu', ram: 'var_ram', hdd: 'var_disk', os: 'var_os', version: 'var_version' };
|
||||
|
||||
function formatMethodsList(arr) {
|
||||
if (arr.length === 0) return '*None*';
|
||||
return arr.map(function (im, i) {
|
||||
const r = im.resources || {};
|
||||
return (i + 1) + '. **`' + (im.type || '?') + '`** — CPU: `' + (r.cpu != null ? r.cpu : '?') +
|
||||
'` · RAM: `' + (r.ram != null ? r.ram : '?') + ' MB` · HDD: `' + (r.hdd != null ? r.hdd : '?') + ' GB`';
|
||||
}).join('\n');
|
||||
function applyMethodChanges(method, parsed) {
|
||||
if (!method.resources) method.resources = {};
|
||||
for (const [k, v] of Object.entries(parsed)) {
|
||||
if (RESOURCE_KEYS[k]) {
|
||||
method.resources[k] = RESOURCE_KEYS[k] === 'number' ? parseInt(v, 10) : v;
|
||||
} else if (METHOD_KEYS[k]) {
|
||||
method[k] = v === '' ? null : v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function patchInstallMethodsJson(arr) {
|
||||
async function patchMethods(arr) {
|
||||
const res = await request(recordsUrl + '/' + record.id, {
|
||||
method: 'PATCH',
|
||||
headers: { 'Authorization': token, 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ install_methods_json: JSON.stringify(arr) })
|
||||
body: JSON.stringify({ install_methods: arr })
|
||||
});
|
||||
if (!res.ok) {
|
||||
await addReaction('-1');
|
||||
await postComment('❌ **PocketBase Bot**: Failed to update `install_methods_json`:\n```\n' + res.body + '\n```');
|
||||
await postComment('❌ **PocketBase Bot**: Failed to update install methods:\n```\n' + res.body + '\n```');
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
@@ -432,70 +697,144 @@ jobs:
|
||||
'ℹ️ **PocketBase Bot**: Install methods for **`' + slug + '`** (' + methodsArr.length + ' total)\n\n' +
|
||||
formatMethodsList(methodsArr)
|
||||
);
|
||||
|
||||
} else {
|
||||
// Parse: <type> cpu=N ram=N hdd=N
|
||||
const methodParts = methodArgs.match(/^(\S+)\s+(.+)$/);
|
||||
if (!methodParts) {
|
||||
await addReaction('-1');
|
||||
// Check for add / remove sub-actions
|
||||
const addMatch = methodArgs.match(/^add\s+(\S+)(?:\s+(.+))?$/i);
|
||||
const removeMatch = methodArgs.match(/^remove\s+(\S+)$/i);
|
||||
|
||||
if (addMatch) {
|
||||
// ── METHOD ADD ───────────────────────────────────────────────
|
||||
const newType = addMatch[1];
|
||||
const parsed = addMatch[2] ? parseKVPairs(addMatch[2]) : {};
|
||||
if (methodsArr.some(function (im) { return (im.type || '').toLowerCase() === newType.toLowerCase(); })) {
|
||||
await addReaction('-1');
|
||||
await postComment('❌ **PocketBase Bot**: Install method `' + newType + '` already exists for `' + slug + '`.\n\nUse `/pocketbase ' + slug + ' method list` to see all methods.');
|
||||
process.exit(0);
|
||||
}
|
||||
const newMethod = { type: newType, resources: { cpu: 1, ram: 512, hdd: 4, os: 'debian', version: '13' } };
|
||||
if (addMatch[2]) {
|
||||
const unknown = Object.keys(parsed).filter(function (k) { return !ALL_METHOD_KEYS[k]; });
|
||||
if (unknown.length > 0) {
|
||||
await addReaction('-1');
|
||||
await postComment('❌ **PocketBase Bot**: Unknown method field(s): `' + unknown.join('`, `') + '`\n\n**Allowed:** `' + Object.keys(ALL_METHOD_KEYS).join('`, `') + '`');
|
||||
process.exit(0);
|
||||
}
|
||||
applyMethodChanges(newMethod, parsed);
|
||||
}
|
||||
methodsArr.push(newMethod);
|
||||
await patchMethods(methodsArr);
|
||||
await revalidate(slug);
|
||||
const addCtChanges = {};
|
||||
for (const [k, v] of Object.entries(parsed)) {
|
||||
if (RESOURCE_TO_CT_VAR[k]) addCtChanges[RESOURCE_TO_CT_VAR[k]] = v;
|
||||
}
|
||||
let addCtSync = null;
|
||||
try {
|
||||
addCtSync = await upsertCtDefaultsPr(slug, addCtChanges);
|
||||
} catch (e) {
|
||||
addCtSync = { status: 'skipped', reason: 'CT sync failed: ' + e.message };
|
||||
}
|
||||
await addReaction('+1');
|
||||
await postComment(
|
||||
'❌ **PocketBase Bot**: Invalid `method` syntax.\n\n' +
|
||||
'**Usage:**\n```\n/pocketbase ' + slug + ' method list\n/pocketbase ' + slug + ' method <type> hdd=10\n/pocketbase ' + slug + ' method <type> cpu=4 ram=2048 hdd=20\n```'
|
||||
'✅ **PocketBase Bot**: Added install method **`' + newType + '`** to **`' + slug + '`**\n\n' +
|
||||
formatMethodsList([newMethod]) + '\n\n' +
|
||||
formatCtSyncResult(addCtSync) + '\n\n' +
|
||||
'*Executed by @' + actor + '*'
|
||||
);
|
||||
process.exit(0);
|
||||
}
|
||||
const targetType = methodParts[1].toLowerCase();
|
||||
const resourcesStr = methodParts[2];
|
||||
|
||||
// Parse resource fields (only cpu/ram/hdd allowed)
|
||||
const RESOURCE_FIELDS = { cpu: true, ram: true, hdd: true };
|
||||
const resourceChanges = {};
|
||||
const rePairs = /([a-z]+)=(\d+)/gi;
|
||||
let m;
|
||||
while ((m = rePairs.exec(resourcesStr)) !== null) {
|
||||
const key = m[1].toLowerCase();
|
||||
if (RESOURCE_FIELDS[key]) resourceChanges[key] = parseInt(m[2], 10);
|
||||
}
|
||||
if (Object.keys(resourceChanges).length === 0) {
|
||||
await addReaction('-1');
|
||||
await postComment('❌ **PocketBase Bot**: No valid resource fields found. Use `cpu=N`, `ram=N`, `hdd=N`.');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// Find matching method by type name (case-insensitive)
|
||||
const idx = methodsArr.findIndex(function (im) {
|
||||
return (im.type || '').toLowerCase() === targetType;
|
||||
});
|
||||
if (idx === -1) {
|
||||
await addReaction('-1');
|
||||
const availableTypes = methodsArr.map(function (im) { return im.type || '?'; });
|
||||
} else if (removeMatch) {
|
||||
// ── METHOD REMOVE ────────────────────────────────────────────
|
||||
const removeType = removeMatch[1].toLowerCase();
|
||||
const removed = methodsArr.filter(function (im) { return (im.type || '').toLowerCase() === removeType; });
|
||||
if (removed.length === 0) {
|
||||
await addReaction('-1');
|
||||
const available = methodsArr.map(function (im) { return im.type || '?'; });
|
||||
await postComment('❌ **PocketBase Bot**: No install method `' + removeType + '` found.\n\n**Available:** `' + (available.length ? available.join('`, `') : '(none)') + '`');
|
||||
process.exit(0);
|
||||
}
|
||||
methodsArr = methodsArr.filter(function (im) { return (im.type || '').toLowerCase() !== removeType; });
|
||||
await patchMethods(methodsArr);
|
||||
await revalidate(slug);
|
||||
await addReaction('+1');
|
||||
await postComment(
|
||||
'❌ **PocketBase Bot**: No install method with type `' + targetType + '` found for `' + slug + '`.\n\n' +
|
||||
'**Available types:** `' + (availableTypes.length ? availableTypes.join('`, `') : '(none)') + '`\n\n' +
|
||||
'Use `/pocketbase ' + slug + ' method list` to see all methods.'
|
||||
'✅ **PocketBase Bot**: Removed install method **`' + removed[0].type + '`** from **`' + slug + '`**\n\n' +
|
||||
'*Executed by @' + actor + '*'
|
||||
);
|
||||
|
||||
} else {
|
||||
// ── METHOD EDIT ──────────────────────────────────────────────
|
||||
const editParts = methodArgs.match(/^(\S+)\s+(.+)$/);
|
||||
if (!editParts) {
|
||||
await addReaction('-1');
|
||||
await postComment(
|
||||
'❌ **PocketBase Bot**: Invalid `method` syntax.\n\n' +
|
||||
'**Usage:**\n```\n/pocketbase ' + slug + ' method list\n' +
|
||||
'/pocketbase ' + slug + ' method <type> cpu=4 ram=2048 hdd=20\n' +
|
||||
'/pocketbase ' + slug + ' method <type> config_path="/opt/app/.env"\n' +
|
||||
'/pocketbase ' + slug + ' method add <type> cpu=2 ram=2048 hdd=8\n' +
|
||||
'/pocketbase ' + slug + ' method remove <type>\n```'
|
||||
);
|
||||
process.exit(0);
|
||||
}
|
||||
const targetType = editParts[1].toLowerCase();
|
||||
const parsed = parseKVPairs(editParts[2]);
|
||||
|
||||
const unknown = Object.keys(parsed).filter(function (k) { return !ALL_METHOD_KEYS[k]; });
|
||||
if (unknown.length > 0) {
|
||||
await addReaction('-1');
|
||||
await postComment('❌ **PocketBase Bot**: Unknown method field(s): `' + unknown.join('`, `') + '`\n\n**Allowed:** `' + Object.keys(ALL_METHOD_KEYS).join('`, `') + '`');
|
||||
process.exit(0);
|
||||
}
|
||||
if (Object.keys(parsed).length === 0) {
|
||||
await addReaction('-1');
|
||||
await postComment('❌ **PocketBase Bot**: No valid `key=value` pairs found.\n\n**Allowed:** `' + Object.keys(ALL_METHOD_KEYS).join('`, `') + '`');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
const idx = methodsArr.findIndex(function (im) { return (im.type || '').toLowerCase() === targetType; });
|
||||
if (idx === -1) {
|
||||
await addReaction('-1');
|
||||
const available = methodsArr.map(function (im) { return im.type || '?'; });
|
||||
await postComment(
|
||||
'❌ **PocketBase Bot**: No install method `' + targetType + '` found for `' + slug + '`.\n\n' +
|
||||
'**Available:** `' + (available.length ? available.join('`, `') : '(none)') + '`\n\n' +
|
||||
'Use `/pocketbase ' + slug + ' method list` to see all methods.'
|
||||
);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
applyMethodChanges(methodsArr[idx], parsed);
|
||||
await patchMethods(methodsArr);
|
||||
await revalidate(slug);
|
||||
const editCtChanges = {};
|
||||
for (const [k, v] of Object.entries(parsed)) {
|
||||
if (RESOURCE_TO_CT_VAR[k]) editCtChanges[RESOURCE_TO_CT_VAR[k]] = v;
|
||||
}
|
||||
let editCtSync = null;
|
||||
try {
|
||||
editCtSync = await upsertCtDefaultsPr(slug, editCtChanges);
|
||||
} catch (e) {
|
||||
editCtSync = { status: 'skipped', reason: 'CT sync failed: ' + e.message };
|
||||
}
|
||||
|
||||
const changesLines = Object.entries(parsed)
|
||||
.map(function ([k, v]) {
|
||||
const unit = k === 'ram' ? ' MB' : k === 'hdd' ? ' GB' : '';
|
||||
return '- `' + k + '` → `' + v + unit + '`';
|
||||
}).join('\n');
|
||||
await addReaction('+1');
|
||||
await postComment(
|
||||
'✅ **PocketBase Bot**: Updated install method **`' + methodsArr[idx].type + '`** for **`' + slug + '`**\n\n' +
|
||||
'**Changes applied:**\n' + changesLines + '\n\n' +
|
||||
formatCtSyncResult(editCtSync) + '\n\n' +
|
||||
'*Executed by @' + actor + '*'
|
||||
);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
if (!methodsArr[idx].resources) methodsArr[idx].resources = {};
|
||||
if (resourceChanges.cpu != null) methodsArr[idx].resources.cpu = resourceChanges.cpu;
|
||||
if (resourceChanges.ram != null) methodsArr[idx].resources.ram = resourceChanges.ram;
|
||||
if (resourceChanges.hdd != null) methodsArr[idx].resources.hdd = resourceChanges.hdd;
|
||||
|
||||
await patchInstallMethodsJson(methodsArr);
|
||||
|
||||
const changesLines = Object.entries(resourceChanges)
|
||||
.map(function ([k, v]) { return '- `' + k + '` → `' + v + (k === 'ram' ? ' MB' : k === 'hdd' ? ' GB' : '') + '`'; })
|
||||
.join('\n');
|
||||
await addReaction('+1');
|
||||
await postComment(
|
||||
'✅ **PocketBase Bot**: Updated install method **`' + methodsArr[idx].type + '`** for **`' + slug + '`**\n\n' +
|
||||
'**Changes applied:**\n' + changesLines + '\n\n' +
|
||||
'*Executed by @' + actor + '*'
|
||||
);
|
||||
}
|
||||
|
||||
} else if (setMatch) {
|
||||
// ── SET SUBCOMMAND (multi-line / HTML / special chars via code block) ──
|
||||
// ── SET SUBCOMMAND (value from code block) ───────────────────────
|
||||
const fieldName = setMatch[1].toLowerCase();
|
||||
const SET_ALLOWED = {
|
||||
name: 'string', description: 'string', logo: 'string',
|
||||
@@ -531,6 +870,7 @@ jobs:
|
||||
await postComment('❌ **PocketBase Bot**: PATCH failed for `' + slug + '`:\n```\n' + setPatchRes.body + '\n```');
|
||||
process.exit(1);
|
||||
}
|
||||
await revalidate(slug);
|
||||
const preview = codeBlockValue.length > 300 ? codeBlockValue.substring(0, 300) + '…' : codeBlockValue;
|
||||
await addReaction('+1');
|
||||
await postComment(
|
||||
@@ -541,11 +881,6 @@ jobs:
|
||||
|
||||
} else {
|
||||
// ── FIELD=VALUE PATH ─────────────────────────────────────────────
|
||||
const fieldsStr = rest;
|
||||
|
||||
// Skipped: slug, script_created/updated, created (auto), categories/
|
||||
// install_methods/notes/type (relations), github_data/install_methods_json/
|
||||
// notes_json (auto-generated), execute_in (select relation), last_update_commit (auto)
|
||||
const ALLOWED_FIELDS = {
|
||||
name: 'string',
|
||||
description: 'string',
|
||||
@@ -555,9 +890,11 @@ jobs:
|
||||
project_url: 'string',
|
||||
github: 'string',
|
||||
config_path: 'string',
|
||||
tags: 'string',
|
||||
port: 'number',
|
||||
default_user: 'nullable_string',
|
||||
default_passwd: 'nullable_string',
|
||||
unprivileged: 'number',
|
||||
updateable: 'boolean',
|
||||
privileged: 'boolean',
|
||||
has_arm: 'boolean',
|
||||
@@ -568,39 +905,7 @@ jobs:
|
||||
deleted_message: 'string',
|
||||
};
|
||||
|
||||
// Field=value parser (handles quoted values and empty=null)
|
||||
function parseFields(str) {
|
||||
const fields = {};
|
||||
let pos = 0;
|
||||
while (pos < str.length) {
|
||||
while (pos < str.length && /\s/.test(str[pos])) pos++;
|
||||
if (pos >= str.length) break;
|
||||
let keyStart = pos;
|
||||
while (pos < str.length && str[pos] !== '=' && !/\s/.test(str[pos])) pos++;
|
||||
const key = str.substring(keyStart, pos).trim();
|
||||
if (!key || pos >= str.length || str[pos] !== '=') { pos++; continue; }
|
||||
pos++;
|
||||
let value;
|
||||
if (str[pos] === '"') {
|
||||
pos++;
|
||||
let valStart = pos;
|
||||
while (pos < str.length && str[pos] !== '"') {
|
||||
if (str[pos] === '\\') pos++;
|
||||
pos++;
|
||||
}
|
||||
value = str.substring(valStart, pos).replace(/\\"/g, '"');
|
||||
if (pos < str.length) pos++;
|
||||
} else {
|
||||
let valStart = pos;
|
||||
while (pos < str.length && !/\s/.test(str[pos])) pos++;
|
||||
value = str.substring(valStart, pos);
|
||||
}
|
||||
fields[key] = value;
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
|
||||
const parsedFields = parseFields(fieldsStr);
|
||||
const parsedFields = parseKVPairs(rest);
|
||||
|
||||
const unknownFields = Object.keys(parsedFields).filter(function (f) { return !ALLOWED_FIELDS[f]; });
|
||||
if (unknownFields.length > 0) {
|
||||
@@ -655,6 +960,18 @@ jobs:
|
||||
await postComment('❌ **PocketBase Bot**: PATCH failed for `' + slug + '`:\n```\n' + patchRes.body + '\n```');
|
||||
process.exit(1);
|
||||
}
|
||||
await revalidate(slug);
|
||||
const FIELD_TO_CT_VAR = { tags: 'var_tags', unprivileged: 'var_unprivileged' };
|
||||
const fieldCtChanges = {};
|
||||
for (const [k, v] of Object.entries(payload)) {
|
||||
if (FIELD_TO_CT_VAR[k]) fieldCtChanges[FIELD_TO_CT_VAR[k]] = v;
|
||||
}
|
||||
let fieldCtSync = null;
|
||||
try {
|
||||
fieldCtSync = await upsertCtDefaultsPr(slug, fieldCtChanges);
|
||||
} catch (e) {
|
||||
fieldCtSync = { status: 'skipped', reason: 'CT sync failed: ' + e.message };
|
||||
}
|
||||
await addReaction('+1');
|
||||
const changesLines = Object.entries(payload)
|
||||
.map(function ([k, v]) { return '- `' + k + '` → `' + JSON.stringify(v) + '`'; })
|
||||
@@ -662,6 +979,7 @@ jobs:
|
||||
await postComment(
|
||||
'✅ **PocketBase Bot**: Updated **`' + slug + '`** successfully!\n\n' +
|
||||
'**Changes applied:**\n' + changesLines + '\n\n' +
|
||||
formatCtSyncResult(fieldCtSync) + '\n\n' +
|
||||
'*Executed by @' + actor + '*'
|
||||
);
|
||||
}
|
||||
|
||||
+1
-1
@@ -170,7 +170,6 @@ jobs:
|
||||
website: data.website,
|
||||
logo: data.logo,
|
||||
description: data.description,
|
||||
config_path: data.config_path,
|
||||
default_user: (data.default_credentials && data.default_credentials.username) || data.default_user || null,
|
||||
default_passwd: (data.default_credentials && data.default_credentials.password) || data.default_passwd || null,
|
||||
is_dev: false
|
||||
@@ -180,6 +179,7 @@ jobs:
|
||||
if (resolvedType) payload.type = resolvedType;
|
||||
var resolvedCats = (data.categories || []).map(function(n) { return categoryNameToPbId[categoryIdToName[n]]; }).filter(Boolean);
|
||||
if (resolvedCats.length) payload.categories = resolvedCats;
|
||||
if (data.has_arm !== undefined) payload.has_arm = data.has_arm === true || data.has_arm === 'true';
|
||||
if (data.version !== undefined) payload.version = data.version;
|
||||
if (data.changelog !== undefined) payload.changelog = data.changelog;
|
||||
if (data.screenshots !== undefined) payload.screenshots = data.screenshots;
|
||||
|
||||
+5
-38
@@ -2,32 +2,14 @@
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Editor & IDE files (keeping .vscode settings but ignoring unnecessary metadata)
|
||||
# Editor & IDE files
|
||||
!.vscode/
|
||||
.vscode/*.workspace
|
||||
.vscode/*.tmp
|
||||
|
||||
# Log and Cache files
|
||||
# Log files
|
||||
logs/
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Python-specific exclusions
|
||||
__pycache__/
|
||||
*.pyc
|
||||
*.pyo
|
||||
*.pyd
|
||||
*.venv/
|
||||
venv/
|
||||
env/
|
||||
*.env
|
||||
|
||||
# API and Backend specific exclusions
|
||||
api/.env
|
||||
api/__pycache__/
|
||||
api/*.sqlite3
|
||||
|
||||
# Install scripts and temporary files
|
||||
install/tmp/
|
||||
@@ -41,7 +23,7 @@ vm/*.vmdk
|
||||
vm/*.iso
|
||||
vm/*.bak
|
||||
|
||||
# Miscellaneous temporary or unnecessary files
|
||||
# Miscellaneous temporary files
|
||||
*.bak
|
||||
*.swp
|
||||
*.swo
|
||||
@@ -49,22 +31,7 @@ vm/*.bak
|
||||
*.tmp
|
||||
*.backup
|
||||
|
||||
# JSON configuration backups
|
||||
# JSON temporary files
|
||||
json/
|
||||
json/*.bak
|
||||
json/*.tmp
|
||||
json/.vscode/
|
||||
|
||||
# Ignore compiled binaries or packaged artifacts
|
||||
*.exe
|
||||
*.dll
|
||||
*.bin
|
||||
*.deb
|
||||
*.rpm
|
||||
*.tar.gz
|
||||
*.zip
|
||||
*.tgz
|
||||
|
||||
# Ignore repository metadata or Git itself
|
||||
.git/
|
||||
.gitignore
|
||||
.vscode/settings.json
|
||||
|
||||
-16
@@ -1,16 +0,0 @@
|
||||
; editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
continuation_indent_size = 2
|
||||
end_of_line = lf
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
max_line_length = 120
|
||||
tab_width = 2
|
||||
; trim_trailing_whitespace = true ; disabled until files are cleaned up
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
+532
-516
File diff suppressed because it is too large
Load Diff
+137
@@ -0,0 +1,137 @@
|
||||
# Contributing to Proxmox VE Helper-Scripts
|
||||
|
||||
Welcome! We're glad you want to contribute. This guide covers everything you need to add new scripts, improve existing ones, or help in other ways.
|
||||
|
||||
For detailed coding standards and full documentation, visit **[community-scripts.org/docs](https://community-scripts.org/docs)**.
|
||||
|
||||
---
|
||||
|
||||
## How Can I Help?
|
||||
|
||||
> [!IMPORTANT]
|
||||
> **New scripts** must always be submitted to [ProxmoxVED](https://github.com/community-scripts/ProxmoxVED) first — not to this repository.
|
||||
> PRs with new scripts opened directly against ProxmoxVE **will be closed without review**.
|
||||
> **Bug fixes, improvements, and features for existing scripts** go here (ProxmoxVE).
|
||||
|
||||
| I want to… | Where to go |
|
||||
| :------------------------------------------ | :------------------------------------------------------------------------------------------- |
|
||||
| **Add a brand-new script** | [ProxmoxVED](https://github.com/community-scripts/ProxmoxVED) — testing repo for new scripts |
|
||||
| **Fix a bug or improve an existing script** | This repo (ProxmoxVE) — open a PR here |
|
||||
| **Add a feature to an existing script** | This repo (ProxmoxVE) — open a PR here |
|
||||
| Report a bug or broken script | [Open an Issue](https://github.com/community-scripts/ProxmoxVE/issues) |
|
||||
| Request a new script or feature | [Start a Discussion](https://github.com/community-scripts/ProxmoxVE/discussions) |
|
||||
| Report a security vulnerability | [Security Policy](SECURITY.md) |
|
||||
| Chat with contributors | [Discord](https://discord.gg/3AnUqsXnmK) |
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before writing scripts, we recommend setting up:
|
||||
|
||||
- **Visual Studio Code** with these extensions:
|
||||
- [Shell Syntax](https://marketplace.visualstudio.com/items?itemName=bmalehorn.shell-syntax)
|
||||
- [ShellCheck](https://marketplace.visualstudio.com/items?itemName=timonwong.shellcheck)
|
||||
- [Shell Format](https://marketplace.visualstudio.com/items?itemName=foxundermoon.shell-format)
|
||||
|
||||
---
|
||||
|
||||
## Script Structure
|
||||
|
||||
Every script consists of two files:
|
||||
|
||||
| File | Purpose |
|
||||
| :--------------------------- | :------------------------------------------------------ |
|
||||
| `ct/AppName.sh` | Container creation, variable setup, and update handling |
|
||||
| `install/AppName-install.sh` | Application installation logic |
|
||||
|
||||
Use existing scripts in [`ct/`](ct/) and [`install/`](install/) as reference. Full coding standards and annotated templates are at **[community-scripts.org/docs/contribution](https://community-scripts.org/docs/contribution)**.
|
||||
|
||||
---
|
||||
|
||||
## Contribution Process
|
||||
|
||||
### Adding a new script
|
||||
|
||||
New scripts are **not accepted directly in this repository**. The workflow is:
|
||||
|
||||
1. Fork [ProxmoxVED](https://github.com/community-scripts/ProxmoxVED) and clone it
|
||||
2. Create a branch: `git switch -c feat/myapp`
|
||||
3. Write your two script files:
|
||||
- `ct/myapp.sh`
|
||||
- `install/myapp-install.sh`
|
||||
4. Test thoroughly in ProxmoxVED — run the script against a real Proxmox instance
|
||||
5. Open a PR in **ProxmoxVED** for review and testing
|
||||
6. Once accepted and verified there, the script will be promoted to ProxmoxVE by maintainers
|
||||
|
||||
Follow the coding standards at [community-scripts.org/docs/contribution](https://community-scripts.org/docs/contribution).
|
||||
|
||||
---
|
||||
|
||||
### Fixing a bug or improving an existing script
|
||||
|
||||
Changes to scripts that already exist in ProxmoxVE go directly here:
|
||||
|
||||
1. Fork **this repository** (ProxmoxVE) and clone it:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/YOUR_USERNAME/ProxmoxVE
|
||||
cd ProxmoxVE
|
||||
```
|
||||
|
||||
2. Create a branch:
|
||||
|
||||
```bash
|
||||
git switch -c fix/myapp-description
|
||||
```
|
||||
|
||||
3. Make your changes to the relevant files in `ct/` and/or `install/`
|
||||
|
||||
4. Open a PR from your fork to `community-scripts/ProxmoxVE/main`
|
||||
|
||||
Your PR should only contain the files you changed. Do not include unrelated modifications.
|
||||
|
||||
---
|
||||
|
||||
## Code Standards
|
||||
|
||||
Key rules at a glance:
|
||||
|
||||
- One script per service — keep them focused
|
||||
- Naming convention: lowercase, hyphen-separated (`my-app.sh`)
|
||||
- Shebang: `#!/usr/bin/env bash`
|
||||
- Quote all variables: `"$VAR"` not `$VAR`
|
||||
- Use lowercase variable names
|
||||
- Do not hardcode credentials or sensitive values
|
||||
|
||||
Full standards and examples: **[community-scripts.org/docs/contribution](https://community-scripts.org/docs/contribution)**
|
||||
|
||||
---
|
||||
|
||||
## Developer Mode & Debugging
|
||||
|
||||
Set the `dev_mode` variable to enable debugging features when testing. Flags can be combined (comma-separated):
|
||||
|
||||
```bash
|
||||
dev_mode="trace,keep" bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/myapp.sh)"
|
||||
```
|
||||
|
||||
| Flag | Description |
|
||||
| :----------- | :----------------------------------------------------------- |
|
||||
| `trace` | Enables `set -x` for maximum verbosity during execution |
|
||||
| `keep` | Prevents the container from being deleted if the build fails |
|
||||
| `pause` | Pauses execution at key points before customization |
|
||||
| `breakpoint` | Drops to a shell at hardcoded `breakpoint` calls in scripts |
|
||||
| `logs` | Saves detailed build logs to `/var/log/community-scripts/` |
|
||||
| `dryrun` | Bypasses actual container creation (limited support) |
|
||||
| `motd` | Forces an update of the Message of the Day |
|
||||
|
||||
---
|
||||
|
||||
## Notes
|
||||
|
||||
- **Website metadata** (name, description, logo, tags) is managed via the website — use the "Report Issue" link on any script page to request changes. Do not submit metadata changes via repo files.
|
||||
- **JSON files** in `json/` define script properties used by the website. See existing files for structure reference.
|
||||
- Keep PRs small and focused. One fix or feature per PR is ideal.
|
||||
- PRs with **new scripts** opened against ProxmoxVE will be closed — submit them to [ProxmoxVED](https://github.com/community-scripts/ProxmoxVED) instead.
|
||||
- PRs that fail CI checks will not be merged.
|
||||
@@ -1,283 +1,209 @@
|
||||
<div align="center">
|
||||
<img src="https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/images/logo-81x112.png" height="120px" alt="Proxmox VE Helper-Scripts Logo" />
|
||||
|
||||
<img src="https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/images/logo-81x112.png" height="112px" alt="Proxmox VE Helper-Scripts Logo" />
|
||||
|
||||
<h1>Proxmox VE Helper-Scripts</h1>
|
||||
<p><em>A Community Legacy in Memory of @tteck</em></p>
|
||||
<p><strong>One-command installations for services, containers, and VMs on Proxmox VE</strong><br/>
|
||||
A community project — built on the foundation of <a href="https://github.com/tteck">@tteck</a>'s original work</p>
|
||||
|
||||
<p>
|
||||
<a href="https://community-scripts.org">
|
||||
<img src="https://img.shields.io/badge/🌐_Website-Visit-4c9b3f?style=for-the-badge&labelColor=2d3748" alt="Website" />
|
||||
</a>
|
||||
<a href="https://discord.gg/3AnUqsXnmK">
|
||||
<img src="https://img.shields.io/badge/💬_Discord-Join-7289da?style=for-the-badge&labelColor=2d3748" alt="Discord" />
|
||||
</a>
|
||||
<a href="https://ko-fi.com/community_scripts">
|
||||
<img src="https://img.shields.io/badge/❤️_Support-Donate-FF5F5F?style=for-the-badge&labelColor=2d3748" alt="Donate" />
|
||||
</a>
|
||||
<a href="https://community-scripts.org"><img src="https://img.shields.io/badge/Website-community--scripts.org-4c9b3f?style=flat-square" /></a>
|
||||
<a href="https://discord.gg/3AnUqsXnmK"><img src="https://img.shields.io/badge/Discord-Join_us-7289da?style=flat-square&logo=discord&logoColor=white" /></a>
|
||||
<a href="https://github.com/community-scripts/ProxmoxVE/stargazers"><img src="https://img.shields.io/github/stars/community-scripts/ProxmoxVE?style=flat-square&label=Stars&color=f5a623" /></a>
|
||||
<a href="https://github.com/community-scripts/ProxmoxVE/blob/main/CHANGELOG.md"><img src="https://img.shields.io/badge/Changelog-view-6c5ce7?style=flat-square" /></a>
|
||||
<a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue?style=flat-square" /></a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a href="https://github.com/community-scripts/ProxmoxVE/blob/main/docs/contribution/README.md">
|
||||
<img src="https://img.shields.io/badge/🤝_Contribute-Guidelines-ff4785?style=for-the-badge&labelColor=2d3748" alt="Contribute" />
|
||||
</a>
|
||||
<a href="https://github.com/community-scripts/ProxmoxVE/blob/main/docs/contribution/USER_SUBMITTED_GUIDES.md">
|
||||
<img src="https://img.shields.io/badge/📚_Guides-Read-0077b5?style=for-the-badge&labelColor=2d3748" alt="Guides" />
|
||||
</a>
|
||||
<a href="https://github.com/community-scripts/ProxmoxVE/blob/main/CHANGELOG.md">
|
||||
<img src="https://img.shields.io/badge/📋_Changelog-View-6c5ce7?style=for-the-badge&labelColor=2d3748" alt="Changelog" />
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<br />
|
||||
|
||||
**Simplify your Proxmox VE setup with community-driven automation scripts**
|
||||
Originally created by tteck, now maintained and expanded by the community
|
||||
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
<div align="center">
|
||||
<sub>🙌 <strong>Shoutout to</strong></sub>
|
||||
<br />
|
||||
<br />
|
||||
<a href="https://selfh.st/">
|
||||
<img src="https://img.shields.io/badge/selfh.st-Icons_for_Self--Hosted-2563eb?style=for-the-badge&logo=data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMTIgMkM2LjQ4IDIgMiA2LjQ4IDIgMTJzNC40OCAxMCAxMCAxMCAxMC00LjQ4IDEwLTEwUzE3LjUyIDIgMTIgMnptMCAxOGMtNC40MSAwLTgtMy41OS04LThzMy41OS04IDgtOCA4IDMuNTkgOCA4LTMuNTkgOC04IDh6IiBmaWxsPSJ3aGl0ZSIvPjwvc3ZnPg==&labelColor=1e3a8a" alt="selfh.st Icons" />
|
||||
</a>
|
||||
<br />
|
||||
<sub><a href="https://github.com/selfhst/icons">View on GitHub</a> • Consistent, beautiful icons for 5000+ self-hosted apps</sub>
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Key Features
|
||||
## What is this?
|
||||
|
||||
<div align="center">
|
||||
**Simplify your Proxmox VE setup with community-driven automation scripts.**
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td align="center" width="25%">
|
||||
<h3>⚡ Quick Setup</h3>
|
||||
<p>One-command installations for popular services and containers</p>
|
||||
</td>
|
||||
<td align="center" width="25%">
|
||||
<h3>⚙️ Flexible Config</h3>
|
||||
<p>Simple mode for beginners, advanced options for power users</p>
|
||||
</td>
|
||||
<td align="center" width="25%">
|
||||
<h3>🔄 Auto Updates</h3>
|
||||
<p>Keep your installations current with built-in update mechanisms</p>
|
||||
</td>
|
||||
<td align="center" width="25%">
|
||||
<h3>🛠️ Easy Management</h3>
|
||||
<p>Post-install scripts for configuration and troubleshooting</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" width="25%">
|
||||
<h3>👥 Community Driven</h3>
|
||||
<p>Actively maintained with contributions from users worldwide</p>
|
||||
</td>
|
||||
<td align="center" width="25%">
|
||||
<h3>📖 Well Documented</h3>
|
||||
<p>Comprehensive guides and community support</p>
|
||||
</td>
|
||||
<td align="center" width="25%">
|
||||
<h3>🔒 Secure</h3>
|
||||
<p>Regular security updates and best practices</p>
|
||||
</td>
|
||||
<td align="center" width="25%">
|
||||
<h3>⚡ Performance</h3>
|
||||
<p>Optimized configurations for best performance</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
Install and configure popular self-hosted services with a single command — no manual package hunting, no config file archaeology. Paste a command into your Proxmox shell, answer a few prompts, and your container or VM is up and running.
|
||||
|
||||
</div>
|
||||
The collection covers hundreds of services across categories like home automation, media servers, networking tools, databases, monitoring stacks, and more.
|
||||
|
||||
---
|
||||
|
||||
## 📋 Requirements
|
||||
## Requirements
|
||||
|
||||
<div align="center">
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td align="center" width="33%">
|
||||
<h3>🖥️ Proxmox VE</h3>
|
||||
<p>Version: 8.4.x | 9.0.x | 9.1.x</p>
|
||||
</td>
|
||||
<td align="center" width="33%">
|
||||
<h3>🐧 Operating System</h3>
|
||||
<p>Debian-based with Proxmox Tools</p>
|
||||
</td>
|
||||
<td align="center" width="33%">
|
||||
<h3>🌐 Network</h3>
|
||||
<p>Internet connection required</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
| Component | Details |
|
||||
| -------------- | ------------------------------------------------ |
|
||||
| **Proxmox VE** | Version 8.4, 9.0, 9.1, or 9.2 |
|
||||
| **Host OS** | Proxmox VE (Debian-based) |
|
||||
| **Access** | Root shell access on the Proxmox host |
|
||||
| **Network** | Internet connection required during installation |
|
||||
|
||||
---
|
||||
|
||||
## 📥 Getting Started
|
||||
## Getting Started
|
||||
|
||||
Choose your preferred installation method:
|
||||
The fastest way to find and run scripts:
|
||||
|
||||
### Method 1: One-Click Web Installer
|
||||
1. Go to **[community-scripts.org](https://community-scripts.org)**
|
||||
2. Search for the service you want (e.g. "Home Assistant", "Nginx Proxy Manager", "Jellyfin")
|
||||
3. Copy the one-line install command from the script page
|
||||
4. Open your **Proxmox Shell** and paste it
|
||||
5. Choose between **Default** or **Advanced** setup and follow the prompts
|
||||
|
||||
The fastest way to get started:
|
||||
|
||||
1. Visit **[community-scripts.org](https://community-scripts.org/)** 🌐
|
||||
2. Search for your desired script (e.g., "Home Assistant", "Docker")
|
||||
3. Copy the bash command displayed on the script page
|
||||
4. Open your **Proxmox Shell** and paste the command
|
||||
5. Press Enter and follow the interactive prompts
|
||||
|
||||
### Method 2: PVEScripts-Local
|
||||
|
||||
Install a convenient script manager directly in your Proxmox UI:
|
||||
|
||||
```bash
|
||||
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/pve-scripts-local.sh)"
|
||||
```
|
||||
|
||||
This adds a menu to your Proxmox interface for easy script access without visiting the website.
|
||||
|
||||
📖 **Learn more:** [ProxmoxVE-Local Repository](https://github.com/community-scripts/ProxmoxVE-Local)
|
||||
Each script page documents what the container includes, default resource allocation, and post-install notes.
|
||||
|
||||
---
|
||||
|
||||
## 💬 Join the Community
|
||||
## How Scripts Work
|
||||
|
||||
<div align="center">
|
||||
Every script follows the same pattern:
|
||||
|
||||
<table>
|
||||
**Default mode** — Picks sensible resource defaults (CPU, RAM, storage) and asks only the minimum required questions. Most installs finish in under five minutes.
|
||||
|
||||
**Advanced mode** — Gives you full control over container settings, networking, storage backends, and application-level configuration before anything is installed.
|
||||
|
||||
After installation, each container ships with a **post-install helper** accessible from the Proxmox shell. It handles common tasks like:
|
||||
|
||||
- Applying updates to the installed service
|
||||
- Changing application settings without manually editing config files
|
||||
- Basic troubleshooting and log access
|
||||
|
||||
---
|
||||
|
||||
## What's Included
|
||||
|
||||
The repository covers a wide range of categories. A few examples:
|
||||
|
||||
| Category | Examples |
|
||||
| --------------- | --------------------------------------------------- |
|
||||
| Home Automation | Home Assistant, Zigbee2MQTT, ESPHome, Node-RED |
|
||||
| Media | Jellyfin, Plex, Radarr, Sonarr, Immich |
|
||||
| Networking | AdGuard Home, Nginx Proxy Manager, Pi-hole, Traefik |
|
||||
| Monitoring | Grafana, Prometheus, Uptime Kuma, Netdata |
|
||||
| Databases | PostgreSQL, MariaDB, Redis, InfluxDB |
|
||||
| Security | Vaultwarden, CrowdSec, Authentik |
|
||||
| Dev & Tools | Gitea, Portainer, VS Code Server, n8n |
|
||||
|
||||
> Browse the full list at **[community-scripts.org/categories](https://community-scripts.org/categories)** — new scripts are added regularly.
|
||||
|
||||
---
|
||||
|
||||
## Contributing
|
||||
|
||||
This project runs on community contributions. Whether you want to write new scripts, improve existing ones, or just report a bug — every bit helps.
|
||||
|
||||
### Where to start
|
||||
|
||||
| I want to… | Go here |
|
||||
| ------------------------------------- | ------------------------------------------------------------------------------------------------- |
|
||||
| Add a **new** script | [ProxmoxVED](https://github.com/community-scripts/ProxmoxVED) — new scripts are tested here first |
|
||||
| Fix or improve an **existing** script | [Contributing Guidelines](CONTRIBUTING.md) — open a PR in this repo |
|
||||
| Report a bug or broken script | [Issues](https://github.com/community-scripts/ProxmoxVE/issues) |
|
||||
| Request a new script or feature | [Discussions](https://github.com/community-scripts/ProxmoxVE/discussions) |
|
||||
| Report a security vulnerability | [Security Policy](SECURITY.md) |
|
||||
| Get help or chat with other users | [Discord](https://discord.gg/3AnUqsXnmK) |
|
||||
|
||||
### Before you open a PR
|
||||
|
||||
- **New scripts go to [ProxmoxVED](https://github.com/community-scripts/ProxmoxVED), not here.** PRs with new scripts opened directly against this repo will be closed.
|
||||
- Bug fixes and improvements to existing scripts belong in this repo — read the [Contributing Guidelines](CONTRIBUTING.md) first.
|
||||
- Keep PRs focused. One fix or feature per PR.
|
||||
- Document what your script installs and any non-obvious decisions in the corresponding JSON metadata file.
|
||||
|
||||
---
|
||||
|
||||
## Core Team
|
||||
|
||||
<table align="center">
|
||||
<tr>
|
||||
<td align="center" width="33%">
|
||||
<h3>💬 Discord</h3>
|
||||
<p>Real-time chat, support, and discussions</p>
|
||||
<a href="https://discord.gg/3AnUqsXnmK">
|
||||
<img src="https://img.shields.io/badge/Join-7289da?style=for-the-badge&logo=discord&logoColor=white" alt="Discord" />
|
||||
<td align="center">
|
||||
<a href="https://github.com/MickLesk">
|
||||
<img src="https://github.com/MickLesk.png" width="80" height="80" style="border-radius:50%" alt="MickLesk" /><br/>
|
||||
<sub><b>MickLesk</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" width="33%">
|
||||
<h3>💭 Discussions</h3>
|
||||
<p>Feature requests, Q&A, and ideas</p>
|
||||
<a href="https://github.com/community-scripts/ProxmoxVE/discussions">
|
||||
<img src="https://img.shields.io/badge/Discuss-238636?style=for-the-badge&logo=github&logoColor=white" alt="Discussions" />
|
||||
<td align="center">
|
||||
<a href="https://github.com/michelroegl-brunner">
|
||||
<img src="https://github.com/michelroegl-brunner.png" width="80" height="80" style="border-radius:50%" alt="michelroegl-brunner" /><br/>
|
||||
<sub><b>michelroegl-brunner</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" width="33%">
|
||||
<h3>🐛 Issues</h3>
|
||||
<p>Bug reports and issue tracking</p>
|
||||
<a href="https://github.com/community-scripts/ProxmoxVE/issues">
|
||||
<img src="https://img.shields.io/badge/Report-d73a4a?style=for-the-badge&logo=github&logoColor=white" alt="Issues" />
|
||||
<td align="center">
|
||||
<a href="https://github.com/BramSuurdje">
|
||||
<img src="https://github.com/BramSuurdje.png" width="80" height="80" style="border-radius:50%" alt="BramSuurdje" /><br/>
|
||||
<sub><b>BramSuurdje</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/CrazyWolf13">
|
||||
<img src="https://github.com/CrazyWolf13.png" width="80" height="80" style="border-radius:50%" alt="CrazyWolf13" /><br/>
|
||||
<sub><b>CrazyWolf13</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/tremor021">
|
||||
<img src="https://github.com/tremor021.png" width="80" height="80" style="border-radius:50%" alt="tremor021" /><br/>
|
||||
<sub><b>tremor021</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/vhsdream">
|
||||
<img src="https://github.com/vhsdream.png" width="80" height="80" style="border-radius:50%" alt="vhsdream" /><br/>
|
||||
<sub><b>vhsdream</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ Contribute
|
||||
## Project Activity
|
||||
|
||||
<div align="center">
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td align="center" width="25%">
|
||||
<h3>💻 Code</h3>
|
||||
<p>Add new scripts or improve existing ones</p>
|
||||
</td>
|
||||
<td align="center" width="25%">
|
||||
<h3>📝 Documentation</h3>
|
||||
<p>Write guides, improve READMEs, translate content</p>
|
||||
</td>
|
||||
<td align="center" width="25%">
|
||||
<h3>🧪 Testing</h3>
|
||||
<p>Test scripts and report compatibility issues</p>
|
||||
</td>
|
||||
<td align="center" width="25%">
|
||||
<h3>💡 Ideas</h3>
|
||||
<p>Suggest features or workflow improvements</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
<div align="center">
|
||||
<br />
|
||||
|
||||
👉 Check our **[Contributing Guidelines](https://github.com/community-scripts/ProxmoxVE/blob/main/docs/contribution/README.md)** to get started
|
||||
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
## ❤️ Support the Project
|
||||
|
||||
This project is maintained by volunteers in memory of tteck. Your support helps us maintain infrastructure, improve documentation, and give back to important causes.
|
||||
|
||||
**🎗️ 30% of all donations go directly to cancer research and hospice care**
|
||||
|
||||
<div align="center">
|
||||
|
||||
<a href="https://ko-fi.com/community_scripts">
|
||||
<img src="https://img.shields.io/badge/☕_Buy_us_a_coffee-Support_on_Ko--fi-FF5F5F?style=for-the-badge&labelColor=2d3748" alt="Support on Ko-fi" />
|
||||
</a>
|
||||
|
||||
<br />
|
||||
<sub>Every contribution helps keep this project alive and supports meaningful causes</sub>
|
||||
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
## 📈 Project Statistics
|
||||
<p align="center">
|
||||
<img
|
||||
src="https://repobeats.axiom.co/api/embed/57edde03e00f88d739bdb5b844ff7d07dd079375.svg"
|
||||
alt="Repobeats analytics"
|
||||
width="650"
|
||||
alt="Repository activity"
|
||||
width="700"
|
||||
/>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://star-history.com/#community-scripts/ProxmoxVE&Date">
|
||||
<picture>
|
||||
<source
|
||||
media="(prefers-color-scheme: dark)"
|
||||
srcset="https://api.star-history.com/svg?repos=community-scripts/ProxmoxVE&type=Date&theme=dark"
|
||||
/>
|
||||
<source
|
||||
media="(prefers-color-scheme: light)"
|
||||
srcset="https://api.star-history.com/svg?repos=community-scripts/ProxmoxVE&type=Date"
|
||||
/>
|
||||
<img
|
||||
alt="Star History Chart"
|
||||
src="https://api.star-history.com/svg?repos=community-scripts/ProxmoxVE&type=Date"
|
||||
width="650"
|
||||
/>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=community-scripts/ProxmoxVE&type=Date&theme=dark" />
|
||||
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=community-scripts/ProxmoxVE&type=Date" />
|
||||
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=community-scripts/ProxmoxVE&type=Date" width="700" />
|
||||
</picture>
|
||||
</a>
|
||||
</p>
|
||||
|
||||
---
|
||||
|
||||
## 📜 License
|
||||
## Support the Project
|
||||
|
||||
This project is licensed under the **[MIT License](LICENSE)** - feel free to use, modify, and distribute.
|
||||
This project is maintained by volunteers. All infrastructure costs come out of pocket, and the work is done in people's spare time.
|
||||
|
||||
**30% of all donations are forwarded directly to cancer research and hospice care** — a cause that was important to tteck.
|
||||
|
||||
<div align="center">
|
||||
<a href="https://ko-fi.com/community_scripts">
|
||||
<img src="https://img.shields.io/badge/Support_on_Ko--fi-FF5F5F?style=for-the-badge&logo=ko-fi&logoColor=white" alt="Support on Ko-fi" />
|
||||
</a>
|
||||
|
||||
<a href="https://community-scripts.org/donate">
|
||||
<img src="https://img.shields.io/badge/Donate-community--scripts.org%2Fdonate-4c9b3f?style=for-the-badge" alt="Donate via community-scripts.org" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the [MIT License](LICENSE) — free to use, modify, and redistribute for personal and commercial purposes.
|
||||
|
||||
See the full license text in [LICENSE](LICENSE).
|
||||
|
||||
---
|
||||
|
||||
<div align="center">
|
||||
<sub>Made with ❤️ by the Proxmox community in memory of tteck</sub>
|
||||
<br />
|
||||
<sub>Built on the foundation of <a href="https://github.com/tteck">tteck</a>'s original work · <a href="https://github.com/tteck/Proxmox">Original Repository</a></sub><br/>
|
||||
<sub>Maintained and expanded by the community · In memory of tteck</sub><br/>
|
||||
<sub><i>Proxmox® is a registered trademark of <a href="https://www.proxmox.com/en/about/company">Proxmox Server Solutions GmbH</a></i></sub>
|
||||
</div>
|
||||
|
||||
@@ -6,6 +6,7 @@ This project currently supports the following versions of Proxmox VE (PVE):
|
||||
|
||||
| Version | Supported |
|
||||
| ------- | ------------------ |
|
||||
| 9.2.x | :white_check_mark: |
|
||||
| 9.1.x | :white_check_mark: |
|
||||
| 9.0.x | :white_check_mark: |
|
||||
| 8.4.x | :white_check_mark: |
|
||||
|
||||
+17
-9
@@ -12,6 +12,7 @@ var_ram="${var_ram:-512}"
|
||||
var_disk="${var_disk:-2}"
|
||||
var_os="${var_os:-debian}"
|
||||
var_version="${var_version:-13}"
|
||||
var_arm64="${var_arm64:-yes}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -24,7 +25,7 @@ function update_script() {
|
||||
check_container_storage
|
||||
check_container_resources
|
||||
|
||||
if [[ ! -d "/opt/2fauth" ]]; then
|
||||
if [[ ! -d /opt/2fauth ]]; then
|
||||
msg_error "No ${APP} Installation Found!"
|
||||
exit
|
||||
fi
|
||||
@@ -34,7 +35,10 @@ function update_script() {
|
||||
$STD apt -y upgrade
|
||||
|
||||
msg_info "Creating Backup"
|
||||
mv "/opt/2fauth" "/opt/2fauth-backup"
|
||||
create_backup \
|
||||
/opt/2fauth/.env \
|
||||
/opt/2fauth/storage
|
||||
|
||||
if ! dpkg -l | grep -q 'php8.4'; then
|
||||
cp /etc/nginx/conf.d/2fauth.conf /etc/nginx/conf.d/2fauth.conf.bak
|
||||
fi
|
||||
@@ -44,17 +48,21 @@ function update_script() {
|
||||
PHP_VERSION="8.4" PHP_FPM="YES" setup_php
|
||||
sed -i 's/php8\.[0-9]/php8.4/g' /etc/nginx/conf.d/2fauth.conf
|
||||
fi
|
||||
|
||||
fetch_and_deploy_gh_release "2fauth" "Bubka/2FAuth" "tarball"
|
||||
setup_composer
|
||||
mv "/opt/2fauth-backup/.env" "/opt/2fauth/.env"
|
||||
mv "/opt/2fauth-backup/storage" "/opt/2fauth/storage"
|
||||
cd "/opt/2fauth" || return
|
||||
chown -R www-data: "/opt/2fauth"
|
||||
chmod -R 755 "/opt/2fauth"
|
||||
restore_backup
|
||||
|
||||
msg_info "Configuring 2FAuth"
|
||||
cd /opt/2fauth
|
||||
export COMPOSER_ALLOW_SUPERUSER=1
|
||||
$STD composer install --no-dev --prefer-dist
|
||||
php artisan 2fauth:install
|
||||
chown -R www-data: /opt/2fauth
|
||||
chmod -R 755 /opt/2fauth
|
||||
$STD systemctl restart php8.4-fpm
|
||||
$STD systemctl restart nginx
|
||||
msg_ok "Configured 2FAuth"
|
||||
msg_ok "Updated successfully!"
|
||||
fi
|
||||
exit
|
||||
@@ -66,5 +74,5 @@ description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:80${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following URL:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}:80${CL}"
|
||||
|
||||
+6
-5
@@ -12,6 +12,7 @@ var_ram="${var_ram:-2048}"
|
||||
var_disk="${var_disk:-4}"
|
||||
var_os="${var_os:-debian}"
|
||||
var_version="${var_version:-13}"
|
||||
var_arm64="${var_arm64:-yes}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -48,9 +49,9 @@ function update_script() {
|
||||
msg_ok "Updated successfully!"
|
||||
fi
|
||||
else
|
||||
msg_info "Old Installation Found, you need to migrate your data and recreate to a new container"
|
||||
msg_info "Please follow the instructions on the Actual Budget website to migrate your data"
|
||||
msg_info "https://actualbudget.org/docs/backup-restore/backup"
|
||||
msg_warn "Old Installation Found, you need to migrate your data and recreate to a new container"
|
||||
msg_warn "Please follow the instructions on the Actual Budget website to migrate your data"
|
||||
msg_warn "https://actualbudget.org/docs/backup-restore/backup"
|
||||
exit
|
||||
fi
|
||||
exit
|
||||
@@ -62,5 +63,5 @@ description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}https://${IP}:5006${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following URL:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}https://${IP}:5006${CL}"
|
||||
|
||||
+3
-2
@@ -12,6 +12,7 @@ var_ram="${var_ram:-512}"
|
||||
var_disk="${var_disk:-2}"
|
||||
var_os="${var_os:-debian}"
|
||||
var_version="${var_version:-13}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -37,5 +38,5 @@ description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:3000${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following URL:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}:3000${CL}"
|
||||
|
||||
+10
-13
@@ -9,9 +9,10 @@ APP="AdventureLog"
|
||||
var_tags="${var_tags:-traveling}"
|
||||
var_disk="${var_disk:-7}"
|
||||
var_cpu="${var_cpu:-2}"
|
||||
var_ram="${var_ram:-2048}"
|
||||
var_ram="${var_ram:-4096}"
|
||||
var_os="${var_os:-debian}"
|
||||
var_version="${var_version:-13}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -34,10 +35,8 @@ function update_script() {
|
||||
systemctl stop adventurelog-frontend
|
||||
msg_ok "Services Stopped"
|
||||
|
||||
msg_info "Backup Old Installation"
|
||||
cp -r /opt/adventurelog /opt/adventurelog-backup
|
||||
rm -rf /opt/adventurelog
|
||||
msg_ok "Backup done"
|
||||
create_backup /opt/adventurelog/backend/server/.env \
|
||||
/opt/adventurelog/backend/server/media
|
||||
|
||||
fetch_and_deploy_gh_release "adventurelog" "seanmorley15/adventurelog" "tarball"
|
||||
PYTHON_VERSION="3.13" setup_uv
|
||||
@@ -46,9 +45,9 @@ function update_script() {
|
||||
$STD sudo -u postgres psql -d adventurelog_db -c "CREATE EXTENSION IF NOT EXISTS postgis;"
|
||||
msg_ok "PostgreSQL Extensions Ready"
|
||||
|
||||
msg_info "Updating ${APP}"
|
||||
cp /opt/adventurelog-backup/backend/server/.env /opt/adventurelog/backend/server/.env
|
||||
cp -r /opt/adventurelog-backup/backend/server/media /opt/adventurelog/backend/server/media
|
||||
restore_backup
|
||||
|
||||
msg_info "Updating AdventureLog"
|
||||
cd /opt/adventurelog/backend/server
|
||||
if [[ ! -x .venv/bin/python ]]; then
|
||||
$STD uv venv --clear .venv
|
||||
@@ -60,12 +59,10 @@ function update_script() {
|
||||
$STD .venv/bin/python -m manage collectstatic --noinput
|
||||
$STD .venv/bin/python -m manage migrate
|
||||
|
||||
cp /opt/adventurelog-backup/frontend/.env /opt/adventurelog/frontend/.env
|
||||
cd /opt/adventurelog/frontend
|
||||
$STD pnpm i
|
||||
$STD pnpm build
|
||||
rm -rf /opt/adventurelog-backup
|
||||
msg_ok "Updated ${APP}"
|
||||
msg_ok "Updated AdventureLog"
|
||||
|
||||
msg_info "Starting Services"
|
||||
systemctl daemon-reexec
|
||||
@@ -83,5 +80,5 @@ description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:3000${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following URL:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}:3000${CL}"
|
||||
|
||||
+3
-2
@@ -12,6 +12,7 @@ var_ram="${var_ram:-2048}"
|
||||
var_disk="${var_disk:-8}"
|
||||
var_os="${var_os:-ubuntu}"
|
||||
var_version="${var_version:-24.04}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-0}"
|
||||
var_gpu="${var_gpu:-yes}"
|
||||
|
||||
@@ -60,5 +61,5 @@ description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:8090${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following URL:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}:8090${CL}"
|
||||
|
||||
@@ -12,6 +12,7 @@ var_ram="${var_ram:-256}"
|
||||
var_disk="${var_disk:-1}"
|
||||
var_os="${var_os:-alpine}"
|
||||
var_version="${var_version:-3.23}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -42,5 +43,5 @@ description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:3000${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following URL:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}:3000${CL}"
|
||||
|
||||
@@ -12,6 +12,7 @@ var_ram="${var_ram:-1024}"
|
||||
var_disk="${var_disk:-3}"
|
||||
var_os="${var_os:-alpine}"
|
||||
var_version="${var_version:-3.23}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -84,5 +85,5 @@ description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following IP:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:3333${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following IP:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}:3333${CL}"
|
||||
|
||||
@@ -13,6 +13,7 @@ var_ram="${var_ram:-1024}"
|
||||
var_disk="${var_disk:-20}"
|
||||
var_os="${var_os:-alpine}"
|
||||
var_version="${var_version:-3.23}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -103,5 +104,5 @@ description
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW}Connection information:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}ssh backup@${IP}${CL}"
|
||||
echo -e "${GATEWAY}${BGN}ssh backup@${IP}${CL}"
|
||||
echo -e "${TAB}${VERIFYPW}${YW}To set SSH key, run this script with the 'update' option and select option 2${CL}"
|
||||
|
||||
+3
-2
@@ -12,6 +12,7 @@ var_ram="${var_ram:-256}"
|
||||
var_disk="${var_disk:-3}"
|
||||
var_os="${var_os:-alpine}"
|
||||
var_version="${var_version:-3.23}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -42,5 +43,5 @@ description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:80${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following URL:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}:80${CL}"
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
#!/usr/bin/env bash
|
||||
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
|
||||
# Copyright (c) 2021-2026 community-scripts ORG
|
||||
# Author: Tobias Salzmann (Eun)
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||
# Source: https://github.com/cinnyapp/cinny
|
||||
|
||||
APP="Alpine-Cinny"
|
||||
var_tags="${var_tags:-alpine;matrix}"
|
||||
var_cpu="${var_cpu:-1}"
|
||||
var_ram="${var_ram:-256}"
|
||||
var_disk="${var_disk:-1}"
|
||||
var_os="${var_os:-alpine}"
|
||||
var_version="${var_version:-3.23}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
var_nesting="${var_nesting:-0}"
|
||||
|
||||
header_info "$APP"
|
||||
variables
|
||||
color
|
||||
catch_errors
|
||||
|
||||
function update_script() {
|
||||
header_info
|
||||
|
||||
if [[ ! -d /opt/cinny ]]; then
|
||||
msg_error "No ${APP} Installation Found!"
|
||||
exit
|
||||
fi
|
||||
|
||||
if check_for_gh_release "cinny" "cinnyapp/cinny"; then
|
||||
msg_info "Backing up Configuration"
|
||||
cp /opt/cinny/config.json /opt/cinny_config.json.bak
|
||||
msg_ok "Backed up Configuration"
|
||||
|
||||
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "cinny" "cinnyapp/cinny" "prebuild" "latest" "/opt/cinny" "cinny-*.tar.gz"
|
||||
|
||||
msg_info "Restoring Configuration"
|
||||
cp /opt/cinny_config.json.bak /opt/cinny/config.json
|
||||
rm -f /opt/cinny_config.json.bak
|
||||
msg_ok "Restored Configuration"
|
||||
|
||||
msg_info "Restarting nginx"
|
||||
$STD rc-service nginx restart
|
||||
msg_ok "Updated successfully!"
|
||||
fi
|
||||
exit
|
||||
}
|
||||
|
||||
start
|
||||
build_container
|
||||
description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following IP:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:8080${CL}"
|
||||
@@ -12,6 +12,7 @@ var_ram="${var_ram:-1024}"
|
||||
var_disk="${var_disk:-2}"
|
||||
var_os="${var_os:-alpine}"
|
||||
var_version="${var_version:-3.23}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
|
||||
@@ -12,6 +12,7 @@ var_ram="${var_ram:-256}"
|
||||
var_disk="${var_disk:-1}"
|
||||
var_os="${var_os:-alpine}"
|
||||
var_version="${var_version:-3.23}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -41,5 +42,5 @@ description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:3000${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following URL:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}:3000${CL}"
|
||||
|
||||
+3
-2
@@ -12,6 +12,7 @@ var_ram="${var_ram:-512}"
|
||||
var_disk="${var_disk:-5}"
|
||||
var_os="${var_os:-alpine}"
|
||||
var_version="${var_version:-3.23}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -59,5 +60,5 @@ description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following URL:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}${CL}"
|
||||
|
||||
+3
-2
@@ -12,6 +12,7 @@ var_ram="${var_ram:-256}"
|
||||
var_disk="${var_disk:-3}"
|
||||
var_os="${var_os:-alpine}"
|
||||
var_version="${var_version:-3.23}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -57,5 +58,5 @@ description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following IP:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:8080${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following IP:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}:8080${CL}"
|
||||
|
||||
+3
-2
@@ -12,6 +12,7 @@ var_ram="${var_ram:-256}"
|
||||
var_disk="${var_disk:-1}"
|
||||
var_os="${var_os:-alpine}"
|
||||
var_version="${var_version:-3.23}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -42,5 +43,5 @@ description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:3000${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following URL:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}:3000${CL}"
|
||||
|
||||
@@ -12,6 +12,7 @@ var_ram="${var_ram:-256}"
|
||||
var_disk="${var_disk:-2}"
|
||||
var_os="${var_os:-alpine}"
|
||||
var_version="${var_version:-3.23}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -54,5 +55,6 @@ build_container
|
||||
description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${APP} should be reachable by going to the following URL.
|
||||
${BL}http://${IP}:3000${CL} \n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following URL:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}:3000${CL}"
|
||||
|
||||
+10
-10
@@ -12,6 +12,7 @@ var_ram="${var_ram:-1024}"
|
||||
var_disk="${var_disk:-8}"
|
||||
var_os="${var_os:-alpine}"
|
||||
var_version="${var_version:-3.23}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -21,8 +22,6 @@ catch_errors
|
||||
|
||||
function update_script() {
|
||||
header_info
|
||||
check_container_storage
|
||||
check_container_resources
|
||||
|
||||
if [[ ! -f /usr/local/bin/ironclaw ]]; then
|
||||
msg_error "No ${APP} Installation Found!"
|
||||
@@ -61,11 +60,12 @@ description
|
||||
|
||||
msg_ok "Completed Successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Complete setup by running:${CL}"
|
||||
echo -e "${TAB}${BGN}ironclaw onboard${CL}"
|
||||
echo -e "${INFO}${YW} Then start the service:${CL}"
|
||||
echo -e "${TAB}${BGN}rc-service ironclaw start${CL}"
|
||||
echo -e "${INFO}${YW} Access the Web UI at:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:3000${CL}"
|
||||
echo -e "${INFO}${YW} Auth token and database credentials:${CL}"
|
||||
echo -e "${TAB}${BGN}cat /root/.ironclaw/.env${CL}"
|
||||
echo -e "${INFO}${YW} Next Steps:${CL}"
|
||||
echo -e "${TAB}1. Complete setup by running:${CL}"
|
||||
echo -e "${TAB}${TAB}${BGN}/usr/local/bin/ironclaw onboard${CL}"
|
||||
echo -e "${TAB}2. Start the service:${CL}"
|
||||
echo -e "${TAB}${TAB}${BGN}rc-service ironclaw start${CL}"
|
||||
echo -e "${TAB}3. Access the Web UI at:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}:3000${CL}"
|
||||
echo -e "${INFO}${YW} Use Gateway Authentication Token to login:${CL}"
|
||||
echo -e "${TAB}${TAB}${BGN}cat /root/.ironclaw/gateway.creds${CL}"
|
||||
|
||||
@@ -12,6 +12,7 @@ var_ram="${var_ram:-256}"
|
||||
var_disk="${var_disk:-1}"
|
||||
var_os="${var_os:-alpine}"
|
||||
var_version="${var_version:-3.23}"
|
||||
var_arm64="${var_arm64:-yes}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -50,5 +51,5 @@ description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following IP:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following IP:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}${CL}"
|
||||
|
||||
+3
-2
@@ -12,6 +12,7 @@ var_ram="${var_ram:-1024}"
|
||||
var_disk="${var_disk:-10}"
|
||||
var_os="${var_os:-alpine}"
|
||||
var_version="${var_version:-3.23}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -71,5 +72,5 @@ description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:9120${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following URL:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}:9120${CL}"
|
||||
|
||||
+7
-5
@@ -12,6 +12,7 @@ var_ram="${var_ram:-256}"
|
||||
var_disk="${var_disk:-1}"
|
||||
var_os="${var_os:-alpine}"
|
||||
var_version="${var_version:-3.23}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -53,8 +54,9 @@ start
|
||||
build_container
|
||||
description
|
||||
|
||||
msg_ok "Completed Successfully!\n"
|
||||
echo -e "${APP} should be reachable by going to the following URL.
|
||||
${BL}http://${IP}:3100${CL} \n"
|
||||
echo -e "Promtail should be reachable by going to the following URL.
|
||||
${BL}http://${IP}:9080${CL} \n"
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following URL:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}:3100${CL}"
|
||||
echo -e "${INFO}${YW}Access Promtail using the following URL:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}:9080${CL}"
|
||||
|
||||
@@ -12,6 +12,7 @@ var_ram="${var_ram:-256}"
|
||||
var_disk="${var_disk:-1}"
|
||||
var_os="${var_os:-alpine}"
|
||||
var_version="${var_version:-3.23}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -41,5 +42,5 @@ description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following IP:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}${IP}:3306${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following IP:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}${IP}:3306${CL}"
|
||||
|
||||
@@ -12,6 +12,7 @@ var_ram="${var_ram:-1024}"
|
||||
var_disk="${var_disk:-2}"
|
||||
var_os="${var_os:-alpine}"
|
||||
var_version="${var_version:-3.23}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -56,5 +57,6 @@ build_container
|
||||
description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${APP} should be reachable by going to the following URL.
|
||||
${BL}https://${IP}${CL} \n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following URL:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}https://${IP}${CL}"
|
||||
|
||||
@@ -12,6 +12,7 @@ var_ram="${var_ram:-256}"
|
||||
var_disk="${var_disk:-1}"
|
||||
var_os="${var_os:-alpine}"
|
||||
var_version="${var_version:-3.23}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -45,5 +46,5 @@ description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:1880${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following URL:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}:1880${CL}"
|
||||
|
||||
+3
-4
@@ -13,6 +13,7 @@ var_ram="${var_ram:-256}"
|
||||
var_disk="${var_disk:-2}"
|
||||
var_os="${var_os:-alpine}"
|
||||
var_version="${var_version:-3.23}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -22,8 +23,6 @@ catch_errors
|
||||
|
||||
function update_script() {
|
||||
header_info
|
||||
check_container_storage
|
||||
check_container_resources
|
||||
if [[ ! -d /etc/ntfy ]]; then
|
||||
msg_error "No ${APP} Installation Found!"
|
||||
exit
|
||||
@@ -46,5 +45,5 @@ description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following URL:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}${CL}"
|
||||
|
||||
@@ -12,6 +12,7 @@ var_ram="${var_ram:-256}"
|
||||
var_disk="${var_disk:-1}"
|
||||
var_os="${var_os:-alpine}"
|
||||
var_version="${var_version:-3.23}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -41,5 +42,5 @@ description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following IP:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}${IP}:5432${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following IP:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}${IP}:5432${CL}"
|
||||
|
||||
@@ -12,6 +12,7 @@ var_ram="${var_ram:-256}"
|
||||
var_disk="${var_disk:-1}"
|
||||
var_os="${var_os:-alpine}"
|
||||
var_version="${var_version:-3.23}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -41,5 +42,5 @@ description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:9090${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following URL:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}:9090${CL}"
|
||||
|
||||
+3
-2
@@ -12,6 +12,7 @@ var_ram="${var_ram:-256}"
|
||||
var_disk="${var_disk:-1}"
|
||||
var_os="${var_os:-alpine}"
|
||||
var_version="${var_version:-3.23}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
var_fuse="${var_fuse:-yes}"
|
||||
|
||||
@@ -47,5 +48,5 @@ description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following IP:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:3000${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following IP:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}:3000${CL}"
|
||||
|
||||
+4
-2
@@ -12,6 +12,7 @@ var_ram="${var_ram:-256}"
|
||||
var_disk="${var_disk:-1}"
|
||||
var_os="${var_os:-alpine}"
|
||||
var_version="${var_version:-3.23}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -57,5 +58,6 @@ build_container
|
||||
description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${APP} should be reachable on port 6379.
|
||||
${BL}redis-cli -h ${IP} -p 6379${CL} \n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW}Connect to Redis CLI using the following command:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}redis-cli -h ${IP} -p 6379${CL}"
|
||||
|
||||
+3
-3
@@ -12,6 +12,7 @@ var_ram="${var_ram:-512}"
|
||||
var_disk="${var_disk:-1}"
|
||||
var_os="${var_os:-alpine}"
|
||||
var_version="${var_version:-3.23}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -21,7 +22,6 @@ catch_errors
|
||||
|
||||
function update_script() {
|
||||
header_info
|
||||
check_container_resources
|
||||
|
||||
if [[ ! -d /opt/redlib ]]; then
|
||||
msg_error "No ${APP} Installation Found!"
|
||||
@@ -51,5 +51,5 @@ description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:5252${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following URL:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}:5252${CL}"
|
||||
|
||||
@@ -12,6 +12,7 @@ var_ram="${var_ram:-512}"
|
||||
var_disk="${var_disk:-3}"
|
||||
var_os="${var_os:-alpine}"
|
||||
var_version="${var_version:-3.23}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -71,5 +72,5 @@ description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following IP:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:21114${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following IP:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}:21114${CL}"
|
||||
|
||||
@@ -12,6 +12,7 @@ var_ram="${var_ram:-256}"
|
||||
var_disk="${var_disk:-4}"
|
||||
var_os="${var_os:-alpine}"
|
||||
var_version="${var_version:-3.23}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -21,8 +22,6 @@ catch_errors
|
||||
|
||||
function update_script() {
|
||||
header_info
|
||||
check_container_storage
|
||||
check_container_resources
|
||||
|
||||
if ! apk info -e rustypaste >/dev/null 2>&1; then
|
||||
msg_error "No ${APP} Installation Found!"
|
||||
@@ -47,5 +46,5 @@ description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:8000${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following URL:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}:8000${CL}"
|
||||
|
||||
@@ -12,6 +12,7 @@ var_ram="${var_ram:-256}"
|
||||
var_disk="${var_disk:-1}"
|
||||
var_os="${var_os:-alpine}"
|
||||
var_version="${var_version:-3.23}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -41,5 +42,5 @@ description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:8384${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following URL:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}:8384${CL}"
|
||||
|
||||
@@ -12,6 +12,7 @@ var_ram="${var_ram:-256}"
|
||||
var_disk="${var_disk:-2}"
|
||||
var_os="${var_os:-alpine}"
|
||||
var_version="${var_version:-3.23}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -53,5 +54,5 @@ description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following IP:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}${IP}:9987${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following IP:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}${IP}:9987${CL}"
|
||||
|
||||
@@ -3,7 +3,7 @@ source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxV
|
||||
# Copyright (c) 2021-2026 community-scripts ORG
|
||||
# Author: Slaviša Arežina (tremor021) | Co-Author: Stavros (steveiliop56)
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||
# Source: https://github.com/steveiliop56/tinyauth
|
||||
# Source: https://github.com/tinyauthapp/tinyauth
|
||||
|
||||
APP="Alpine-Tinyauth"
|
||||
var_tags="${var_tags:-alpine;auth}"
|
||||
@@ -12,6 +12,7 @@ var_ram="${var_ram:-256}"
|
||||
var_disk="${var_disk:-2}"
|
||||
var_os="${var_os:-alpine}"
|
||||
var_version="${var_version:-3.23}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -29,7 +30,7 @@ function update_script() {
|
||||
$STD apk -U upgrade
|
||||
msg_ok "Updated packages"
|
||||
|
||||
RELEASE=$(curl -s https://api.github.com/repos/steveiliop56/tinyauth/releases/latest | grep "tag_name" | awk '{print substr($2, 3, length($2)-4) }')
|
||||
RELEASE=$(curl -s https://api.github.com/repos/tinyauthapp/tinyauth/releases/latest | grep "tag_name" | awk '{print substr($2, 3, length($2)-4) }')
|
||||
if [ "${RELEASE}" != "$(cat ~/.tinyauth 2>/dev/null)" ] || [ ! -f ~/.tinyauth ]; then
|
||||
msg_info "Stopping Service"
|
||||
$STD service tinyauth stop
|
||||
@@ -51,7 +52,7 @@ function update_script() {
|
||||
|
||||
msg_info "Updating Tinyauth"
|
||||
rm -f /opt/tinyauth/tinyauth
|
||||
curl -fsSL "https://github.com/steveiliop56/tinyauth/releases/download/v${RELEASE}/tinyauth-amd64" -o /opt/tinyauth/tinyauth
|
||||
curl -fsSL "https://github.com/tinyauthapp/tinyauth/releases/download/v${RELEASE}/tinyauth-amd64" -o /opt/tinyauth/tinyauth
|
||||
chmod +x /opt/tinyauth/tinyauth
|
||||
echo "${RELEASE}" >~/.tinyauth
|
||||
msg_ok "Updated Tinyauth"
|
||||
@@ -72,5 +73,5 @@ description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:3000${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following URL:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}:3000${CL}"
|
||||
|
||||
@@ -12,6 +12,7 @@ var_ram="${var_ram:-512}"
|
||||
var_disk="${var_disk:-1}"
|
||||
var_os="${var_os:-alpine}"
|
||||
var_version="${var_version:-3.23}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -39,4 +40,4 @@ description
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} WebUI Access (if configured) - using the following URL:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:8080/dashboard${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}:8080/dashboard${CL}"
|
||||
|
||||
@@ -12,6 +12,7 @@ var_ram="${var_ram:-256}"
|
||||
var_disk="${var_disk:-1}"
|
||||
var_os="${var_os:-alpine}"
|
||||
var_version="${var_version:-3.23}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -41,5 +42,5 @@ description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:9091${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following URL:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}:9091${CL}"
|
||||
|
||||
+4
-2
@@ -12,6 +12,7 @@ var_ram="${var_ram:-256}"
|
||||
var_disk="${var_disk:-1}"
|
||||
var_os="${var_os:-alpine}"
|
||||
var_version="${var_version:-3.23}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -58,5 +59,6 @@ build_container
|
||||
description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${APP} should be reachable on port 6379.
|
||||
${BL}valkey-cli -h ${IP} -p 6379${CL} \n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW}Connect to Valkey CLI using the following command:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}valkey-cli -h ${IP} -p 6379${CL}"
|
||||
|
||||
@@ -12,6 +12,7 @@ var_ram="${var_ram:-256}"
|
||||
var_disk="${var_disk:-1}"
|
||||
var_os="${var_os:-alpine}"
|
||||
var_version="${var_version:-3.23}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -59,5 +60,6 @@ build_container
|
||||
description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${APP} should be reachable by going to the following URL.
|
||||
${BL}https://${IP}:8000${CL} \n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following URL:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}https://${IP}:8000${CL}"
|
||||
|
||||
+3
-2
@@ -13,6 +13,7 @@ var_ram="${var_ram:-512}"
|
||||
var_disk="${var_disk:-4}"
|
||||
var_os="${var_os:-alpine}"
|
||||
var_version="${var_version:-3.23}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -67,5 +68,5 @@ description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:3000${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following URL:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}:3000${CL}"
|
||||
|
||||
@@ -12,6 +12,7 @@ var_ram="${var_ram:-256}"
|
||||
var_disk="${var_disk:-1}"
|
||||
var_os="${var_os:-alpine}"
|
||||
var_version="${var_version:-3.23}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
var_tun="${var_tun:-1}"
|
||||
|
||||
@@ -46,5 +47,5 @@ description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} WGDashboard Access it using the following URL:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:10086${CL}"
|
||||
echo -e "${INFO}${YW} WGDashboardAccess it using the following URL:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}:10086${CL}"
|
||||
|
||||
@@ -12,6 +12,7 @@ var_cpu="${var_cpu:-1}"
|
||||
var_ram="${var_ram:-256}"
|
||||
var_os="${var_os:-alpine}"
|
||||
var_version="${var_version:-3.23}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-0}"
|
||||
|
||||
header_info "$APP"
|
||||
|
||||
@@ -12,6 +12,7 @@ var_ram="${var_ram:-512}"
|
||||
var_disk="${var_disk:-1}"
|
||||
var_os="${var_os:-alpine}"
|
||||
var_version="${var_version:-3.23}"
|
||||
var_arm64="${var_arm64:-yes}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
|
||||
+8
-15
@@ -12,6 +12,7 @@ var_cpu="${var_cpu:-4}"
|
||||
var_ram="${var_ram:-2048}"
|
||||
var_os="${var_os:-debian}"
|
||||
var_version="${var_version:-13}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -33,24 +34,16 @@ function update_script() {
|
||||
systemctl stop apache2
|
||||
msg_ok "Stopped Service"
|
||||
|
||||
msg_info "Creating Backup"
|
||||
cp /opt/ampache/config/ampache.cfg.php /tmp/ampache.cfg.php.backup
|
||||
cp /opt/ampache/public/rest/.htaccess /tmp/ampache_rest.htaccess.backup
|
||||
cp /opt/ampache/public/play/.htaccess /tmp/ampache_play.htaccess.backup
|
||||
rm -rf /opt/ampache_backup
|
||||
mv /opt/ampache /opt/ampache_backup
|
||||
msg_ok "Created Backup"
|
||||
create_backup /opt/ampache/config/ampache.cfg.php \
|
||||
/opt/ampache/public/rest/.htaccess \
|
||||
/opt/ampache/public/play/.htaccess \
|
||||
/opt/ampache/advanced-config
|
||||
|
||||
fetch_and_deploy_gh_release "Ampache" "ampache/ampache" "prebuild" "latest" "/opt/ampache" "ampache-*_all_php8.4.zip"
|
||||
|
||||
msg_info "Restoring Backup"
|
||||
cp /tmp/ampache.cfg.php.backup /opt/ampache/config/ampache.cfg.php
|
||||
cp /tmp/ampache_rest.htaccess.backup /opt/ampache/public/rest/.htaccess
|
||||
cp /tmp/ampache_play.htaccess.backup /opt/ampache/public/play/.htaccess
|
||||
restore_backup
|
||||
chmod 664 /opt/ampache/public/rest/.htaccess /opt/ampache/public/play/.htaccess
|
||||
chown -R www-data:www-data /opt/ampache
|
||||
rm -f /tmp/ampache*.backup
|
||||
msg_ok "Restored Configuration"
|
||||
|
||||
msg_info "Starting Service"
|
||||
systemctl start apache2
|
||||
@@ -67,5 +60,5 @@ description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}/install.php${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following URL:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}/install.php${CL}"
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
#!/usr/bin/env bash
|
||||
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
|
||||
# Copyright (c) 2021-2026 community-scripts ORG
|
||||
# Author: MickLesk (CanbiZ)
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||
# Source: https://github.com/ZhFahim/anchor
|
||||
|
||||
APP="Anchor"
|
||||
var_tags="${var_tags:-notes;productivity;sync}"
|
||||
var_cpu="${var_cpu:-2}"
|
||||
var_ram="${var_ram:-2048}"
|
||||
var_disk="${var_disk:-10}"
|
||||
var_os="${var_os:-debian}"
|
||||
var_version="${var_version:-13}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
variables
|
||||
color
|
||||
catch_errors
|
||||
|
||||
function update_script() {
|
||||
header_info
|
||||
check_container_storage
|
||||
check_container_resources
|
||||
|
||||
if [[ ! -f ~/.anchor ]]; then
|
||||
msg_error "No ${APP} Installation Found!"
|
||||
exit
|
||||
fi
|
||||
|
||||
if check_for_gh_release "anchor" "ZhFahim/anchor"; then
|
||||
msg_info "Stopping Services"
|
||||
systemctl stop anchor-web anchor-server
|
||||
msg_ok "Stopped Services"
|
||||
|
||||
create_backup /opt/anchor/.env
|
||||
|
||||
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "anchor" "ZhFahim/anchor" "tarball"
|
||||
|
||||
msg_info "Building Server"
|
||||
cd /opt/anchor/server
|
||||
$STD pnpm install --frozen-lockfile
|
||||
$STD pnpm prisma generate
|
||||
$STD pnpm build
|
||||
[[ -d src/generated ]] && mkdir -p dist/src && cp -R src/generated dist/src/
|
||||
msg_ok "Built Server"
|
||||
|
||||
msg_info "Building Web Interface"
|
||||
cd /opt/anchor/web
|
||||
$STD pnpm install --frozen-lockfile
|
||||
SERVER_URL=http://127.0.0.1:3001 $STD pnpm build
|
||||
cp -r .next/static .next/standalone/.next/static
|
||||
cp -r public .next/standalone/public
|
||||
msg_ok "Built Web Interface"
|
||||
|
||||
restore_backup
|
||||
|
||||
msg_info "Running Database Migrations"
|
||||
cd /opt/anchor/server
|
||||
set -a && source /opt/anchor/.env && set +a
|
||||
$STD pnpm prisma migrate deploy
|
||||
msg_ok "Ran Database Migrations"
|
||||
|
||||
msg_info "Starting Services"
|
||||
systemctl start anchor-server anchor-web
|
||||
msg_ok "Started Services"
|
||||
msg_ok "Updated ${APP}"
|
||||
fi
|
||||
exit
|
||||
}
|
||||
|
||||
start
|
||||
build_container
|
||||
description
|
||||
|
||||
msg_ok "Completed Successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following URL:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}:3000${CL}"
|
||||
+6
-10
@@ -13,6 +13,7 @@ var_ram="${var_ram:-4096}"
|
||||
var_disk="${var_disk:-16}"
|
||||
var_os="${var_os:-ubuntu}"
|
||||
var_version="${var_version:-24.04}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -35,17 +36,12 @@ function update_script() {
|
||||
systemctl stop anytype
|
||||
msg_ok "Stopped Service"
|
||||
|
||||
msg_info "Backing up Data"
|
||||
cp -r /opt/anytype/data /opt/anytype_data_backup
|
||||
msg_ok "Backed up Data"
|
||||
create_backup /opt/anytype/data
|
||||
|
||||
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "anytype" "grishy/any-sync-bundle" "prebuild" "latest" "/opt/anytype" "any-sync-bundle_*_linux_amd64.tar.gz"
|
||||
chmod +x /opt/anytype/any-sync-bundle
|
||||
|
||||
msg_info "Restoring Data"
|
||||
cp -r /opt/anytype_data_backup/. /opt/anytype/data
|
||||
rm -rf /opt/anytype_data_backup
|
||||
msg_ok "Restored Data"
|
||||
restore_backup
|
||||
|
||||
msg_info "Starting Service"
|
||||
systemctl start anytype
|
||||
@@ -61,7 +57,7 @@ description
|
||||
|
||||
msg_ok "Completed Successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:33010${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following URL:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}:33010${CL}"
|
||||
echo -e "${INFO}${YW} Client config file:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}/opt/anytype/data/client-config.yml${CL}"
|
||||
echo -e "${GATEWAY}${BGN}/opt/anytype/data/client-config.yml${CL}"
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
#!/usr/bin/env bash
|
||||
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
|
||||
# Copyright (c) 2021-2026 tteck
|
||||
# Author: tteck (tteckster)
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||
# Source: https://cassandra.apache.org/_/index.html
|
||||
|
||||
APP="Apache-Cassandra"
|
||||
var_tags="${var_tags:-database;NoSQL}"
|
||||
var_cpu="${var_cpu:-1}"
|
||||
var_ram="${var_ram:-2048}"
|
||||
var_disk="${var_disk:-4}"
|
||||
var_os="${var_os:-debian}"
|
||||
var_version="${var_version:-13}"
|
||||
var_arm64="${var_arm64:-yes}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
variables
|
||||
color
|
||||
catch_errors
|
||||
|
||||
function update_script() {
|
||||
header_info
|
||||
check_container_storage
|
||||
check_container_resources
|
||||
if [[ ! -f /etc/init.d/cassandra ]]; then
|
||||
msg_error "No ${APP} Installation Found!"
|
||||
exit
|
||||
fi
|
||||
msg_info "Updating Apache Cassandra"
|
||||
$STD apt update
|
||||
$STD apt install -y --only-upgrade cassandra cassandra-tools
|
||||
msg_ok "Updated Apache Cassandra"
|
||||
msg_ok "Updated successfully!"
|
||||
exit
|
||||
}
|
||||
|
||||
start
|
||||
build_container
|
||||
description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
@@ -12,6 +12,7 @@ var_ram="${var_ram:-4096}"
|
||||
var_disk="${var_disk:-10}"
|
||||
var_os="${var_os:-debian}"
|
||||
var_version="${var_version:-13}"
|
||||
var_arm64="${var_arm64:-yes}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -41,5 +42,5 @@ description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:5984/_utils/${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following URL:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}:5984/_utils/${CL}"
|
||||
|
||||
+11
-10
@@ -12,6 +12,7 @@ var_cpu="${var_cpu:-1}"
|
||||
var_ram="${var_ram:-2048}"
|
||||
var_os="${var_os:-debian}"
|
||||
var_version="${var_version:-13}"
|
||||
var_arm64="${var_arm64:-yes}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -89,7 +90,7 @@ function update_script() {
|
||||
# Auth JDBC follows server version
|
||||
msg_info "Updating Guacamole Auth JDBC"
|
||||
rm -f /etc/guacamole/extensions/guacamole-auth-jdbc-mysql-*.jar
|
||||
curl -fsSL "https://downloads.apache.org/guacamole/${LATEST_SERVER}/binary/guacamole-auth-jdbc-${LATEST_SERVER}.tar.gz" -o "/tmp/guacamole-auth-jdbc.tar.gz"
|
||||
curl_download "/tmp/guacamole-auth-jdbc.tar.gz" "https://downloads.apache.org/guacamole/${LATEST_SERVER}/binary/guacamole-auth-jdbc-${LATEST_SERVER}.tar.gz"
|
||||
$STD tar -xf /tmp/guacamole-auth-jdbc.tar.gz -C /tmp
|
||||
mv /tmp/guacamole-auth-jdbc-"${LATEST_SERVER}"/mysql/guacamole-auth-jdbc-mysql-"${LATEST_SERVER}".jar /etc/guacamole/extensions/
|
||||
echo "${LATEST_SERVER}" >~/.guacamole_auth_jdbc
|
||||
@@ -101,7 +102,7 @@ function update_script() {
|
||||
# Update Guacamole Client
|
||||
if [[ "$CURRENT_CLIENT" != "$LATEST_CLIENT" ]]; then
|
||||
msg_info "Updating Guacamole Client (${CURRENT_CLIENT} → ${LATEST_CLIENT})"
|
||||
curl -fsSL "https://downloads.apache.org/guacamole/${LATEST_CLIENT}/binary/guacamole-${LATEST_CLIENT}.war" -o "/opt/apache-guacamole/tomcat9/webapps/guacamole.war"
|
||||
curl_download "/opt/apache-guacamole/tomcat9/webapps/guacamole.war" "https://downloads.apache.org/guacamole/${LATEST_CLIENT}/binary/guacamole-${LATEST_CLIENT}.war"
|
||||
echo "${LATEST_CLIENT}" >~/.guacamole_client
|
||||
msg_ok "Updated Guacamole Client"
|
||||
else
|
||||
@@ -111,7 +112,7 @@ function update_script() {
|
||||
# Update MySQL Connector
|
||||
if [[ "$CURRENT_MYSQL_CONNECTOR" != "$LATEST_MYSQL_CONNECTOR" ]]; then
|
||||
msg_info "Updating MySQL Connector (${CURRENT_MYSQL_CONNECTOR} → ${LATEST_MYSQL_CONNECTOR})"
|
||||
curl -fsSL "https://repo1.maven.org/maven2/com/mysql/mysql-connector-j/${LATEST_MYSQL_CONNECTOR}/mysql-connector-j-${LATEST_MYSQL_CONNECTOR}.jar" -o "/etc/guacamole/lib/mysql-connector-j.jar"
|
||||
curl_download "/etc/guacamole/lib/mysql-connector-j.jar" "https://repo1.maven.org/maven2/com/mysql/mysql-connector-j/${LATEST_MYSQL_CONNECTOR}/mysql-connector-j-${LATEST_MYSQL_CONNECTOR}.jar"
|
||||
echo "${LATEST_MYSQL_CONNECTOR}" >~/.guacamole_mysql_connector
|
||||
msg_ok "Updated MySQL Connector"
|
||||
else
|
||||
@@ -148,7 +149,7 @@ function update_script() {
|
||||
if [[ -f /etc/guacamole/extensions/guacamole-auth-totp-*.jar ]]; then
|
||||
msg_info "Updating TOTP Extension"
|
||||
rm -f /etc/guacamole/extensions/guacamole-auth-totp-*.jar
|
||||
curl -fsSL "https://downloads.apache.org/guacamole/${LATEST_SERVER}/binary/guacamole-auth-totp-${LATEST_SERVER}.tar.gz" -o "/tmp/guacamole-auth-totp.tar.gz"
|
||||
curl_download "/tmp/guacamole-auth-totp.tar.gz" "https://downloads.apache.org/guacamole/${LATEST_SERVER}/binary/guacamole-auth-totp-${LATEST_SERVER}.tar.gz"
|
||||
$STD tar -xf /tmp/guacamole-auth-totp.tar.gz -C /tmp
|
||||
mv /tmp/guacamole-auth-totp-"${LATEST_SERVER}"/guacamole-auth-totp-"${LATEST_SERVER}".jar /etc/guacamole/extensions/
|
||||
chmod 664 /etc/guacamole/extensions/guacamole-auth-totp-"${LATEST_SERVER}".jar
|
||||
@@ -160,7 +161,7 @@ function update_script() {
|
||||
if [[ -f /etc/guacamole/extensions/guacamole-auth-duo-*.jar ]]; then
|
||||
msg_info "Updating DUO Extension"
|
||||
rm -f /etc/guacamole/extensions/guacamole-auth-duo-*.jar
|
||||
curl -fsSL "https://downloads.apache.org/guacamole/${LATEST_SERVER}/binary/guacamole-auth-duo-${LATEST_SERVER}.tar.gz" -o "/tmp/guacamole-auth-duo.tar.gz"
|
||||
curl_download "/tmp/guacamole-auth-duo.tar.gz" "https://downloads.apache.org/guacamole/${LATEST_SERVER}/binary/guacamole-auth-duo-${LATEST_SERVER}.tar.gz"
|
||||
$STD tar -xf /tmp/guacamole-auth-duo.tar.gz -C /tmp
|
||||
mv /tmp/guacamole-auth-duo-"${LATEST_SERVER}"/guacamole-auth-duo-"${LATEST_SERVER}".jar /etc/guacamole/extensions/
|
||||
chmod 664 /etc/guacamole/extensions/guacamole-auth-duo-"${LATEST_SERVER}".jar
|
||||
@@ -172,7 +173,7 @@ function update_script() {
|
||||
if [[ -f /etc/guacamole/extensions/guacamole-auth-ldap-*.jar ]]; then
|
||||
msg_info "Updating LDAP Extension"
|
||||
rm -f /etc/guacamole/extensions/guacamole-auth-ldap-*.jar
|
||||
curl -fsSL "https://downloads.apache.org/guacamole/${LATEST_SERVER}/binary/guacamole-auth-ldap-${LATEST_SERVER}.tar.gz" -o "/tmp/guacamole-auth-ldap.tar.gz"
|
||||
curl_download "/tmp/guacamole-auth-ldap.tar.gz" "https://downloads.apache.org/guacamole/${LATEST_SERVER}/binary/guacamole-auth-ldap-${LATEST_SERVER}.tar.gz"
|
||||
$STD tar -xf /tmp/guacamole-auth-ldap.tar.gz -C /tmp
|
||||
mv /tmp/guacamole-auth-ldap-"${LATEST_SERVER}"/guacamole-auth-ldap-"${LATEST_SERVER}".jar /etc/guacamole/extensions/
|
||||
chmod 664 /etc/guacamole/extensions/guacamole-auth-ldap-"${LATEST_SERVER}".jar
|
||||
@@ -184,7 +185,7 @@ function update_script() {
|
||||
if [[ -f /etc/guacamole/extensions/guacamole-auth-quickconnect-*.jar ]]; then
|
||||
msg_info "Updating Quick Connect Extension"
|
||||
rm -f /etc/guacamole/extensions/guacamole-auth-quickconnect-*.jar
|
||||
curl -fsSL "https://downloads.apache.org/guacamole/${LATEST_SERVER}/binary/guacamole-auth-quickconnect-${LATEST_SERVER}.tar.gz" -o "/tmp/guacamole-auth-quickconnect.tar.gz"
|
||||
curl_download "/tmp/guacamole-auth-quickconnect.tar.gz" "https://downloads.apache.org/guacamole/${LATEST_SERVER}/binary/guacamole-auth-quickconnect-${LATEST_SERVER}.tar.gz"
|
||||
$STD tar -xf /tmp/guacamole-auth-quickconnect.tar.gz -C /tmp
|
||||
mv /tmp/guacamole-auth-quickconnect-"${LATEST_SERVER}"/guacamole-auth-quickconnect-"${LATEST_SERVER}".jar /etc/guacamole/extensions/
|
||||
chmod 664 /etc/guacamole/extensions/guacamole-auth-quickconnect-"${LATEST_SERVER}".jar
|
||||
@@ -196,7 +197,7 @@ function update_script() {
|
||||
if [[ -f /etc/guacamole/extensions/guacamole-history-recording-storage-*.jar ]]; then
|
||||
msg_info "Updating History Recording Storage Extension"
|
||||
rm -f /etc/guacamole/extensions/guacamole-history-recording-storage-*.jar
|
||||
curl -fsSL "https://downloads.apache.org/guacamole/${LATEST_SERVER}/binary/guacamole-history-recording-storage-${LATEST_SERVER}.tar.gz" -o "/tmp/guacamole-history-recording-storage.tar.gz"
|
||||
curl_download "/tmp/guacamole-history-recording-storage.tar.gz" "https://downloads.apache.org/guacamole/${LATEST_SERVER}/binary/guacamole-history-recording-storage-${LATEST_SERVER}.tar.gz"
|
||||
$STD tar -xf /tmp/guacamole-history-recording-storage.tar.gz -C /tmp
|
||||
mv /tmp/guacamole-history-recording-storage-"${LATEST_SERVER}"/guacamole-history-recording-storage-"${LATEST_SERVER}".jar /etc/guacamole/extensions/
|
||||
chmod 664 /etc/guacamole/extensions/guacamole-history-recording-storage-"${LATEST_SERVER}".jar
|
||||
@@ -226,5 +227,5 @@ description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:8080/guacamole${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following URL:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}:8080/guacamole${CL}"
|
||||
|
||||
+3
-2
@@ -12,6 +12,7 @@ var_ram="${var_ram:-2048}"
|
||||
var_disk="${var_disk:-10}"
|
||||
var_os="${var_os:-debian}"
|
||||
var_version="${var_version:-12}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -58,5 +59,5 @@ description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:9998${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following URL:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}:9998${CL}"
|
||||
|
||||
+11
-14
@@ -12,6 +12,7 @@ var_cpu="${var_cpu:-1}"
|
||||
var_ram="${var_ram:-1024}"
|
||||
var_os="${var_os:-debian}"
|
||||
var_version="${var_version:-13}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -25,26 +26,26 @@ function update_script() {
|
||||
check_container_resources
|
||||
|
||||
TOMCAT_DIR=$(ls -d /opt/tomcat-* 2>/dev/null | head -n1)
|
||||
if [[ -z "$TOMCAT_DIR" || ! -d "$TOMCAT_DIR" ]]; then
|
||||
if [[ -z $TOMCAT_DIR || ! -d $TOMCAT_DIR ]]; then
|
||||
msg_error "No ${APP} Installation Found!"
|
||||
exit
|
||||
fi
|
||||
|
||||
# Detect major version and current version from install path (e.g., /opt/tomcat-11 -> 11)
|
||||
TOMCAT_MAJOR=$(basename "$TOMCAT_DIR" | grep -oP 'tomcat-\K[0-9]+')
|
||||
if [[ -z "$TOMCAT_MAJOR" ]]; then
|
||||
if [[ -z $TOMCAT_MAJOR ]]; then
|
||||
msg_error "Cannot determine Tomcat major version from path: $TOMCAT_DIR"
|
||||
exit
|
||||
fi
|
||||
CURRENT_VERSION=$(grep -oP 'Apache Tomcat Version \K[0-9.]+' "$TOMCAT_DIR/RELEASE-NOTES" 2>/dev/null || echo "unknown")
|
||||
LATEST_VERSION=$(curl -fsSL "https://dlcdn.apache.org/tomcat/tomcat-${TOMCAT_MAJOR}/" | grep -oP 'v[0-9]+\.[0-9]+\.[0-9]+(-M[0-9]+)?/' | sort -V | tail -n1 | sed 's/\/$//; s/v//')
|
||||
|
||||
if [[ -z "$LATEST_VERSION" ]]; then
|
||||
if [[ -z $LATEST_VERSION ]]; then
|
||||
msg_error "Failed to fetch latest version for Tomcat ${TOMCAT_MAJOR}"
|
||||
exit
|
||||
fi
|
||||
|
||||
if [[ "$CURRENT_VERSION" == "$LATEST_VERSION" ]]; then
|
||||
if [[ $CURRENT_VERSION == "$LATEST_VERSION" ]]; then
|
||||
msg_ok "${APP} ${CURRENT_VERSION} is already up to date"
|
||||
exit
|
||||
fi
|
||||
@@ -53,13 +54,9 @@ function update_script() {
|
||||
systemctl stop tomcat
|
||||
msg_ok "Stopped Tomcat service"
|
||||
|
||||
msg_info "Backing up configuration and applications"
|
||||
BACKUP_DIR="/tmp/tomcat-backup-$$"
|
||||
mkdir -p "$BACKUP_DIR"
|
||||
cp -a "$TOMCAT_DIR/conf" "$BACKUP_DIR/conf"
|
||||
cp -a "$TOMCAT_DIR/webapps" "$BACKUP_DIR/webapps"
|
||||
[[ -d "$TOMCAT_DIR/lib" ]] && cp -a "$TOMCAT_DIR/lib" "$BACKUP_DIR/lib"
|
||||
msg_ok "Backed up configuration and applications"
|
||||
create_backup $TOMCAT_DIR/conf
|
||||
[[ -d $TOMCAT_DIR/webapps ]] && create_backup $TOMCAT_DIR/webapps
|
||||
[[ -d $TOMCAT_DIR/lib ]] && create_backup $TOMCAT_DIR/lib
|
||||
|
||||
msg_info "Downloading Tomcat ${LATEST_VERSION}"
|
||||
TOMCAT_URL="https://dlcdn.apache.org/tomcat/tomcat-${TOMCAT_MAJOR}/v${LATEST_VERSION}/bin/apache-tomcat-${LATEST_VERSION}.tar.gz"
|
||||
@@ -77,7 +74,7 @@ function update_script() {
|
||||
cp -a "$BACKUP_DIR/webapps"/* "$TOMCAT_DIR/webapps/" 2>/dev/null || true
|
||||
if [[ -d "$BACKUP_DIR/lib" ]]; then
|
||||
for jar in "$BACKUP_DIR/lib"/*.jar; do
|
||||
[[ -f "$jar" ]] || continue
|
||||
[[ -f $jar ]] || continue
|
||||
jar_name=$(basename "$jar")
|
||||
if [[ ! -f "$TOMCAT_DIR/lib/$jar_name" ]]; then
|
||||
cp "$jar" "$TOMCAT_DIR/lib/"
|
||||
@@ -101,5 +98,5 @@ description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:8080${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following URL:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}:8080${CL}"
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
#!/usr/bin/env bash
|
||||
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
|
||||
# Copyright (c) 2021-2026 community-scripts ORG
|
||||
# Author: SystemIdleProcess
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||
# Source: https://github.com/caronc/apprise-api
|
||||
|
||||
APP="Apprise-API"
|
||||
var_tags="${var_tags:-notification}"
|
||||
var_cpu="${var_cpu:-1}"
|
||||
var_ram="${var_ram:-512}"
|
||||
var_disk="${var_disk:-2}"
|
||||
var_os="${var_os:-debian}"
|
||||
var_version="${var_version:-13}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
variables
|
||||
color
|
||||
catch_errors
|
||||
|
||||
function update_script() {
|
||||
header_info
|
||||
check_container_storage
|
||||
check_container_resources
|
||||
|
||||
if [[ ! -d "/opt/apprise" ]]; then
|
||||
msg_error "No ${APP} Installation Found!"
|
||||
exit
|
||||
fi
|
||||
if check_for_gh_release "apprise" "caronc/apprise-api"; then
|
||||
msg_info "Stopping Service"
|
||||
systemctl stop apprise-api
|
||||
msg_ok "Stopped Service"
|
||||
|
||||
PYTHON_VERSION="3.12" setup_uv
|
||||
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "apprise" "caronc/apprise-api" "tarball"
|
||||
|
||||
msg_info "Updating Apprise-API"
|
||||
cd /opt/apprise
|
||||
cp ./requirements.txt /etc/requirements.txt
|
||||
$STD apt install -y nginx git
|
||||
$STD uv pip install -r requirements.txt gunicorn supervisor --system
|
||||
cp -fr apprise_api/static /usr/share/nginx/html/s/
|
||||
mv apprise_api/ webapp
|
||||
touch /etc/nginx/server-override.conf
|
||||
touch /etc/nginx/location-override.conf
|
||||
mkdir -p /config/store /attach /plugin /tmp/apprise /opt/apprise/logs
|
||||
chmod 1777 /tmp/apprise && chmod 777 /config /config/store /attach /plugin /opt/apprise/logs
|
||||
sed -i \
|
||||
-e '/[[]program:nginx]/,/^[[]/ s|stdout_logfile=/dev/stdout|stdout_logfile=/opt/apprise/logs/nginx.log|' \
|
||||
-e '/[[]program:nginx]/,/^[[]/ s|stderr_logfile=/dev/stderr|stderr_logfile=/opt/apprise/logs/nginx_error.log|' \
|
||||
-e '/[[]program:gunicorn]/,/^[[]/ s|stdout_logfile=/dev/stdout|stdout_logfile=/opt/apprise/logs/gunicorn.log|' \
|
||||
-e '/[[]program:gunicorn]/,/^[[]/ s|stderr_logfile=/dev/stderr|stderr_logfile=/opt/apprise/logs/gunicorn_error.log|' \
|
||||
-e '/[[]supervisord]/,/^[[]/ s|logfile=/dev/null|logfile=/opt/apprise/logs/supervisor.log|' \
|
||||
-e 's|_maxbytes=0|_maxbytes=10485760|g' \
|
||||
/opt/apprise/webapp/etc/supervisord.conf
|
||||
msg_ok "Updated Apprise-API"
|
||||
|
||||
msg_info "Starting Service"
|
||||
systemctl start apprise-api
|
||||
msg_ok "Started Service"
|
||||
msg_ok "Updated successfully!"
|
||||
fi
|
||||
exit
|
||||
}
|
||||
|
||||
start
|
||||
build_container
|
||||
description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following URL:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}:8000${CL}"
|
||||
+3
-2
@@ -12,6 +12,7 @@ var_ram="${var_ram:-512}"
|
||||
var_disk="${var_disk:-10}"
|
||||
var_os="${var_os:-debian}"
|
||||
var_version="${var_version:-13}"
|
||||
var_arm64="${var_arm64:-yes}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -41,5 +42,5 @@ description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:3142/acng-report.html${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following URL:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}:3142/acng-report.html${CL}"
|
||||
|
||||
+3
-2
@@ -12,6 +12,7 @@ var_ram="${var_ram:-1024}"
|
||||
var_disk="${var_disk:-8}"
|
||||
var_os="${var_os:-debian}"
|
||||
var_version="${var_version:-12}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -61,5 +62,5 @@ description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:8000/admin/login${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following URL:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}:8000/admin/login${CL}"
|
||||
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
#!/usr/bin/env bash
|
||||
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
|
||||
# Copyright (c) 2021-2026 community-scripts ORG
|
||||
# Author: MickLesk (CanbiZ)
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||
# Source: https://release-argus.io/ | Github: https://github.com/release-argus/Argus
|
||||
|
||||
APP="Argus"
|
||||
var_tags="${var_tags:-watcher}"
|
||||
var_cpu="${var_cpu:-1}"
|
||||
var_ram="${var_ram:-512}"
|
||||
var_disk="${var_disk:-3}"
|
||||
var_os="${var_os:-debian}"
|
||||
var_version="${var_version:-13}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
variables
|
||||
color
|
||||
catch_errors
|
||||
|
||||
function update_script() {
|
||||
header_info
|
||||
check_container_storage
|
||||
check_container_resources
|
||||
if [[ ! -d /opt/argus ]]; then
|
||||
msg_error "No ${APP} Installation Found!"
|
||||
exit
|
||||
fi
|
||||
if check_for_gh_release "argus" "release-argus/Argus"; then
|
||||
msg_info "Stopping service"
|
||||
systemctl stop argus
|
||||
msg_ok "Service stopped"
|
||||
|
||||
fetch_and_deploy_gh_release "Argus" "release-argus/Argus" "singlefile" "latest" "/opt/argus" "Argus*linux-amd64"
|
||||
|
||||
msg_info "Starting service"
|
||||
systemctl start argus
|
||||
msg_ok "Service started"
|
||||
msg_ok "Updated successfully!"
|
||||
fi
|
||||
exit
|
||||
}
|
||||
|
||||
start
|
||||
build_container
|
||||
description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following URL:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}:8080${CL}"
|
||||
+3
-2
@@ -12,6 +12,7 @@ var_ram="${var_ram:-1024}"
|
||||
var_disk="${var_disk:-8}"
|
||||
var_os="${var_os:-debian}"
|
||||
var_version="${var_version:-13}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -41,5 +42,5 @@ description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:6880${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following URL:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}:6880${CL}"
|
||||
|
||||
@@ -12,6 +12,7 @@ var_ram="${var_ram:-2048}"
|
||||
var_disk="${var_disk:-4}"
|
||||
var_os="${var_os:-debian}"
|
||||
var_version="${var_version:-13}"
|
||||
var_arm64="${var_arm64:-yes}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
|
||||
@@ -12,6 +12,7 @@ var_ram="${var_ram:-2048}"
|
||||
var_disk="${var_disk:-5}"
|
||||
var_os="${var_os:-debian}"
|
||||
var_version="${var_version:-13}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -42,5 +43,5 @@ description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:13378${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following URL:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}:13378${CL}"
|
||||
|
||||
+3
-2
@@ -12,6 +12,7 @@ var_ram="${var_ram:-512}"
|
||||
var_disk="${var_disk:-2}"
|
||||
var_os="${var_os:-debian}"
|
||||
var_version="${var_version:-13}"
|
||||
var_arm64="${var_arm64:-yes}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -44,5 +45,5 @@ description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:9091 or https://auth.YOURDOMAIN ${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following URL:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}:9091 or https://auth.YOURDOMAIN ${CL}"
|
||||
|
||||
+273
@@ -0,0 +1,273 @@
|
||||
#!/usr/bin/env bash
|
||||
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
|
||||
# Copyright (c) 2021-2026 community-scripts ORG
|
||||
# Author: Thieneret
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||
# Source: https://github.com/goauthentik/authentik
|
||||
|
||||
APP="authentik"
|
||||
var_tags="${var_tags:-auth}"
|
||||
var_cpu="${var_cpu:-4}"
|
||||
var_ram="${var_ram:-8192}"
|
||||
var_disk="${var_disk:-16}"
|
||||
var_os="${var_os:-debian}"
|
||||
var_version="${var_version:-13}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
variables
|
||||
color
|
||||
catch_errors
|
||||
|
||||
function update_script() {
|
||||
header_info
|
||||
check_container_storage
|
||||
check_container_resources
|
||||
|
||||
if [[ ! -d /opt/authentik ]]; then
|
||||
msg_error "No authentik Installation Found!"
|
||||
exit
|
||||
fi
|
||||
|
||||
read -r MAJOR MINOR PATCH <<< "$(sed 's/^version\///; s/\./ /g' "$HOME/.authentik")"
|
||||
|
||||
msg_info "Update dependencies"
|
||||
ensure_dependencies crossbuild-essential-amd64 gcc-x86-64-linux-gnu cmake clang libunwind-18-dev
|
||||
msg_ok "Update dependencies"
|
||||
|
||||
NODE_VERSION="24" setup_nodejs
|
||||
setup_go
|
||||
UV_PYTHON_INSTALL_DIR="/usr/local/bin" PYTHON_VERSION="3.14.3" setup_uv
|
||||
RUST_PROFILE="minimal" RUST_TOOLCHAIN="stable" setup_rust
|
||||
setup_yq
|
||||
|
||||
AUTHENTIK_VERSION="version/2026.5.3"
|
||||
# Source: https://github.com/goauthentik/fips/blob/main/Makefile#L26
|
||||
XMLSEC_VERSION="1.3.11"
|
||||
|
||||
if check_for_gh_release "geoipupdate" "maxmind/geoipupdate"; then
|
||||
fetch_and_deploy_gh_release "geoipupdate" "maxmind/geoipupdate" "binary"
|
||||
fi
|
||||
|
||||
if check_for_gh_release "xmlsec" "lsh123/xmlsec" "${XMLSEC_VERSION}"; then
|
||||
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "xmlsec" "lsh123/xmlsec" "tarball" "${XMLSEC_VERSION}" "/opt/xmlsec"
|
||||
|
||||
msg_info "Updating xmlsec"
|
||||
cd /opt/xmlsec
|
||||
$STD ./autogen.sh
|
||||
$STD make -j $(nproc)
|
||||
$STD make check
|
||||
$STD make install
|
||||
$STD ldconfig
|
||||
msg_ok "Updated xmlsec"
|
||||
fi
|
||||
|
||||
if check_for_gh_release "authentik" "goauthentik/authentik" "${AUTHENTIK_VERSION}"; then
|
||||
msg_info "Stopping Services"
|
||||
systemctl stop authentik-server authentik-worker
|
||||
if [[ $(systemctl is-active authentik-ldap) == active ]]; then
|
||||
systemctl stop authentik-ldap
|
||||
fi
|
||||
if [[ $(systemctl is-active authentik-rac) == active ]]; then
|
||||
systemctl stop authentik-rac
|
||||
fi
|
||||
if [[ $(systemctl is-active authentik-radius) == active ]]; then
|
||||
systemctl stop authentik-radius
|
||||
fi
|
||||
msg_ok "Stopped Services"
|
||||
|
||||
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "authentik" "goauthentik/authentik" "tarball" "${AUTHENTIK_VERSION}" "/opt/authentik"
|
||||
|
||||
msg_info "Configuring rust"
|
||||
cd /opt/authentik
|
||||
$STD rustup install
|
||||
$STD rustup default "$(sed -n 's/channel = "\(.*\)"/\1/p' rust-toolchain.toml)"
|
||||
msg_ok "Configured rust"
|
||||
|
||||
msg_info "Updating web"
|
||||
cd /opt/authentik/web
|
||||
export NODE_ENV="production"
|
||||
$STD npm install
|
||||
$STD npm run build
|
||||
$STD npm run build:sfe
|
||||
msg_ok "Updated web"
|
||||
|
||||
msg_info "Updating go proxy"
|
||||
cd /opt/authentik
|
||||
export CGO_ENABLED="1"
|
||||
$STD go mod download
|
||||
$STD go build -o /opt/authentik/authentik-server ./cmd/server
|
||||
$STD go build -o /opt/authentik/ldap ./cmd/ldap
|
||||
$STD go build -o /opt/authentik/rac ./cmd/rac
|
||||
$STD go build -o /opt/authentik/radius ./cmd/radius
|
||||
msg_ok "Updated go proxy"
|
||||
|
||||
msg_info "Building worker"
|
||||
export AWS_LC_FIPS_SYS_CC="clang"
|
||||
cd /opt/authentik
|
||||
$STD cargo build --package authentik --no-default-features --features core --locked --release --jobs 1
|
||||
cp ./target/release/authentik /opt/authentik/authentik-worker
|
||||
rm -r ./target
|
||||
msg_ok "Built worker"
|
||||
|
||||
msg_info "Updating python server"
|
||||
export UV_NO_BINARY_PACKAGE="cryptography lxml python-kadmin-rs xmlsec"
|
||||
export UV_COMPILE_BYTECODE="1"
|
||||
export UV_LINK_MODE="copy"
|
||||
export UV_NATIVE_TLS="1"
|
||||
export RUSTUP_PERMIT_COPY_RENAME="true"
|
||||
export UV_PYTHON_INSTALL_DIR="/usr/local/bin"
|
||||
cd /opt/authentik
|
||||
$STD uv sync --frozen --no-install-project --no-dev
|
||||
chown -R authentik:authentik /opt/authentik
|
||||
msg_ok "Updated python server"
|
||||
|
||||
if [[ $MAJOR == 2026 && $MINOR -lt 5 ]]; then
|
||||
msg_info "Updating Worker and Server config"
|
||||
cp /etc/authentik/config.yml /etc/authentik/config.bak
|
||||
yq -i ".postgresql.conn_max_age = 0" /etc/authentik/config.yml
|
||||
yq -i ".postgresql.conn_health_checks = false" /etc/authentik/config.yml
|
||||
yq -i ".listen.debug_tokio = \"[::]:6669\"" /etc/authentik/config.yml
|
||||
yq -i ".log.rust_log.console_subscriber = \"info\"" /etc/authentik/config.yml
|
||||
yq -i ".log.rust_log.h2 = \"info\"" /etc/authentik/config.yml
|
||||
yq -i ".log.rust_log.hyper_util = \"warn\"" /etc/authentik/config.yml
|
||||
yq -i ".log.rust_log.mio = \"info\"" /etc/authentik/config.yml
|
||||
yq -i ".log.rust_log.notify = \"info\"" /etc/authentik/config.yml
|
||||
yq -i ".log.rust_log.reqwest = \"info\"" /etc/authentik/config.yml
|
||||
yq -i ".log.rust_log.runtime = \"info\"" /etc/authentik/config.yml
|
||||
yq -i ".log.rust_log.rustls = \"info\"" /etc/authentik/config.yml
|
||||
yq -i ".log.rust_log.sqlx = \"info\"" /etc/authentik/config.yml
|
||||
yq -i ".log.rust_log.sqlx_postgres = \"info\"" /etc/authentik/config.yml
|
||||
yq -i ".log.rust_log.tokio = \"info\"" /etc/authentik/config.yml
|
||||
yq -i ".log.rust_log.tungstenite = \"info\"" /etc/authentik/config.yml
|
||||
yq -i ".web.workers = 2" /etc/authentik/config.yml
|
||||
mv /etc/default/authentik /etc/default/authentik.bak
|
||||
cat <<EOF >/etc/default/authentik-server
|
||||
TMPDIR=/dev/shm/
|
||||
UV_LINK_MODE=copy
|
||||
UV_PYTHON_DOWNLOADS=0
|
||||
UV_NATIVE_TLS=1
|
||||
VENV_PATH=/opt/authentik/.venv
|
||||
PYTHONDONTWRITEBYTECODE=1
|
||||
PYTHONUNBUFFERED=1
|
||||
PATH=/opt/authentik/lifecycle:/opt/authentik/.venv/bin:/usr/local/bin:/usr/local/sbin:/usr/sbin:/usr/bin:/sbin:/bin
|
||||
DJANGO_SETTINGS_MODULE=authentik.root.settings
|
||||
PROMETHEUS_MULTIPROC_DIR="/tmp/authentik_prometheus_tmp"
|
||||
AUTHENTIK_LISTEN__HTTP="[::]:9000"
|
||||
AUTHENTIK_LISTEN__HTTPS="[::]:9443"
|
||||
AUTHENTIK_LISTEN__METRICS="[::]:9300"
|
||||
EOF
|
||||
cat <<EOF >/etc/default/authentik-worker
|
||||
TMPDIR=/dev/shm/
|
||||
UV_LINK_MODE=copy
|
||||
UV_PYTHON_DOWNLOADS=0
|
||||
UV_NATIVE_TLS=1
|
||||
VENV_PATH=/opt/authentik/.venv
|
||||
PYTHONDONTWRITEBYTECODE=1
|
||||
PYTHONUNBUFFERED=1
|
||||
PATH=/opt/authentik/lifecycle:/opt/authentik/.venv/bin:/usr/local/bin:/usr/local/sbin:/usr/sbin:/usr/bin:/sbin:/bin
|
||||
DJANGO_SETTINGS_MODULE=authentik.root.settings
|
||||
PROMETHEUS_MULTIPROC_DIR="/tmp/authentik_prometheus_tmp"
|
||||
AUTHENTIK_LISTEN__HTTP="[::]:8000"
|
||||
AUTHENTIK_LISTEN__HTTPS="[::]:8443"
|
||||
AUTHENTIK_LISTEN__METRICS="[::]:8300"
|
||||
EOF
|
||||
msg_ok "Updated Worker and Server config!"
|
||||
msg_warn "Please check /etc/default/authentik-worker and /etc/default/authentik-server config files for port configurations!"
|
||||
|
||||
msg_info "Updating services"
|
||||
cat <<EOF >/etc/systemd/system/authentik-server.service
|
||||
[Unit]
|
||||
Description=authentik Go Server (API Gateway)
|
||||
After=network.target
|
||||
Wants=postgresql.service
|
||||
|
||||
[Service]
|
||||
User=authentik
|
||||
Group=authentik
|
||||
ExecStartPre=/usr/bin/mkdir -p "\${PROMETHEUS_MULTIPROC_DIR}"
|
||||
ExecStart=/opt/authentik/authentik-server
|
||||
WorkingDirectory=/opt/authentik/
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
EnvironmentFile=/etc/default/authentik-server
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
cat <<EOF >/etc/systemd/system/authentik-worker.service
|
||||
[Unit]
|
||||
Description=authentik Worker
|
||||
After=network.target postgresql.service
|
||||
|
||||
[Service]
|
||||
User=authentik
|
||||
Group=authentik
|
||||
Type=simple
|
||||
EnvironmentFile=/etc/default/authentik-worker
|
||||
ExecStartPre=/usr/bin/mkdir -p "\${PROMETHEUS_MULTIPROC_DIR}"
|
||||
ExecStart=/opt/authentik/authentik-worker worker
|
||||
WorkingDirectory=/opt/authentik
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
systemctl daemon-reload
|
||||
msg_ok "Updated services"
|
||||
fi
|
||||
fi
|
||||
|
||||
msg_info "Starting Services"
|
||||
systemctl start authentik-server authentik-worker
|
||||
if [[ $(systemctl is-enabled authentik-ldap) == enabled ]]; then
|
||||
systemctl start authentik-ldap
|
||||
fi
|
||||
if [[ $(systemctl is-enabled authentik-rac) == enabled ]]; then
|
||||
systemctl start authentik-rac
|
||||
fi
|
||||
if [[ $(systemctl is-enabled authentik-radius) == enabled ]]; then
|
||||
systemctl start authentik-radius
|
||||
fi
|
||||
msg_ok "Started Services"
|
||||
msg_ok "Updated successfully!"
|
||||
exit
|
||||
}
|
||||
|
||||
start
|
||||
build_container
|
||||
|
||||
msg_info "Attaching data storage volume"
|
||||
$STD pct stop "$CTID"
|
||||
if [ "${PROTECT_CT:-}" == "1" ] || [ "${PROTECT_CT:-}" == "yes" ]; then
|
||||
$STD pct set "$CTID" --protection 0
|
||||
$STD pct set "$CTID" -mp0 "${CONTAINER_STORAGE}":1,mp=/opt/authentik-data,backup=1
|
||||
$STD pct set "$CTID" --protection 1
|
||||
else
|
||||
$STD pct set "$CTID" -mp0 "${CONTAINER_STORAGE}":1,mp=/opt/authentik-data,backup=1
|
||||
fi
|
||||
$STD pct start "$CTID"
|
||||
for i in {1..10}; do
|
||||
pct status "$CTID" | grep -q "status: running" && break
|
||||
sleep 1
|
||||
done
|
||||
$STD pct exec "$CTID" -- bash -c "mkdir -p /opt/authentik-data/{certs,media,geoip,templates}; \
|
||||
cp /opt/authentik/tests/GeoLite2-ASN-Test.mmdb /opt/authentik-data/geoip/GeoLite2-ASN.mmdb; \
|
||||
cp /opt/authentik/tests/GeoLite2-City-Test.mmdb /opt/authentik-data/geoip/GeoLite2-City.mmdb; \
|
||||
chown authentik:authentik /opt/authentik-data; \
|
||||
chown -R authentik:authentik /opt/authentik-data/{certs,media,geoip,templates}"
|
||||
msg_ok "Attached data storage volume"
|
||||
|
||||
msg_info "Starting Services"
|
||||
pct exec "$CTID" -- systemctl enable -q --now authentik-server authentik-worker
|
||||
msg_ok "Started Services"
|
||||
|
||||
description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}https://${IP}:9443${CL}"
|
||||
+3
-2
@@ -12,6 +12,7 @@ var_ram="${var_ram:-2048}"
|
||||
var_disk="${var_disk:-8}"
|
||||
var_os="${var_os:-debian}"
|
||||
var_version="${var_version:-13}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -49,5 +50,5 @@ description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:7474${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following URL:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}:7474${CL}"
|
||||
|
||||
+3
-2
@@ -12,6 +12,7 @@ var_ram="${var_ram:-2048}"
|
||||
var_disk="${var_disk:-6}"
|
||||
var_os="${var_os:-debian}"
|
||||
var_version="${var_version:-13}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -80,5 +81,5 @@ description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:8083${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following URL:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}:8083${CL}"
|
||||
|
||||
+7
-4
@@ -12,6 +12,7 @@ var_cpu="${var_cpu:-2}"
|
||||
var_ram="${var_ram:-2048}"
|
||||
var_os="${var_os:-debian}"
|
||||
var_version="${var_version:-12}"
|
||||
var_arm64="${var_arm64:-yes}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -36,18 +37,20 @@ function update_script() {
|
||||
systemctl stop uwsgi
|
||||
msg_ok "Services Stopped"
|
||||
|
||||
create_backup /opt/babybuddy/babybuddy/settings/production.py
|
||||
|
||||
msg_info "Cleaning old files"
|
||||
cp /opt/babybuddy/babybuddy/settings/production.py /tmp/production.py.bak
|
||||
find . -mindepth 1 -maxdepth 1 ! -name '.venv' -exec rm -rf {} +
|
||||
msg_ok "Cleaned old files"
|
||||
|
||||
fetch_and_deploy_gh_release "babybuddy" "babybuddy/babybuddy" "tarball"
|
||||
restore_backup
|
||||
|
||||
msg_info "Updating ${APP}"
|
||||
cd /opt/babybuddy
|
||||
mv /tmp/production.py.bak /opt/babybuddy/babybuddy/settings/production.py
|
||||
source .venv/bin/activate
|
||||
$STD uv pip install -r requirements.txt
|
||||
export DJANGO_SETTINGS_MODULE=babybuddy.settings.production
|
||||
$STD python manage.py migrate
|
||||
msg_ok "Updated ${APP}"
|
||||
|
||||
@@ -71,5 +74,5 @@ description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following URL:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}${CL}"
|
||||
|
||||
+3
-2
@@ -12,6 +12,7 @@ var_ram="${var_ram:-512}"
|
||||
var_disk="${var_disk:-8}"
|
||||
var_os="${var_os:-debian}"
|
||||
var_version="${var_version:-13}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -49,5 +50,5 @@ description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:9898${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following URL:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}:9898${CL}"
|
||||
|
||||
+8
-10
@@ -12,6 +12,7 @@ var_ram="${var_ram:-512}"
|
||||
var_disk="${var_disk:-4}"
|
||||
var_os="${var_os:-debian}"
|
||||
var_version="${var_version:-13}"
|
||||
var_arm64="${var_arm64:-yes}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -33,22 +34,19 @@ function update_script() {
|
||||
systemctl stop apache2
|
||||
msg_ok "Stopped Service"
|
||||
|
||||
msg_info "Backing up data"
|
||||
mv /opt/baikal /opt/baikal-backup
|
||||
msg_ok "Backed up data"
|
||||
create_backup /opt/baikal/config/baikal.yaml \
|
||||
/opt/baikal/Specific/
|
||||
|
||||
PHP_APACHE="YES" PHP_VERSION="8.3" setup_php
|
||||
setup_composer
|
||||
fetch_and_deploy_gh_release "baikal" "sabre-io/Baikal" "tarball"
|
||||
|
||||
msg_info "Configuring Baikal"
|
||||
cp -r /opt/baikal-backup/config/baikal.yaml /opt/baikal/config/
|
||||
cp -r /opt/baikal-backup/Specific/ /opt/baikal/
|
||||
restore_backup
|
||||
chown -R www-data:www-data /opt/baikal/
|
||||
chmod -R 755 /opt/baikal/
|
||||
|
||||
msg_info "Configuring Baikal"
|
||||
cd /opt/baikal
|
||||
$STD composer install
|
||||
rm -rf /opt/baikal-backup
|
||||
msg_ok "Configured Baikal"
|
||||
|
||||
msg_info "Starting Service"
|
||||
@@ -65,5 +63,5 @@ description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following URL:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}${CL}"
|
||||
|
||||
+10
-21
@@ -12,6 +12,7 @@ var_ram="${var_ram:-2048}"
|
||||
var_disk="${var_disk:-10}"
|
||||
var_os="${var_os:-debian}"
|
||||
var_version="${var_version:-13}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -37,18 +38,18 @@ function update_script() {
|
||||
msg_ok "Stopped Service"
|
||||
|
||||
msg_info "Backing up Configuration and Data"
|
||||
cp /opt/bambuddy/.env /opt/bambuddy.env.bak
|
||||
cp -r /opt/bambuddy/data /opt/bambuddy_data_bak
|
||||
[[ -f /opt/bambuddy/bambuddy.db ]] && cp /opt/bambuddy/bambuddy.db /opt/bambuddy.db.bak
|
||||
[[ -f /opt/bambuddy/bambutrack.db ]] && cp /opt/bambuddy/bambutrack.db /opt/bambutrack.db.bak
|
||||
[[ -d /opt/bambuddy/archive ]] && cp -r /opt/bambuddy/archive /opt/bambuddy_archive_bak
|
||||
create_backup /opt/bambuddy/.env \
|
||||
/opt/bambuddy/data \
|
||||
/opt/bambuddy/bambuddy.db \
|
||||
/opt/bambuddy/bambutrack.db \
|
||||
/opt/bambuddy/archive
|
||||
msg_ok "Backed up Configuration and Data"
|
||||
|
||||
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "bambuddy" "maziggy/bambuddy" "tarball" "latest" "/opt/bambuddy"
|
||||
|
||||
msg_info "Updating Python Dependencies"
|
||||
cd /opt/bambuddy
|
||||
$STD uv venv
|
||||
$STD uv venv --clear
|
||||
$STD uv pip install -r requirements.txt
|
||||
msg_ok "Updated Python Dependencies"
|
||||
|
||||
@@ -58,19 +59,7 @@ function update_script() {
|
||||
$STD npm run build
|
||||
msg_ok "Rebuilt Frontend"
|
||||
|
||||
msg_info "Restoring Configuration and Data"
|
||||
mkdir -p /opt/bambuddy/data
|
||||
cp /opt/bambuddy.env.bak /opt/bambuddy/.env
|
||||
cp -r /opt/bambuddy_data_bak/. /opt/bambuddy/data/
|
||||
[[ -f /opt/bambuddy.db.bak ]] && cp /opt/bambuddy.db.bak /opt/bambuddy/bambuddy.db
|
||||
[[ -f /opt/bambutrack.db.bak ]] && cp /opt/bambutrack.db.bak /opt/bambuddy/bambutrack.db
|
||||
if [[ -d /opt/bambuddy_archive_bak ]]; then
|
||||
mkdir -p /opt/bambuddy/archive
|
||||
cp -r /opt/bambuddy_archive_bak/. /opt/bambuddy/archive/
|
||||
fi
|
||||
rm -f /opt/bambuddy.env.bak /opt/bambuddy.db.bak /opt/bambutrack.db.bak
|
||||
rm -rf /opt/bambuddy_data_bak /opt/bambuddy_archive_bak
|
||||
msg_ok "Restored Configuration and Data"
|
||||
restore_backup
|
||||
|
||||
msg_info "Starting Service"
|
||||
systemctl start bambuddy
|
||||
@@ -86,5 +75,5 @@ description
|
||||
|
||||
msg_ok "Completed Successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:8000${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following URL:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}:8000${CL}"
|
||||
|
||||
+14
-17
@@ -14,6 +14,7 @@ var_ram="${var_ram:-2048}"
|
||||
var_disk="${var_disk:-4}"
|
||||
var_os="${var_os:-debian}"
|
||||
var_version="${var_version:-13}"
|
||||
var_arm64="${var_arm64:-yes}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -36,16 +37,15 @@ function update_script() {
|
||||
|
||||
PHP_VERSION="8.4" PHP_FPM="YES" PHP_MODULE="pdo-sqlite" setup_php
|
||||
|
||||
msg_info "Backing up Bar Assistant"
|
||||
mv /opt/bar-assistant /opt/bar-assistant-backup
|
||||
msg_ok "Backed up Bar Assistant"
|
||||
create_backup /opt/bar-assistant/.env \
|
||||
/opt/bar-assistant/storage/bar-assistant
|
||||
|
||||
fetch_and_deploy_gh_release "bar-assistant" "karlomikus/bar-assistant" "tarball" "latest" "/opt/bar-assistant"
|
||||
setup_composer
|
||||
|
||||
msg_info "Updating Bar-Assistant"
|
||||
cp -r /opt/bar-assistant-backup/.env /opt/bar-assistant/.env
|
||||
cp -r /opt/bar-assistant-backup/storage/bar-assistant /opt/bar-assistant/storage/bar-assistant
|
||||
restore_backup
|
||||
|
||||
msg_info "Configuring Bar-Assistant"
|
||||
cd /opt/bar-assistant
|
||||
$STD composer install --no-interaction
|
||||
$STD php artisan migrate --force
|
||||
@@ -56,8 +56,7 @@ function update_script() {
|
||||
$STD php artisan route:cache
|
||||
$STD php artisan event:cache
|
||||
chown -R www-data:www-data /opt/bar-assistant
|
||||
rm -rf /opt/bar-assistant-backup
|
||||
msg_ok "Updated Bar-Assistant"
|
||||
msg_ok "Configured Bar-Assistant"
|
||||
|
||||
msg_info "Starting nginx"
|
||||
systemctl start nginx
|
||||
@@ -65,23 +64,21 @@ function update_script() {
|
||||
fi
|
||||
|
||||
if check_for_gh_release "vue-salt-rim" "karlomikus/vue-salt-rim"; then
|
||||
msg_info "Backing up Vue Salt Rim"
|
||||
mv /opt/vue-salt-rim /opt/vue-salt-rim-backup
|
||||
msg_ok "Backed up Vue Salt Rim"
|
||||
|
||||
create_backup /opt/vue-salt-rim/public/config.js
|
||||
|
||||
msg_info "Stopping nginx"
|
||||
systemctl stop nginx
|
||||
msg_ok "Stopped nginx"
|
||||
|
||||
fetch_and_deploy_gh_release "vue-salt-rim" "karlomikus/vue-salt-rim" "tarball" "latest" "/opt/vue-salt-rim"
|
||||
restore_backup
|
||||
|
||||
msg_info "Updating Vue Salt Rim"
|
||||
cp /opt/vue-salt-rim-backup/public/config.js /opt/vue-salt-rim/public/config.js
|
||||
msg_info "Configuring Vue Salt Rim"
|
||||
cd /opt/vue-salt-rim
|
||||
$STD npm install
|
||||
$STD npm run build
|
||||
rm -rf /opt/vue-salt-rim-backup
|
||||
msg_ok "Updated Vue Salt Rim"
|
||||
msg_ok "Configured Vue Salt Rim"
|
||||
|
||||
msg_info "Starting nginx"
|
||||
systemctl start nginx
|
||||
@@ -99,5 +96,5 @@ description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following URL:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}${CL}"
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
#!/usr/bin/env bash
|
||||
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
|
||||
# Copyright (c) 2021-2026 community-scripts ORG
|
||||
# Author: MickLesk (CanbiZ)
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||
# Source: https://github.com/baserow/baserow
|
||||
|
||||
APP="Baserow"
|
||||
var_tags="${var_tags:-database;nocode;spreadsheet}"
|
||||
var_cpu="${var_cpu:-4}"
|
||||
var_ram="${var_ram:-10240}"
|
||||
var_disk="${var_disk:-15}"
|
||||
var_os="${var_os:-debian}"
|
||||
var_version="${var_version:-13}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
variables
|
||||
color
|
||||
catch_errors
|
||||
|
||||
function update_script() {
|
||||
header_info
|
||||
check_container_storage
|
||||
check_container_resources
|
||||
|
||||
if [[ ! -d /opt/baserow ]]; then
|
||||
msg_error "No ${APP} Installation Found!"
|
||||
exit
|
||||
fi
|
||||
|
||||
if check_for_gh_release "baserow" "baserow/baserow"; then
|
||||
msg_info "Stopping Services"
|
||||
systemctl stop baserow-backend baserow-celery baserow-celery-beat baserow-celery-export baserow-frontend
|
||||
msg_ok "Stopped Services"
|
||||
|
||||
create_backup /opt/baserow/.env
|
||||
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "baserow" "baserow/baserow" "tarball"
|
||||
restore_backup
|
||||
|
||||
msg_info "Configuring Baserow"
|
||||
cd /opt/baserow/backend
|
||||
$STD uv sync --frozen --no-dev
|
||||
msg_ok "Configured Baserow"
|
||||
|
||||
msg_info "Rebuilding Frontend"
|
||||
cd /opt/baserow/web-frontend
|
||||
$STD npm install
|
||||
$STD npm run build
|
||||
msg_ok "Rebuilt Frontend"
|
||||
|
||||
msg_info "Running Migrations"
|
||||
cd /opt/baserow/backend
|
||||
set -a && source /opt/baserow/.env && set +a
|
||||
export PYTHONPATH="/opt/baserow/backend/src:/opt/baserow/premium/backend/src:/opt/baserow/enterprise/backend/src"
|
||||
$STD /opt/baserow/backend/.venv/bin/python src/baserow/manage.py migrate
|
||||
msg_ok "Ran Migrations"
|
||||
|
||||
msg_info "Starting Services"
|
||||
systemctl start baserow-backend baserow-celery baserow-celery-beat baserow-celery-export baserow-frontend
|
||||
msg_ok "Started Services"
|
||||
msg_ok "Updated successfully!"
|
||||
fi
|
||||
exit
|
||||
}
|
||||
|
||||
start
|
||||
build_container
|
||||
description
|
||||
|
||||
msg_ok "Completed Successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:3000${CL}"
|
||||
+3
-2
@@ -12,6 +12,7 @@ var_ram="${var_ram:-1024}"
|
||||
var_disk="${var_disk:-4}"
|
||||
var_os="${var_os:-debian}"
|
||||
var_version="${var_version:-13}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -65,5 +66,5 @@ description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:6767${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following URL:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}:6767${CL}"
|
||||
|
||||
+9
-13
@@ -12,6 +12,7 @@ var_ram="${var_ram:-4096}"
|
||||
var_disk="${var_disk:-4}"
|
||||
var_os="${var_os:-debian}"
|
||||
var_version="${var_version:-13}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -35,18 +36,13 @@ function update_script() {
|
||||
systemctl stop bentopdf
|
||||
msg_ok "Stopped Service"
|
||||
|
||||
[[ -f /opt/bentopdf/.env.production ]] && cp /opt/bentopdf/.env.production /opt/production.env
|
||||
|
||||
create_backup /opt/bentopdf/.env.production
|
||||
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "bentopdf" "alam00000/bentopdf" "tarball" "latest" "/opt/bentopdf"
|
||||
restore_backup
|
||||
|
||||
msg_info "Updating BentoPDF"
|
||||
msg_info "Configuring BentoPDF"
|
||||
cd /opt/bentopdf
|
||||
$STD npm ci --no-audit --no-fund
|
||||
if [[ -f /opt/production.env ]]; then
|
||||
mv /opt/production.env ./.env.production
|
||||
else
|
||||
cp ./.env.example ./.env.production
|
||||
fi
|
||||
export NODE_OPTIONS="--max-old-space-size=3072"
|
||||
export SIMPLE_MODE=true
|
||||
export VITE_USE_CDN=true
|
||||
@@ -63,9 +59,9 @@ EOF
|
||||
if [[ ! -f /etc/ssl/private/bentopdf-selfsigned.key || ! -f /etc/ssl/certs/bentopdf-selfsigned.crt ]]; then
|
||||
CERT_CN="$(hostname -I | awk '{print $1}')"
|
||||
$STD openssl req -x509 -nodes -newkey rsa:2048 -days 3650 \
|
||||
-keyout /etc/ssl/private/bentopdf-selfsigned.key \
|
||||
-out /etc/ssl/certs/bentopdf-selfsigned.crt \
|
||||
-subj "/CN=${CERT_CN}"
|
||||
-keyout /etc/ssl/private/bentopdf-selfsigned.key \
|
||||
-out /etc/ssl/certs/bentopdf-selfsigned.crt \
|
||||
-subj "/CN=${CERT_CN}"
|
||||
fi
|
||||
cat <<'EOF' >/etc/nginx/sites-available/bentopdf
|
||||
server {
|
||||
@@ -155,5 +151,5 @@ description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}https://${IP}:8443${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following URL:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}https://${IP}:8443${CL}"
|
||||
|
||||
+6
-3
@@ -12,6 +12,7 @@ var_ram="${var_ram:-512}"
|
||||
var_disk="${var_disk:-5}"
|
||||
var_os="${var_os:-debian}"
|
||||
var_version="${var_version:-13}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -36,7 +37,9 @@ function update_script() {
|
||||
msg_info "Updating Beszel"
|
||||
$STD /opt/beszel/beszel update
|
||||
sleep 2 && chmod +x /opt/beszel/beszel
|
||||
msg_ok "Updated Beszel"
|
||||
VERSION=$(/opt/beszel/beszel -v | awk '{print $3}')
|
||||
echo "${VERSION}" >$HOME/.beszel
|
||||
msg_ok "Updated Beszel to ${VERSION}"
|
||||
|
||||
msg_info "Starting Service"
|
||||
systemctl start beszel-hub
|
||||
@@ -52,5 +55,5 @@ description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following IP:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:8090${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following IP:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}:8090${CL}"
|
||||
|
||||
+85
-4
@@ -12,6 +12,7 @@ var_ram="${var_ram:-1024}"
|
||||
var_disk="${var_disk:-4}"
|
||||
var_os="${var_os:-debian}"
|
||||
var_version="${var_version:-13}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -28,14 +29,94 @@ function update_script() {
|
||||
exit
|
||||
fi
|
||||
|
||||
CURRENT_VERSION="unknown"
|
||||
if [[ -f /root/.bichon ]]; then
|
||||
CURRENT_VERSION=$(cat /root/.bichon)
|
||||
fi
|
||||
|
||||
MIGRATE_V1=0
|
||||
if [[ $CURRENT_VERSION == 0.* ]]; then
|
||||
MIGRATE_V1=1
|
||||
DISK_USAGE=$(df / | awk 'NR==2 {print $5}' | sed 's/%//')
|
||||
if [ "$DISK_USAGE" -gt 50 ]; then
|
||||
echo -e "\n${RD}Warning: Less than 50% free storage remaining on the root disk.${CL}"
|
||||
echo -e "${RD}Bichon v1 data migration temporarily duplicates data and requires free space for it.${CL}"
|
||||
read -r -p "Are you sure you want to proceed with the update? (y/N): " proceed
|
||||
if [[ ! $proceed =~ ^[Yy]$ ]]; then
|
||||
msg_error "Update cancelled by user."
|
||||
exit
|
||||
fi
|
||||
fi
|
||||
|
||||
RAM_TOTAL=$(free -m | awk '/^Mem:/{print $2}')
|
||||
if [ "$RAM_TOTAL" -lt 2000 ]; then
|
||||
echo -e "\n${RD}Warning: LXC has less than 2GB of RAM allocated (${RAM_TOTAL}MB).${CL}"
|
||||
echo -e "${RD}Bichon v1 data migration consumes significant memory and may crash if insufficient.${CL}"
|
||||
read -r -p "Are you sure you want to proceed with the update? (y/N): " proceed_ram
|
||||
if [[ ! $proceed_ram =~ ^[Yy]$ ]]; then
|
||||
msg_error "Update cancelled by user."
|
||||
exit
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if check_for_gh_release "bichon" "rustmailer/bichon"; then
|
||||
msg_info "Stopping service"
|
||||
systemctl stop bichon
|
||||
msg_ok "Stopped service"
|
||||
|
||||
cp /opt/bichon/bichon.env /tmp/bichon.env.backup
|
||||
create_backup /opt/bichon/bichon.env
|
||||
|
||||
if [ "$MIGRATE_V1" -eq 1 ] && [ "$CURRENT_VERSION" != "0.3.7" ]; then
|
||||
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "bichon" "rustmailer/bichon" "prebuild" "v0.3.7" "/opt/bichon" "bichon-*-x86_64-unknown-linux-gnu.tar.gz"
|
||||
restore_backup
|
||||
msg_info "Updating to intermediate version v0.3.7"
|
||||
systemctl start bichon
|
||||
sleep 30
|
||||
systemctl stop bichon
|
||||
msg_ok "Intermediate update completed"
|
||||
fi
|
||||
|
||||
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "bichon" "rustmailer/bichon" "prebuild" "latest" "/opt/bichon" "bichon-*-x86_64-unknown-linux-gnu.tar.gz"
|
||||
cp /tmp/bichon.env.backup /opt/bichon/bichon.env
|
||||
restore_backup
|
||||
|
||||
if [ "$MIGRATE_V1" -eq 1 ]; then
|
||||
msg_info "Running Bichon v1 Data Migration (patience)"
|
||||
$STD apt install -y expect
|
||||
$STD expect <<'EOF'
|
||||
set timeout -1
|
||||
spawn /opt/bichon/bichon-admin
|
||||
expect "*Select an operation*"
|
||||
send "\033\[B\r"
|
||||
expect "*--bichon-root-dir*"
|
||||
send "/opt/bichon-data\r"
|
||||
expect "*--bichon-index-dir*"
|
||||
send "\r"
|
||||
expect "*--bichon-data-dir*"
|
||||
send "\r"
|
||||
expect "*Ready to migrate?*"
|
||||
send "y"
|
||||
expect "*Enter batch size*"
|
||||
send "1000\r"
|
||||
expect eof
|
||||
catch wait
|
||||
EOF
|
||||
$STD apt remove --purge expect -y
|
||||
$STD apt autoremove -y
|
||||
msg_ok "Migration completed"
|
||||
|
||||
msg_info "Cleaning up legacy Bichon v0.x storage files"
|
||||
rm -rf /opt/bichon-data/envelope
|
||||
rm -rf /opt/bichon-data/eml
|
||||
rm -f /opt/bichon-data/mailbox.db
|
||||
rm -f /opt/bichon-data/meta.db
|
||||
msg_ok "Cleanup completed"
|
||||
|
||||
msg_info "Updating Bichon service for v1"
|
||||
sed -i 's|ExecStart=/opt/bichon/bichon|ExecStart=/opt/bichon/bichon-server|g; s|RestartSec=5|RestartSec=5\n\nLimitNOFILE=65536|g' /etc/systemd/system/bichon.service
|
||||
systemctl daemon-reload
|
||||
msg_ok "Service updated"
|
||||
fi
|
||||
|
||||
msg_info "Starting service"
|
||||
systemctl start bichon
|
||||
@@ -51,5 +132,5 @@ description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:15630${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following URL:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}:15630${CL}"
|
||||
|
||||
+4
-2
@@ -13,6 +13,7 @@ var_ram="${var_ram:-2048}"
|
||||
var_disk="${var_disk:-12}"
|
||||
var_os="${var_os:-debian}"
|
||||
var_version="${var_version:-13}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
var_gpu="${var_gpu:-no}"
|
||||
|
||||
@@ -42,6 +43,7 @@ function update_script() {
|
||||
cp /opt/birdnet/birdnet-go /usr/local/bin/birdnet-go
|
||||
chmod +x /usr/local/bin/birdnet-go
|
||||
cp -r /opt/birdnet/libtensorflowlite_c.so /usr/local/lib/ || true
|
||||
cp -r /opt/birdnet/libonnxruntime.so /usr/local/lib/ || true
|
||||
ldconfig
|
||||
msg_ok "Deployed Binary"
|
||||
|
||||
@@ -59,5 +61,5 @@ description
|
||||
|
||||
msg_ok "Completed Successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:8080${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following URL:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}:8080${CL}"
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
#!/usr/bin/env bash
|
||||
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
|
||||
# Copyright (c) 2021-2026 community-scripts ORG
|
||||
# Author: glabutis
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||
# Source: https://github.com/bitfocus/companion
|
||||
|
||||
APP="Bitfocus-Companion"
|
||||
var_tags="${var_tags:-automation;media}"
|
||||
var_cpu="${var_cpu:-2}"
|
||||
var_ram="${var_ram:-512}"
|
||||
var_disk="${var_disk:-8}"
|
||||
var_os="${var_os:-debian}"
|
||||
var_version="${var_version:-12}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
variables
|
||||
color
|
||||
catch_errors
|
||||
|
||||
function update_script() {
|
||||
header_info
|
||||
check_container_storage
|
||||
check_container_resources
|
||||
|
||||
if [[ ! -f /opt/bitfocus-companion/companion_headless.sh ]]; then
|
||||
msg_error "No ${APP} Installation Found!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
RELEASE_JSON=$(curl -fsSL "https://api.bitfocus.io/v1/product/companion/packages?limit=20")
|
||||
PACKAGE_JSON=$(echo "$RELEASE_JSON" | jq -c '(if type == "array" then . else .packages end) | [.[] | select(.target=="linux-tgz" and (.uri | contains("linux-x64")))] | first')
|
||||
RELEASE=$(echo "$PACKAGE_JSON" | jq -r '.version // empty')
|
||||
ASSET_URL=$(echo "$PACKAGE_JSON" | jq -r '.uri // empty')
|
||||
if [[ -z "$RELEASE" || -z "$ASSET_URL" ]]; then
|
||||
msg_error "Could not resolve a matching Linux x64 Companion package from the Bitfocus API."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "${RELEASE}" == "$(cat ~/.bitfocus-companion 2>/dev/null)" ]]; then
|
||||
msg_ok "No update required. ${APP} is already at v${RELEASE}"
|
||||
exit
|
||||
fi
|
||||
|
||||
msg_info "Stopping ${APP}"
|
||||
systemctl stop bitfocus-companion
|
||||
msg_ok "Stopped ${APP}"
|
||||
|
||||
msg_info "Updating ${APP} to v${RELEASE}"
|
||||
CLEAN_INSTALL=1 fetch_and_deploy_from_url "$ASSET_URL" "/opt/bitfocus-companion"
|
||||
echo "${RELEASE}" >~/.bitfocus-companion
|
||||
msg_ok "Updated ${APP} to v${RELEASE}"
|
||||
|
||||
msg_info "Starting ${APP}"
|
||||
systemctl start bitfocus-companion
|
||||
msg_ok "Started ${APP}"
|
||||
|
||||
msg_ok "Update Successful"
|
||||
exit
|
||||
}
|
||||
|
||||
start
|
||||
build_container
|
||||
description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following URL:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}:8000${CL}"
|
||||
+9
-10
@@ -12,6 +12,7 @@ var_ram="${var_ram:-1024}"
|
||||
var_disk="${var_disk:-4}"
|
||||
var_os="${var_os:-debian}"
|
||||
var_version="${var_version:-13}"
|
||||
var_arm64="${var_arm64:-yes}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -55,21 +56,19 @@ function update_script() {
|
||||
bitmagnet \
|
||||
>/tmp/backup.sql
|
||||
mv /tmp/backup.sql /opt/
|
||||
[ -f /opt/bitmagnet/.env ] && cp /opt/bitmagnet/.env /opt/
|
||||
[ -f /opt/bitmagnet/config.yml ] && cp /opt/bitmagnet/config.yml /opt/
|
||||
create_backup /opt/bitmagnet/.env \
|
||||
/opt/bitmagnet/config.yml
|
||||
msg_ok "Data backed up"
|
||||
|
||||
rm -rf /opt/bitmagnet
|
||||
fetch_and_deploy_gh_release "bitmagnet" "bitmagnet-io/bitmagnet" "tarball"
|
||||
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "bitmagnet" "bitmagnet-io/bitmagnet" "tarball"
|
||||
restore_backup
|
||||
|
||||
msg_info "Updating Bitmagnet"
|
||||
msg_info "Configuring Bitmagnet"
|
||||
cd /opt/bitmagnet
|
||||
VREL=v$(curl -fsSL https://api.github.com/repos/bitmagnet-io/bitmagnet/releases/latest | grep "tag_name" | awk '{print substr($2, 3, length($2)-4) }')
|
||||
$STD go build -ldflags "-s -w -X github.com/bitmagnet-io/bitmagnet/internal/version.GitTag=$VREL"
|
||||
chmod +x bitmagnet
|
||||
[ -f "/opt/.env" ] && cp "/opt/.env" /opt/bitmagnet/
|
||||
[ -f "/opt/config.yml" ] && cp "/opt/config.yml" /opt/bitmagnet/
|
||||
msg_ok "Updated Bitmagnet"
|
||||
msg_ok "Configured Bitmagnet"
|
||||
|
||||
msg_info "Starting Service"
|
||||
systemctl start bitmagnet-web
|
||||
@@ -85,5 +84,5 @@ description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:3333${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following URL:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}:3333${CL}"
|
||||
|
||||
+5
-10
@@ -12,6 +12,7 @@ var_ram="${var_ram:-512}"
|
||||
var_disk="${var_disk:-2}"
|
||||
var_os="${var_os:-debian}"
|
||||
var_version="${var_version:-13}"
|
||||
var_arm64="${var_arm64:-no}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
@@ -32,15 +33,9 @@ function update_script() {
|
||||
systemctl stop blocky
|
||||
msg_ok "Stopped Service"
|
||||
|
||||
msg_info "Backup Config"
|
||||
mv /opt/blocky/config.yml /opt/config.yml
|
||||
msg_ok "Backed Up Config"
|
||||
|
||||
create_backup /opt/blocky/config.yml
|
||||
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "blocky" "0xERR0R/blocky" "prebuild" "latest" "/opt/blocky" "blocky_*_Linux_x86_64.tar.gz"
|
||||
|
||||
msg_info "Restore Config"
|
||||
mv /opt/config.yml /opt/blocky/config.yml
|
||||
msg_ok "Restored Config"
|
||||
restore_backup
|
||||
|
||||
msg_info "Starting Service"
|
||||
systemctl start blocky
|
||||
@@ -56,5 +51,5 @@ description
|
||||
|
||||
msg_ok "Completed successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following URL:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}${CL}"
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
#!/usr/bin/env bash
|
||||
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
|
||||
# Copyright (c) 2021-2026 community-scripts ORG
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||
|
||||
APP="BookLore"
|
||||
|
||||
header_info "$APP"
|
||||
variables
|
||||
color
|
||||
|
||||
msg_error "This script is no longer available in community-scripts."
|
||||
msg_error "The Booklore or the Grimmory Fork will for now not return to community-scripts. Due to the unstable nature of these projects we decided to remove them and will decide at later point if they come back, which will most likley not happen. Plese do not create Issues for this."
|
||||
msg_warn "More info: https://community-scripts.org/scripts/booklore"
|
||||
exit 1
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user