mirror of
https://github.com/community-scripts/ProxmoxVE.git
synced 2026-04-28 05:10:40 +00:00
Compare commits
1013 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 200b02577f | |||
| 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 | |||
| 33716c92e5 | |||
| dda2ea811f | |||
| 392ff1f575 | |||
| af9bf93707 | |||
| cfe5e7baa7 | |||
| 1d609976d3 | |||
| 041de06a4d | |||
| f0bfec1b59 | |||
| 83ef4a5857 | |||
| 0baafa3993 | |||
| e55fe43e2d | |||
| 482f579dc0 | |||
| 2652ae6c95 | |||
| e9f802dd29 | |||
| 60957a8eee | |||
| 0bf87f6fcc | |||
| 3dd3040010 | |||
| 6a86f52c0e | |||
| 346dfd8bf7 | |||
| 2331f92c32 | |||
| 66ec27a1fb | |||
| 9e1c4a39a1 | |||
| 7c6460f903 | |||
| c3f7cc4d32 | |||
| 41fc57072a | |||
| d8b0ea0490 | |||
| 86a40ebfbe | |||
| bea342ba04 | |||
| dd86af007e | |||
| 146cd312d5 | |||
| 8b0156ede8 | |||
| f8668c74fc | |||
| ecb4d36d6a | |||
| daaa137cec | |||
| e820d58f2e | |||
| 90bc07f65b | |||
| b40bc46b4b | |||
| cacc04b26d | |||
| e9e65854cc | |||
| 017e709ac7 | |||
| ba876c7495 | |||
| 0d2d1f46f5 | |||
| 5e865278e9 | |||
| a18642a8f8 | |||
| 9a82ec48b2 | |||
| f2d46dd8c8 | |||
| 2707295eba | |||
| 82cc074b05 | |||
| 6b224ac649 | |||
| a69f9955f4 | |||
| 7d19269122 | |||
| 498d37ae3a | |||
| 703ad0ecb7 | |||
| ae6cf7666e | |||
| 2c2beab3ce | |||
| a10100d66a | |||
| 41848653d6 | |||
| 1eb246ee41 | |||
| 68b486be92 | |||
| 9dd4bff9c5 | |||
| ae3e1deece | |||
| c11b2e9db2 | |||
| f7c2477e09 | |||
| 8b7c620f92 | |||
| d3a935e347 | |||
| 74c430ddf2 | |||
| be0d0a6a7a | |||
| 507ad186dd | |||
| 927e7181c2 | |||
| c5083471d9 | |||
| fb6c428a0f | |||
| ac3cf75b11 | |||
| 8e010cacfe | |||
| a7a6d5dd17 | |||
| 046e8c749a | |||
| daffd75719 | |||
| c999a61c60 | |||
| e8201ef3e5 | |||
| 10af5efd6b | |||
| 00fdd3a3c5 | |||
| 0c5bcb8122 | |||
| 42c02d1326 | |||
| 5d84c935e5 | |||
| f489db21cd | |||
| a674e84eef | |||
| ec8b73c148 | |||
| e5fd7e4436 | |||
| c2d5b27a79 | |||
| b72d91ef8e | |||
| 9ef3b919c7 | |||
| 70a9d99ecd | |||
| e247a8ee8b | |||
| 68e009e9c6 | |||
| f652864208 | |||
| 59c0052bc8 | |||
| 05748eb1ed | |||
| f2d6840756 | |||
| 9ce2fe9ee0 | |||
| 0b24786695 | |||
| 1abce0c695 | |||
| 762d1e731e | |||
| 3f04e49f04 | |||
| 730176268e | |||
| bff20d3b61 | |||
| 3f8db3bcdb | |||
| 1f5b489d4a | |||
| 428436db71 | |||
| f3a881e6f7 | |||
| 4241c34d3c | |||
| 37588ce5f7 | |||
| 44ddf4cfa7 | |||
| 67f5d213c2 | |||
| 5540d57431 | |||
| 2acac05ddb | |||
| 1a41665a83 | |||
| 1025c7218b | |||
| 3e714b6f6d | |||
| 70cc9749fa | |||
| ffffe960ce | |||
| 4f9f5a64c9 | |||
| 7c482ef06e | |||
| 0d2a24c712 | |||
| ca7811fd1a | |||
| 59eed2646c | |||
| 9789c46e20 | |||
| f2861e108b | |||
| 9a259a96cc | |||
| 997946d65b | |||
| 28e3362b6a | |||
| 8275531161 | |||
| b6907269e8 | |||
| c53ce61472 | |||
| 7511415b89 | |||
| 2b966298f1 | |||
| f985c7e952 | |||
| 76e95ec1d8 | |||
| 8f335651da | |||
| 02257e2a67 | |||
| 263bc371ec | |||
| 78b2c45863 | |||
| d5924f780c | |||
| 8a5d268bd7 | |||
| abb8772e27 | |||
| 699fd14e29 | |||
| 44de5dc34c | |||
| 713677f39f | |||
| 96772b3c28 | |||
| 4ab821815f | |||
| b978e17e0b | |||
| c6bbba090d | |||
| f6cb8caa08 | |||
| fb9547c03b | |||
| 9e129ecf85 | |||
| 52ad08e331 | |||
| 2f51b6c13c | |||
| a17e36bbcb | |||
| 4be8346df9 | |||
| 5e50b79046 | |||
| 30351670b7 | |||
| 022f177d0c | |||
| 46dc693c99 | |||
| 744097ac0d | |||
| 2f3d393726 | |||
| 1085aa5cf6 | |||
| f07f7993ab | |||
| 45b3a62dd5 | |||
| 2eb259bd99 | |||
| 21584a7a5a | |||
| 0c1d6c688b | |||
| 9239ecf10d | |||
| dc9fb678af | |||
| 18359679d9 | |||
| 6dd227859e | |||
| 3e5a5305f6 | |||
| e72400b417 | |||
| 30adc4fca3 | |||
| 6017a124f9 | |||
| 924f1accd7 | |||
| 9a0ab814af | |||
| 1fb8e10c42 | |||
| 81516991a8 | |||
| 095783de3e | |||
| 11777a51cc | |||
| 88e1813f96 | |||
| 6c44215000 | |||
| d4e20816c7 | |||
| d12a0f1701 | |||
| fbe5b57c76 | |||
| b14dfccc99 | |||
| 38a283e549 | |||
| d06a70819d | |||
| 53e73e2f1a | |||
| ee66508879 | |||
| 83cfa0b5b4 | |||
| 0a458c0a11 | |||
| 6703fca0e4 | |||
| 42fbf1afc5 | |||
| d1c5b03fa7 | |||
| b9a39db667 | |||
| 0872f086ef | |||
| 4eecca8aea | |||
| d915dee103 | |||
| 97bf744e96 | |||
| 7425f5d8fe | |||
| 53bc492fdb | |||
| de356fa8b6 | |||
| 00c538dc3b | |||
| 7c4882384f | |||
| 8e4d174a65 | |||
| d7112450c7 | |||
| caf03fe274 | |||
| e731ddf61d | |||
| 86f5c48fc2 | |||
| d1d786cbc7 | |||
| 1c3c223e51 | |||
| 0980a85021 | |||
| 81547bb7a1 | |||
| c62e1ba882 | |||
| 201a26a19e | |||
| 1dda554e40 | |||
| 6b1b255ff6 | |||
| 5d2fea107d | |||
| 86c658909a | |||
| 9aa0390553 | |||
| c8606e9fcc | |||
| 283e762b83 | |||
| 15b5542ad6 | |||
| b1604ceae0 | |||
| 89c205d57c | |||
| 5c795395ca | |||
| 1512711435 | |||
| a2616ee258 | |||
| 4ce6271ec0 | |||
| da932e62d0 | |||
| c2838b69ce | |||
| 676397add0 | |||
| ec7f2a2e33 | |||
| e2027a43b4 | |||
| f29606ae87 | |||
| 7ed27dcdb8 | |||
| e804a4728e | |||
| c5fb74df46 | |||
| 791981ba68 | |||
| f1f7bd17b0 | |||
| 7e470080b6 | |||
| e97053152a | |||
| 3b8550e314 | |||
| 9c3b6a1a94 | |||
| 7a2c754cea | |||
| 00faa7a937 | |||
| d26095dff3 | |||
| b0fa21efdf | |||
| f26adc2208 | |||
| 624607ca48 | |||
| 4a8aed39da | |||
| 2922ecdcbb | |||
| e7dcd37cf7 | |||
| 586d8dd8a7 | |||
| 8a17729812 | |||
| cf99d6ad3e | |||
| 932f4dc134 | |||
| a7131a5df7 | |||
| b4fd23e3f6 | |||
| 9c86e0f133 | |||
| 366e6951b0 | |||
| 72a2ade7c0 | |||
| 6cc2c26573 | |||
| 55324dbb98 | |||
| b54b21d866 | |||
| a48bfe8d0f | |||
| ede91aeb90 | |||
| f638f00291 | |||
| 852a3f4fec | |||
| 572ddddb17 | |||
| 06c99d43a2 | |||
| 2854494dc5 | |||
| 57c929eb81 | |||
| 9bc0bf02f3 | |||
| 62e3335adf | |||
| 2d46978205 | |||
| f00c7d3703 | |||
| 8651abd74b | |||
| 56817ba52d | |||
| 8512144bb6 | |||
| 9f2b0bb5ee | |||
| a096fa19be | |||
| d73def58fc | |||
| fa2d2afc06 | |||
| b9c230fbb0 | |||
| d35e982f11 | |||
| b62b8c053b | |||
| 70b9ba8be0 | |||
| c9bf3de31f | |||
| 3dbf115e0b | |||
| 185dd557ee | |||
| c2705928a7 | |||
| 50c422f11b | |||
| fd96117bc4 | |||
| 2cbba485b3 | |||
| 25c21835cc | |||
| 8c35c68c9c | |||
| d9addf78a3 | |||
| 245433f535 | |||
| 0c70fa5a5b | |||
| d45129c039 | |||
| fa57b7a1d3 | |||
| d0af062c18 | |||
| 23290f4042 | |||
| 8c452e855b | |||
| 24ce6e006b | |||
| 84c7647841 | |||
| 24429475f8 | |||
| 32127096e5 | |||
| 923fbf96d8 | |||
| 1ce0af9455 | |||
| 8879b8ec2e | |||
| 1c74a7b1b1 | |||
| 2a11d8e2d3 | |||
| 31750a6896 | |||
| 1754b68327 | |||
| 2a7b6c8d86 | |||
| ba01175bc6 | |||
| 607eff0939 | |||
| df51f7114e | |||
| 79805f5f3d | |||
| 59c601e0e2 | |||
| 7c467bee7b | |||
| d2e5991416 | |||
| 73e6d4b855 | |||
| a53a851cc9 | |||
| 2001a43229 | |||
| d35249b8f4 | |||
| 9f73b6756e | |||
| 192e2950e7 | |||
| 20c4657f39 | |||
| e20fed1a2d | |||
| 8b4f0f60e1 | |||
| bd91c4d07f | |||
| 6bb264491c | |||
| 852e557b1b | |||
| c5caca97fd | |||
| dff876fb5c | |||
| 02e7e5af8d | |||
| 0f4bfc0b5a | |||
| 152be10741 | |||
| 341489ea3f | |||
| ee7829496f | |||
| b67cbc1585 | |||
| bf17edcc89 | |||
| 8aa4e5b8cb | |||
| 7c770e2ee7 | |||
| 6d15a22d94 | |||
| 3db4ac1050 | |||
| 16dfad5c77 | |||
| 5197d759d7 | |||
| c073286d53 | |||
| cbaba2f133 | |||
| 48afb6c017 | |||
| 37f2e0242d | |||
| 7c62147a00 | |||
| 7d11f9acd6 | |||
| 55a877a3e2 | |||
| 27c9d7fd07 | |||
| c907e10334 | |||
| 804c462dd3 | |||
| 9df9a2831e | |||
| 4aa83fd98e | |||
| 6747f0c340 | |||
| 8ef2c445c8 | |||
| e4a7ed6965 | |||
| c69dae5326 | |||
| fee4617802 | |||
| 339301947b | |||
| 5df3c2cd34 | |||
| 6832e23ff1 | |||
| d08ba7a0c4 | |||
| 780c0e055f | |||
| c55d0784e2 | |||
| 2080603464 | |||
| 13aea57207 | |||
| 815cbb4ffc | |||
| 5ee3ad2702 | |||
| d06af6aa63 | |||
| be2986075c | |||
| c397a64847 | |||
| 16edbdd274 | |||
| 9658f5363e | |||
| 19148d23bf | |||
| dc97f11171 | |||
| 87e42d0aa7 | |||
| 171bbb2f6a | |||
| 182f07b677 | |||
| 10783e1cb2 | |||
| 21a1e2d667 | |||
| cbbf4d7eb3 | |||
| d3428ff1f0 | |||
| a680a5a9d0 | |||
| fd9039e849 | |||
| b2abe63620 | |||
| 7e35b6dd65 | |||
| 00ecf00685 | |||
| 7ba3e9fe5e | |||
| 73f36b6218 | |||
| 915ba410a2 | |||
| 66e1a3a322 | |||
| 4a9de4d6cd | |||
| 165b9e7f01 | |||
| d8810d8d85 | |||
| 7c0c153691 | |||
| 77db9cef1e | |||
| bbd09b40ff | |||
| afb91988bd | |||
| 005260df87 | |||
| 813b11bb4f | |||
| 2e8203a64e | |||
| 1441f4c324 | |||
| 56fa0d0aad | |||
| 749da403fb | |||
| de6cb110e2 | |||
| 40d487282a | |||
| 32a30edcea | |||
| 655a66dd34 | |||
| 48fb024ae8 | |||
| e727c584ba | |||
| b57879afc5 | |||
| 070f1120e6 | |||
| 2c27f8d457 | |||
| 926f1f0f4a | |||
| fd8de10365 | |||
| 9066e318a6 | |||
| 56dca9e163 | |||
| 281ebe0e1e | |||
| 36bedd85cc | |||
| ef7badb776 | |||
| 2ca6278caf | |||
| 0257dafe22 | |||
| ef942a61c0 | |||
| 57b59e8fbd | |||
| ee4111f2b0 | |||
| 106f9c5adf | |||
| 96920367f8 | |||
| 21af1cb143 | |||
| bfedeb0277 | |||
| abccdef6cb | |||
| 12bdbcce5c | |||
| 51418f0d99 | |||
| 3601388abe | |||
| 4189137f55 | |||
| 043401876b | |||
| 543b93ced0 | |||
| dd3b381813 | |||
| 667efeab5e | |||
| 4103efd10b | |||
| 00be37a151 | |||
| c9f7453222 | |||
| 7f95652e80 | |||
| 15f6591d4c | |||
| a530da5760 | |||
| cc95ef2987 | |||
| 38c9421493 | |||
| 5abd9170ba | |||
| 375e526108 | |||
| eb9013f1ce | |||
| de9168f6a7 | |||
| 24a15d2c12 | |||
| a9ebaad37e | |||
| 968e96e2c7 | |||
| 02b5c7f7a8 | |||
| f1f77e5283 | |||
| 1e726852df | |||
| ba85fad318 | |||
| 6ae5eefdf5 | |||
| b6805bb845 | |||
| 3117145e6c | |||
| c144915a74 | |||
| ad1e207ee1 | |||
| f9cb07ee4c | |||
| f5ec5b0e47 | |||
| ba8b85972e | |||
| 766f678321 | |||
| c69c4afd25 | |||
| 516d8d7a0f | |||
| a0c93900e9 | |||
| a11f282a43 | |||
| cac6b4ec59 | |||
| eba96a55d2 | |||
| 37f4585110 | |||
| e6931434b0 | |||
| eec763bed0 | |||
| fa62363628 | |||
| 0bbb5a1c74 | |||
| 064e440d00 | |||
| 129b85a8cf | |||
| 586154d4e1 | |||
| b819231a01 | |||
| 3ec9eba736 | |||
| 75d4bc2b61 | |||
| a5ac56be7a | |||
| fe46d8c22d | |||
| 93cbd51d5b | |||
| 0b99873194 | |||
| 8113c7da22 | |||
| 85023dab51 | |||
| f8ab3dc4b9 | |||
| fedabe4889 | |||
| eba19d8e42 | |||
| e180a3bc44 | |||
| a1a465708f | |||
| 346d6c6a0a | |||
| c76813cbcb | |||
| e7f551dab6 | |||
| d8b2a37228 | |||
| af3950fafc | |||
| b20bf9c658 | |||
| 8c5e340ad0 | |||
| f3cd063816 | |||
| 5adfa3cb45 | |||
| 3398fe9361 | |||
| 2afc25d51f | |||
| 8c5d5c6679 | |||
| fca66c5b56 | |||
| d38ca1a7fc | |||
| b3bedd720f | |||
| b0858920d5 | |||
| e4e365b701 | |||
| c4315713b5 | |||
| 047ea2c66d | |||
| 5e6eb400b5 | |||
| db7880cab5 | |||
| 3909095a2c | |||
| 6685b88695 | |||
| 6076a7ecc7 | |||
| cc351a4817 | |||
| 9217a0fb79 | |||
| 5abaa2e7e3 | |||
| c3b8285584 | |||
| bf2667827b | |||
| 3b7283a13f | |||
| 5aaca69e91 | |||
| 8be52ab1ad | |||
| 447fe2c2e3 | |||
| 0ecbbdf669 | |||
| efce5888d7 | |||
| ab93083a9d | |||
| f757401d65 | |||
| 1e5d52098c | |||
| 152b703389 | |||
| b0cf05fa5f | |||
| e07f2ff160 | |||
| 2bb60e2cec | |||
| f0d070b857 | |||
| 732de1a5bc | |||
| 5d7701275b | |||
| 8f557e460d | |||
| 148f0121df | |||
| 8eb2e58891 | |||
| 3ac7216e63 | |||
| 80f58e1e07 | |||
| 5446706286 | |||
| 79ed7e4b73 | |||
| 94d95ac5d2 | |||
| a39b457888 | |||
| 94ff34d0df | |||
| ff4648b7f3 | |||
| acedb5fb55 | |||
| 4bd39e7bae | |||
| 5c2cf61455 | |||
| 10b47eae33 | |||
| c61b0e766a | |||
| 9ff1d088c5 | |||
| be803ced6f | |||
| 5949e9e32e | |||
| bb3276bbbd | |||
| b7a09989cb | |||
| 039d046649 | |||
| 58301651e4 | |||
| b848c2d1bf | |||
| 9e2bb23d35 | |||
| eb848fd70f | |||
| 176fffff0b | |||
| 14e13edeef | |||
| 4f70196444 | |||
| acc715de82 | |||
| 5bfb5f486f | |||
| 6fbd785a87 | |||
| 75b1c63884 | |||
| ad0808008a | |||
| fcf75b06bf | |||
| b8d47cdce3 | |||
| 8301f04b58 | |||
| 34942ac799 | |||
| 599f11683d | |||
| 55c699f841 | |||
| 3a7f922d90 | |||
| 352716319f | |||
| 5162f13372 | |||
| cbe8cc82c6 | |||
| c02010ea58 | |||
| 45e39b21ec | |||
| 7cbaf9c055 | |||
| 555f18d8df | |||
| f915c68a4b | |||
| da9ddcb382 | |||
| 55e6283075 | |||
| e56b9dce35 | |||
| 363be950f0 | |||
| 0f1a06ca32 | |||
| 24957ea881 | |||
| 0be065bbef | |||
| 10118f4350 | |||
| ac435455a0 | |||
| 929cd08718 | |||
| 299e7bfabe | |||
| 3465f053f5 | |||
| 18801eb4ff | |||
| 87e14ba12f | |||
| 438a519c65 | |||
| 572ea7c2be | |||
| fc8b5af5fe | |||
| 554dfc5b0e | |||
| 4855fdb50d | |||
| 4dbb536922 | |||
| 154f46d6b8 | |||
| bb8ac9696f | |||
| 41b5e5d8b9 | |||
| e07b2325c1 | |||
| 8c9c85c1c7 | |||
| 2d38e509f0 | |||
| 4396108113 | |||
| f82c15ca98 | |||
| 1a09b112b6 | |||
| c70c488648 | |||
| 91db277446 | |||
| 35ce20391c | |||
| 783ba03e92 | |||
| e344d3661c | |||
| c62418069d | |||
| 41611d2682 | |||
| cf8043a22e | |||
| 2521412747 | |||
| 199483be82 | |||
| 821b2b4415 | |||
| 866ae47dd4 | |||
| fbc8133a86 | |||
| 7044b6e017 | |||
| 3ff140101d | |||
| c4b6528bf0 | |||
| 7a85e33791 | |||
| bbfffb97a5 | |||
| 4306b4018d | |||
| 3722533431 | |||
| f773af17b2 | |||
| 56b4490554 | |||
| b45842d76a | |||
| ea279ace89 | |||
| 034061e744 | |||
| dd07ba4453 | |||
| 380aa4bc0f | |||
| aca721e9ee | |||
| 42e546904f | |||
| 4045824bf1 | |||
| 738cbfd1ae | |||
| 278c3cc2d8 | |||
| 14a7ac2618 | |||
| a7699361c1 | |||
| 82a0893036 | |||
| f9b59d7634 | |||
| f279536eb7 | |||
| 8f34c7cd2e | |||
| f922f669a8 | |||
| 2694d60faf | |||
| a326994459 | |||
| 4c8d1ef010 | |||
| 86a9a0aac6 | |||
| 5059ed2320 | |||
| df65c60fe4 | |||
| cff2c90041 | |||
| 88d1494e46 | |||
| 8b62b8f3c5 | |||
| cd38bc3a65 | |||
| 46d25645c2 | |||
| 3701737eff | |||
| b39e296684 | |||
| d8a7620c64 | |||
| 7d5900de18 | |||
| e8b3b936df | |||
| 5c246310f4 | |||
| bdad2cc941 | |||
| f23c33fee7 | |||
| 5b207cf5bd | |||
| f20c9e4ec9 | |||
| 1398ff8397 | |||
| ebc3512f50 | |||
| 564a8136a5 | |||
| 00047c95b8 | |||
| 9849ce79a7 | |||
| cea9858193 | |||
| ee8ea672ef | |||
| fc59910bd2 | |||
| 20ab7bc005 | |||
| 17de8e761b | |||
| ab1e1cc66e | |||
| 256143af42 | |||
| 5dc244a8c1 | |||
| 9f15ca6242 | |||
| 750b904abc | |||
| 96b5411d1d | |||
| a3404102ce | |||
| 374c4492d9 | |||
| 3cfe86512d | |||
| 47e3e415b9 | |||
| 3373533725 | |||
| 62c7c329d7 | |||
| da04899558 | |||
| e49f09b5ec | |||
| 53efcdc9df | |||
| d9e53d5a16 | |||
| 8699013eef | |||
| e3af8ad287 | |||
| f2970522a9 | |||
| e1a45c4831 | |||
| d258ff476f | |||
| a0ea2263a6 | |||
| d29e4cf4a2 | |||
| 6095defed4 | |||
| edd88d33d5 | |||
| fd67210906 | |||
| 393e9bd868 | |||
| 339863366c | |||
| d8db023931 | |||
| 71ccc82853 | |||
| 4d837d82d8 | |||
| 59792ad8b9 | |||
| 020796d411 | |||
| cc7461d959 | |||
| 0fc12576c0 | |||
| 02337ad9be | |||
| 90c0ea3b2d | |||
| 37c1502f5b | |||
| 193c3b305a | |||
| 4dfa649a81 | |||
| 3233646831 | |||
| b122de1f99 | |||
| c3d34736e8 | |||
| a77c95750c | |||
| e10b7fba82 | |||
| dd37770b86 | |||
| c85809e512 | |||
| edb86a7150 | |||
| d0e107d707 | |||
| 187ccc4f1c | |||
| 20cecec4ad | |||
| 8c28126479 | |||
| 85213ea8b0 | |||
| 1858aeee03 | |||
| 7ce4313ba4 | |||
| fd498b0efb | |||
| cdbcf098d2 | |||
| fddc47064d | |||
| 16ae89cd88 | |||
| f2d88b7b4f | |||
| 187c96f777 | |||
| f974ac4773 | |||
| 869985dc60 | |||
| 1e391e22ce | |||
| dae03cf80e | |||
| 1edcc106e3 | |||
| 34eb094143 | |||
| 683c0d4e8b | |||
| 9d8c544f83 | |||
| 5967d51769 | |||
| c37af920df | |||
| 5f08bf2e98 | |||
| a2dc3f44d3 | |||
| 9e9dfd6947 | |||
| 774bbbc6d5 | |||
| c7a1d4bd13 | |||
| a6d56700d9 | |||
| ed22dc806d | |||
| b129614679 | |||
| 154374a2d1 | |||
| 5ec5f980dc | |||
| b83c378667 | |||
| 981e62d53d | |||
| 03028a9a9b | |||
| c080821e31 | |||
| 2f546ec277 | |||
| 56d8ed38b0 | |||
| c0fde54d73 | |||
| 95a7cb1242 | |||
| 7d79a15ddf | |||
| 86f54e3244 | |||
| 06e81e1077 | |||
| 6c545e962a | |||
| 9c4f82db66 | |||
| 1dd067924a | |||
| 6565e20dc1 | |||
| 0d6f5560ff | |||
| 2f7c7c4ea7 | |||
| b7f94befba | |||
| dc3029822b | |||
| 3fb677d768 | |||
| e2a83549cb | |||
| 3911b09d1d | |||
| c24e9ead1c | |||
| 603d5b8f5e | |||
| 4fd70137b4 | |||
| 7398ffd9f4 | |||
| f1c765c534 | |||
| 40aa06940c | |||
| 117786376a | |||
| c5a635cdd7 | |||
| 165e3f22cd | |||
| 2561a50d05 | |||
| 6db5479b26 | |||
| e74ddff49a | |||
| 80132b0332 | |||
| 83a19adbb4 | |||
| 6b196a7c81 | |||
| 30082a1ba7 | |||
| 7741caa6ba | |||
| a3841d3cef | |||
| 89cdabd040 | |||
| cbb82812b2 | |||
| 1c463369c7 | |||
| 1a1e707db3 | |||
| 95a63e66a8 | |||
| b09f2db2a9 | |||
| 340d999b2b | |||
| 8c9874c4aa | |||
| e9b98c2ab0 | |||
| dd46dd2d87 | |||
| 719761de6c | |||
| 765cd6d123 | |||
| 26915e3979 | |||
| 34343bc61c | |||
| 7484c58175 | |||
| dd4a15fff1 | |||
| 6df91f54af | |||
| 8c0016c0a7 | |||
| a94bf79869 | |||
| 191539b28b | |||
| 31f410c3e5 | |||
| efdfe127a7 | |||
| 007ecc3c14 | |||
| db95b776b7 | |||
| 1560a7fb97 | |||
| 8fc5b83b57 | |||
| 33fd68b97f | |||
| 7e37d23c5e | |||
| cc034b57ff | |||
| 98792e9394 | |||
| 87b7918779 | |||
| aa6e2b57fb | |||
| b3eb937d55 | |||
| af24e42919 | |||
| dbdd891a99 | |||
| 1a066e88a9 | |||
| 0e364adb54 | |||
| 73fd1dd11b | |||
| efcdd65c67 | |||
| 8b15af7499 | |||
| 13daffdeed | |||
| fd82f5b496 | |||
| 83f03d617e | |||
| 4c5d5b2030 | |||
| 4e1ade4c28 | |||
| e5073d1a4f | |||
| 01e956bdf8 | |||
| 0cc049edb6 | |||
| ffa1a26b5e | |||
| 59ca9c26c9 | |||
| 56de2d1e39 | |||
| 72eb8b9575 | |||
| 65a67347bd | |||
| 25d54ff69a | |||
| 5c85c5098e | |||
| 7b8080438d | |||
| 2041371a04 | |||
| b172301e0f | |||
| 4b6cb1601b | |||
| d9f766cca6 | |||
| a4973fa3b7 |
+6
-12
@@ -4,35 +4,29 @@
|
|||||||
*.sh linguist-detectable=true
|
*.sh linguist-detectable=true
|
||||||
*.bash linguist-language=Shell
|
*.bash linguist-language=Shell
|
||||||
*.func linguist-language=Shell
|
*.func linguist-language=Shell
|
||||||
|
*.func linguist-detectable=true
|
||||||
*.install linguist-language=Shell
|
*.install linguist-language=Shell
|
||||||
|
|
||||||
# ---------------------------------------
|
# ---------------------------------------
|
||||||
# Treat Golang files as Go (for /api/)
|
# Exclude header art from stats
|
||||||
api/**/*.go linguist-language=Go
|
|
||||||
|
|
||||||
# ---------------------------------------
|
# ---------------------------------------
|
||||||
# Treat frontend as JavaScript/TypeScript (optional)
|
ct/headers/* linguist-documentation
|
||||||
frontend/**/*.ts linguist-language=TypeScript
|
|
||||||
frontend/**/*.js linguist-language=JavaScript
|
|
||||||
|
|
||||||
# ---------------------------------------
|
# ---------------------------------------
|
||||||
# Exclude documentation from stats
|
# Exclude documentation from stats
|
||||||
|
# ---------------------------------------
|
||||||
*.md linguist-documentation
|
*.md linguist-documentation
|
||||||
docs/** linguist-documentation
|
|
||||||
README.md linguist-documentation
|
README.md linguist-documentation
|
||||||
CONTRIBUTING.md linguist-documentation
|
CONTRIBUTING.md linguist-documentation
|
||||||
SECURITY.md linguist-documentation
|
SECURITY.md linguist-documentation
|
||||||
|
|
||||||
# ---------------------------------------
|
# ---------------------------------------
|
||||||
# Exclude generated/config files
|
# 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
|
.github/** linguist-generated
|
||||||
.vscode/** linguist-generated
|
.vscode/** linguist-generated
|
||||||
|
|
||||||
# ---------------------------------------
|
# ---------------------------------------
|
||||||
# Standard text handling
|
# Standard text handling
|
||||||
|
# ---------------------------------------
|
||||||
* text=auto eol=lf
|
* text=auto eol=lf
|
||||||
|
|||||||
Generated
-3
@@ -12,6 +12,3 @@
|
|||||||
|
|
||||||
# Set default reviewers
|
# Set default reviewers
|
||||||
* @community-scripts/Contributor
|
* @community-scripts/Contributor
|
||||||
|
|
||||||
# All changes in frontend
|
|
||||||
/frontend/ @community-scripts/Frontend-Dev
|
|
||||||
|
|||||||
Generated
+250
@@ -1,3 +1,253 @@
|
|||||||
|
## 2026-02-28
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- Update Reactive Resume install script with useful .env information for reverse proxy setup [@Mazianni](https://github.com/Mazianni) ([#12401](https://github.com/community-scripts/ProxmoxVE/pull/12401))
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- gramps-web: install addons (FilterRules) for relationship diagram [@MickLesk](https://github.com/MickLesk) ([#12387](https://github.com/community-scripts/ProxmoxVE/pull/12387))
|
||||||
|
- [Fix] Immich: Change `sed` command to fully replace line in postgresql.conf [@vhsdream](https://github.com/vhsdream) ([#12429](https://github.com/community-scripts/ProxmoxVE/pull/12429))
|
||||||
|
- [FIX] Immich: fix Openvino memory leak during OCR; improve HW-accelerated ML performance [@vhsdream](https://github.com/vhsdream) ([#12426](https://github.com/community-scripts/ProxmoxVE/pull/12426))
|
||||||
|
- Fix default tag for ioBroker LXC install [@josefglatz](https://github.com/josefglatz) ([#12423](https://github.com/community-scripts/ProxmoxVE/pull/12423))
|
||||||
|
- Ombi: Add database.json [@hraphael](https://github.com/hraphael) ([#12412](https://github.com/community-scripts/ProxmoxVE/pull/12412))
|
||||||
|
- Dawarich: add missing build deps and handle seed failure [@MickLesk](https://github.com/MickLesk) ([#12410](https://github.com/community-scripts/ProxmoxVE/pull/12410))
|
||||||
|
- pangolin: increase hdd to 10G [@MickLesk](https://github.com/MickLesk) ([#12409](https://github.com/community-scripts/ProxmoxVE/pull/12409))
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- BookLore: add additional JVM flags [@vhsdream](https://github.com/vhsdream) ([#12421](https://github.com/community-scripts/ProxmoxVE/pull/12421))
|
||||||
|
|
||||||
|
### 🗑️ Deleted Scripts
|
||||||
|
|
||||||
|
- Delete Palmr [@vhsdream](https://github.com/vhsdream) ([#12399](https://github.com/community-scripts/ProxmoxVE/pull/12399))
|
||||||
|
|
||||||
|
### 💾 Core
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- core: read from /dev/tty in all interactive prompts | fix empty or cropped logs due build process [@MickLesk](https://github.com/MickLesk) ([#12406](https://github.com/community-scripts/ProxmoxVE/pull/12406))
|
||||||
|
|
||||||
|
## 2026-02-27
|
||||||
|
|
||||||
|
### 🆕 New Scripts
|
||||||
|
|
||||||
|
- Strapi ([#12320](https://github.com/community-scripts/ProxmoxVE/pull/12320))
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- TrueNAS VM: filter out new nightlies with MASTER [@juronja](https://github.com/juronja) ([#12355](https://github.com/community-scripts/ProxmoxVE/pull/12355))
|
||||||
|
|
||||||
|
### 💾 Core
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- core: graceful fallback for apt-get update failures [@MickLesk](https://github.com/MickLesk) ([#12386](https://github.com/community-scripts/ProxmoxVE/pull/12386))
|
||||||
|
- core: Improve error outputs across core functions [@MickLesk](https://github.com/MickLesk) ([#12378](https://github.com/community-scripts/ProxmoxVE/pull/12378))
|
||||||
|
|
||||||
|
## 2026-02-26
|
||||||
|
|
||||||
|
### 🆕 New Scripts
|
||||||
|
|
||||||
|
- Kima-Hub ([#12319](https://github.com/community-scripts/ProxmoxVE/pull/12319))
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- tools.func: update glx alternatives / nvidia alternative if nvidia glx are missing [@MickLesk](https://github.com/MickLesk) ([#12372](https://github.com/community-scripts/ProxmoxVE/pull/12372))
|
||||||
|
- hotfix: overseer version [@CrazyWolf13](https://github.com/CrazyWolf13) ([#12366](https://github.com/community-scripts/ProxmoxVE/pull/12366))
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- Add ffmpeg for booklore (ffprobe) [@MickLesk](https://github.com/MickLesk) ([#12371](https://github.com/community-scripts/ProxmoxVE/pull/12371))
|
||||||
|
- [QOL] Immich: add warning regarding library compilation time [@vhsdream](https://github.com/vhsdream) ([#12345](https://github.com/community-scripts/ProxmoxVE/pull/12345))
|
||||||
|
|
||||||
|
### 🧰 Tools
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- Improves adguardhome-sync addon when running on alpine LXCs [@Darkangeel-hd](https://github.com/Darkangeel-hd) ([#12362](https://github.com/community-scripts/ProxmoxVE/pull/12362))
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- Add Alpine support and improve Tailscale install [@MickLesk](https://github.com/MickLesk) ([#12370](https://github.com/community-scripts/ProxmoxVE/pull/12370))
|
||||||
|
|
||||||
|
### 📚 Documentation
|
||||||
|
|
||||||
|
- fix wrong link on contributions README.md [@Darkangeel-hd](https://github.com/Darkangeel-hd) ([#12363](https://github.com/community-scripts/ProxmoxVE/pull/12363))
|
||||||
|
|
||||||
|
### 📂 Github
|
||||||
|
|
||||||
|
- github: add workflow to autom. close unauthorized new-script PRs [@MickLesk](https://github.com/MickLesk) ([#12356](https://github.com/community-scripts/ProxmoxVE/pull/12356))
|
||||||
|
|
||||||
|
## 2026-02-25
|
||||||
|
|
||||||
|
### 🆕 New Scripts
|
||||||
|
|
||||||
|
- Zerobyte ([#12321](https://github.com/community-scripts/ProxmoxVE/pull/12321))
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- fix: overseer migration [@CrazyWolf13](https://github.com/CrazyWolf13) ([#12340](https://github.com/community-scripts/ProxmoxVE/pull/12340))
|
||||||
|
- add: vikunja: daemon reload [@CrazyWolf13](https://github.com/CrazyWolf13) ([#12323](https://github.com/community-scripts/ProxmoxVE/pull/12323))
|
||||||
|
- opnsense-VM: Use ip link to verify bridge existence [@MickLesk](https://github.com/MickLesk) ([#12329](https://github.com/community-scripts/ProxmoxVE/pull/12329))
|
||||||
|
- wger: Use $http_host for proxy Host header [@MickLesk](https://github.com/MickLesk) ([#12327](https://github.com/community-scripts/ProxmoxVE/pull/12327))
|
||||||
|
- Passbolt: Update Nginx config `client_max_body_size` [@tremor021](https://github.com/tremor021) ([#12313](https://github.com/community-scripts/ProxmoxVE/pull/12313))
|
||||||
|
- Zammad: configure Elasticsearch before zammad start [@MickLesk](https://github.com/MickLesk) ([#12308](https://github.com/community-scripts/ProxmoxVE/pull/12308))
|
||||||
|
|
||||||
|
- #### 🔧 Refactor
|
||||||
|
|
||||||
|
- OpenProject: Various fixes [@tremor021](https://github.com/tremor021) ([#12246](https://github.com/community-scripts/ProxmoxVE/pull/12246))
|
||||||
|
|
||||||
|
### 💾 Core
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- Fix detection of ssh keys [@1-tempest](https://github.com/1-tempest) ([#12230](https://github.com/community-scripts/ProxmoxVE/pull/12230))
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- tools.func: Improve GitHub/Codeberg API error handling and error output [@MickLesk](https://github.com/MickLesk) ([#12330](https://github.com/community-scripts/ProxmoxVE/pull/12330))
|
||||||
|
|
||||||
|
- #### 🔧 Refactor
|
||||||
|
|
||||||
|
- core: remove duplicate traps, consolidate error handling and harden signal traps [@MickLesk](https://github.com/MickLesk) ([#12316](https://github.com/community-scripts/ProxmoxVE/pull/12316))
|
||||||
|
|
||||||
|
### 📂 Github
|
||||||
|
|
||||||
|
- github: improvements for node drift wf [@MickLesk](https://github.com/MickLesk) ([#12309](https://github.com/community-scripts/ProxmoxVE/pull/12309))
|
||||||
|
|
||||||
|
## 2026-02-24
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- several scripts: add additional github link in source [@MickLesk](https://github.com/MickLesk) ([#12282](https://github.com/community-scripts/ProxmoxVE/pull/12282))
|
||||||
|
- adds further documentation during the installation script. [@d12rio](https://github.com/d12rio) ([#12248](https://github.com/community-scripts/ProxmoxVE/pull/12248))
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- [Fix] PatchMon: remove VITE_API_URL from frontend env [@vhsdream](https://github.com/vhsdream) ([#12294](https://github.com/community-scripts/ProxmoxVE/pull/12294))
|
||||||
|
- fix(searxng): remove orphaned fi causing syntax error [@mark-jeffrey](https://github.com/mark-jeffrey) ([#12283](https://github.com/community-scripts/ProxmoxVE/pull/12283))
|
||||||
|
- Refactor n8n [@MickLesk](https://github.com/MickLesk) ([#12264](https://github.com/community-scripts/ProxmoxVE/pull/12264))
|
||||||
|
- Firefly: PHP bump [@tremor021](https://github.com/tremor021) ([#12247](https://github.com/community-scripts/ProxmoxVE/pull/12247))
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- Databasus: add mariadb path for mysql/mariadb backups | add mongodb database tools [@MickLesk](https://github.com/MickLesk) ([#12259](https://github.com/community-scripts/ProxmoxVE/pull/12259))
|
||||||
|
- make searxng updateable [@shtefko](https://github.com/shtefko) ([#12207](https://github.com/community-scripts/ProxmoxVE/pull/12207))
|
||||||
|
|
||||||
|
- #### 💥 Breaking Changes
|
||||||
|
|
||||||
|
- fix: wealthfolio for v3 [@CrazyWolf13](https://github.com/CrazyWolf13) ([#11765](https://github.com/community-scripts/ProxmoxVE/pull/11765))
|
||||||
|
|
||||||
|
- #### 🔧 Refactor
|
||||||
|
|
||||||
|
- bump various scripts from Node 22 to 24 [@MickLesk](https://github.com/MickLesk) ([#12265](https://github.com/community-scripts/ProxmoxVE/pull/12265))
|
||||||
|
|
||||||
|
### 💾 Core
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- core: fix broken "command not found" after err_trap [@MickLesk](https://github.com/MickLesk) ([#12280](https://github.com/community-scripts/ProxmoxVE/pull/12280))
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- tools.func: add get_latest_gh_tag helper function [@MickLesk](https://github.com/MickLesk) ([#12261](https://github.com/community-scripts/ProxmoxVE/pull/12261))
|
||||||
|
|
||||||
|
### 🧰 Tools
|
||||||
|
|
||||||
|
- Arcane ([#12263](https://github.com/community-scripts/ProxmoxVE/pull/12263))
|
||||||
|
|
||||||
|
### 📂 Github
|
||||||
|
|
||||||
|
- github: add weekly Node.js version drift check workflow [@MickLesk](https://github.com/MickLesk) ([#12267](https://github.com/community-scripts/ProxmoxVE/pull/12267))
|
||||||
|
- add: workflow to close stale PRs [@CrazyWolf13](https://github.com/CrazyWolf13) ([#12243](https://github.com/community-scripts/ProxmoxVE/pull/12243))
|
||||||
|
|
||||||
|
## 2026-02-23
|
||||||
|
|
||||||
|
### 🆕 New Scripts
|
||||||
|
|
||||||
|
- SeaweedFS ([#12220](https://github.com/community-scripts/ProxmoxVE/pull/12220))
|
||||||
|
- Sonobarr ([#12221](https://github.com/community-scripts/ProxmoxVE/pull/12221))
|
||||||
|
- SparkyFitness ([#12185](https://github.com/community-scripts/ProxmoxVE/pull/12185))
|
||||||
|
- Frigate v16.4 [@MickLesk](https://github.com/MickLesk) ([#11887](https://github.com/community-scripts/ProxmoxVE/pull/11887))
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- memos: unpin version due new release artifacts [@MickLesk](https://github.com/MickLesk) ([#12224](https://github.com/community-scripts/ProxmoxVE/pull/12224))
|
||||||
|
- core: Enhance signal handling, reported "status" and logs [@MickLesk](https://github.com/MickLesk) ([#12216](https://github.com/community-scripts/ProxmoxVE/pull/12216))
|
||||||
|
|
||||||
|
- #### 🔧 Refactor
|
||||||
|
|
||||||
|
- booklore v2: embed frontend, bump Java to 25, remove nginx [@MickLesk](https://github.com/MickLesk) ([#12223](https://github.com/community-scripts/ProxmoxVE/pull/12223))
|
||||||
|
|
||||||
|
### 🗑️ Deleted Scripts
|
||||||
|
|
||||||
|
- Remove: Huntarr (deprecated & Security) [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#12226](https://github.com/community-scripts/ProxmoxVE/pull/12226))
|
||||||
|
|
||||||
|
### 💾 Core
|
||||||
|
|
||||||
|
- #### 🔧 Refactor
|
||||||
|
|
||||||
|
- core: Improve error handling and logging for LXC builds [@MickLesk](https://github.com/MickLesk) ([#12208](https://github.com/community-scripts/ProxmoxVE/pull/12208))
|
||||||
|
|
||||||
|
### 🌐 Website
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- calibre-web: update default credentials [@LaevaertK](https://github.com/LaevaertK) ([#12201](https://github.com/community-scripts/ProxmoxVE/pull/12201))
|
||||||
|
|
||||||
|
- #### 📝 Script Information
|
||||||
|
|
||||||
|
- chore: update Frigate documentation and website URLs [@JohnICB](https://github.com/JohnICB) ([#12218](https://github.com/community-scripts/ProxmoxVE/pull/12218))
|
||||||
|
|
||||||
|
## 2026-02-22
|
||||||
|
|
||||||
|
### 🆕 New Scripts
|
||||||
|
|
||||||
|
- Gramps-Web ([#12157](https://github.com/community-scripts/ProxmoxVE/pull/12157))
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- fix: Apache Guacamole - bump to Temurin JDK 17 to resolve Debian 13 (Trixie) install failure [@Copilot](https://github.com/Copilot) ([#12161](https://github.com/community-scripts/ProxmoxVE/pull/12161))
|
||||||
|
- Docker-VM: add error handling for virt-customize finalization [@MickLesk](https://github.com/MickLesk) ([#12127](https://github.com/community-scripts/ProxmoxVE/pull/12127))
|
||||||
|
- [Fix] Sure: add Sidekiq service [@vhsdream](https://github.com/vhsdream) ([#12186](https://github.com/community-scripts/ProxmoxVE/pull/12186))
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- Refactor & Bump to v2: Plex [@MickLesk](https://github.com/MickLesk) ([#12179](https://github.com/community-scripts/ProxmoxVE/pull/12179))
|
||||||
|
|
||||||
|
- #### 🔧 Refactor
|
||||||
|
|
||||||
|
- karakeep: bump to node 24 [@CrazyWolf13](https://github.com/CrazyWolf13) ([#12183](https://github.com/community-scripts/ProxmoxVE/pull/12183))
|
||||||
|
|
||||||
|
### 💾 Core
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- tools.func: add GitHub API rate-limit detection and GITHUB_TOKEN support [@MickLesk](https://github.com/MickLesk) ([#12176](https://github.com/community-scripts/ProxmoxVE/pull/12176))
|
||||||
|
|
||||||
|
### 🧰 Tools
|
||||||
|
|
||||||
|
- CR*NMASTER ([#12065](https://github.com/community-scripts/ProxmoxVE/pull/12065))
|
||||||
|
|
||||||
|
- #### 🔧 Refactor
|
||||||
|
|
||||||
|
- Update package management commands in clean-lxcs.sh [@heinemannj](https://github.com/heinemannj) ([#12166](https://github.com/community-scripts/ProxmoxVE/pull/12166))
|
||||||
|
|
||||||
|
### ❔ Uncategorized
|
||||||
|
|
||||||
|
- calibre-web: Update logo URL [@MickLesk](https://github.com/MickLesk) ([#12178](https://github.com/community-scripts/ProxmoxVE/pull/12178))
|
||||||
|
|
||||||
## 2026-02-21
|
## 2026-02-21
|
||||||
|
|
||||||
### 🚀 Updated Scripts
|
### 🚀 Updated Scripts
|
||||||
|
|||||||
Generated
+711
@@ -0,0 +1,711 @@
|
|||||||
|
## 2026-03-31
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- Graylog: set vm.max_map_count on host for OpenSearch [@MickLesk](https://github.com/MickLesk) ([#13441](https://github.com/community-scripts/ProxmoxVE/pull/13441))
|
||||||
|
- Koillection: ensure newline before appending to .env.local [@MickLesk](https://github.com/MickLesk) ([#13440](https://github.com/community-scripts/ProxmoxVE/pull/13440))
|
||||||
|
|
||||||
|
### 💾 Core
|
||||||
|
|
||||||
|
- #### 🔧 Refactor
|
||||||
|
|
||||||
|
- core: skip empty gateway value in network config [@MickLesk](https://github.com/MickLesk) ([#13442](https://github.com/community-scripts/ProxmoxVE/pull/13442))
|
||||||
|
|
||||||
|
## 2026-03-30
|
||||||
|
|
||||||
|
### 🆕 New Scripts
|
||||||
|
|
||||||
|
- Bambuddy ([#13411](https://github.com/community-scripts/ProxmoxVE/pull/13411))
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- #### 💥 Breaking Changes
|
||||||
|
|
||||||
|
- Rename: BirdNET > BirdNET-Go [@MickLesk](https://github.com/MickLesk) ([#13410](https://github.com/community-scripts/ProxmoxVE/pull/13410))
|
||||||
|
|
||||||
|
## 2026-03-29
|
||||||
|
|
||||||
|
### 🆕 New Scripts
|
||||||
|
|
||||||
|
- YOURLS ([#13379](https://github.com/community-scripts/ProxmoxVE/pull/13379))
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- fix(victoriametrics): use jq to filter releases [@Joery-M](https://github.com/Joery-M) ([#13393](https://github.com/community-scripts/ProxmoxVE/pull/13393))
|
||||||
|
- Ollama: add error handling for Intel GPG key imports [@MickLesk](https://github.com/MickLesk) ([#13397](https://github.com/community-scripts/ProxmoxVE/pull/13397))
|
||||||
|
- Immich: ignore Redis connection error on maintenance mode disable [@MickLesk](https://github.com/MickLesk) ([#13398](https://github.com/community-scripts/ProxmoxVE/pull/13398))
|
||||||
|
- NPM: unmask openresty after migration from package [@MickLesk](https://github.com/MickLesk) ([#13399](https://github.com/community-scripts/ProxmoxVE/pull/13399))
|
||||||
|
|
||||||
|
## 2026-03-28
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- Fix: Update gokapi binary name for v2.2.4+ and add migration step [@krazos](https://github.com/krazos) ([#13377](https://github.com/community-scripts/ProxmoxVE/pull/13377))
|
||||||
|
- Fix: update gokapi asset matching for v2.2.4+ naming convention [@krazos](https://github.com/krazos) ([#13369](https://github.com/community-scripts/ProxmoxVE/pull/13369))
|
||||||
|
- Tandoor Recipes: Add missing env variable [@tremor021](https://github.com/tremor021) ([#13365](https://github.com/community-scripts/ProxmoxVE/pull/13365))
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- FileFlows: add option to install Node [@tremor021](https://github.com/tremor021) ([#13368](https://github.com/community-scripts/ProxmoxVE/pull/13368))
|
||||||
|
|
||||||
|
## 2026-03-27
|
||||||
|
|
||||||
|
### 🆕 New Scripts
|
||||||
|
|
||||||
|
- Matter-Server ([#13355](https://github.com/community-scripts/ProxmoxVE/pull/13355))
|
||||||
|
- GeoPulse ([#13320](https://github.com/community-scripts/ProxmoxVE/pull/13320))
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- RevealJS: Switch from gulp to vite [@tremor021](https://github.com/tremor021) ([#13336](https://github.com/community-scripts/ProxmoxVE/pull/13336))
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- Dispatcharr add custom Postgres port support for upgrade [@MickLesk](https://github.com/MickLesk) ([#13347](https://github.com/community-scripts/ProxmoxVE/pull/13347))
|
||||||
|
- Immich: bump to v2.6.3 [@MickLesk](https://github.com/MickLesk) ([#13324](https://github.com/community-scripts/ProxmoxVE/pull/13324))
|
||||||
|
|
||||||
|
### 🧰 Tools
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- Refactor/Feature-Bump/Security: Update-Cron-LXCs (Now Local Mode!) [@MickLesk](https://github.com/MickLesk) ([#13339](https://github.com/community-scripts/ProxmoxVE/pull/13339))
|
||||||
|
|
||||||
|
## 2026-03-26
|
||||||
|
|
||||||
|
### 🆕 New Scripts
|
||||||
|
|
||||||
|
- BirdNET ([#13313](https://github.com/community-scripts/ProxmoxVE/pull/13313))
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- Immich: Bump to 2.6.2 | use start.sh in service, ensure DB_HOSTNAME in .env | Fix Rights Issue with ZFS Shares [@MickLesk](https://github.com/MickLesk) ([#13199](https://github.com/community-scripts/ProxmoxVE/pull/13199))
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- SparkyFitness: add garmin microservice as addon [@tomfrenzel](https://github.com/tomfrenzel) ([#12642](https://github.com/community-scripts/ProxmoxVE/pull/12642))
|
||||||
|
- Frigate: bump to v0.17.1 & change build order [@MickLesk](https://github.com/MickLesk) ([#13304](https://github.com/community-scripts/ProxmoxVE/pull/13304))
|
||||||
|
|
||||||
|
### 💾 Core
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- tools.func: pin npm to 11.11.0 to work around Node.js 22.22.2 regression [@MickLesk](https://github.com/MickLesk) ([#13296](https://github.com/community-scripts/ProxmoxVE/pull/13296))
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- core: APT/APK Mirror Fallback for CDN Failures [@MickLesk](https://github.com/MickLesk) ([#13316](https://github.com/community-scripts/ProxmoxVE/pull/13316))
|
||||||
|
- core/tools: replace generic return 1 exit_codes with more specific exit_codes [@MickLesk](https://github.com/MickLesk) ([#13311](https://github.com/community-scripts/ProxmoxVE/pull/13311))
|
||||||
|
|
||||||
|
- #### 🔧 Refactor
|
||||||
|
|
||||||
|
- core: use /usr/bin/install to prevent function shadowing [@MickLesk](https://github.com/MickLesk) ([#13299](https://github.com/community-scripts/ProxmoxVE/pull/13299))
|
||||||
|
|
||||||
|
### 🧰 Tools
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- SparkyFitness-Garmin: fix app name [@tomfrenzel](https://github.com/tomfrenzel) ([#13325](https://github.com/community-scripts/ProxmoxVE/pull/13325))
|
||||||
|
|
||||||
|
## 2026-03-25
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- Komodo v2: migrate env vars to v2 and update source [@MickLesk](https://github.com/MickLesk) ([#13262](https://github.com/community-scripts/ProxmoxVE/pull/13262))
|
||||||
|
|
||||||
|
### 💾 Core
|
||||||
|
|
||||||
|
- #### 🔧 Refactor
|
||||||
|
|
||||||
|
- core: make shell command substitutions safe with || true [@MickLesk](https://github.com/MickLesk) ([#13279](https://github.com/community-scripts/ProxmoxVE/pull/13279))
|
||||||
|
|
||||||
|
## 2026-03-24
|
||||||
|
|
||||||
|
### 🆕 New Scripts
|
||||||
|
|
||||||
|
- Homebrew (Addon) ([#13249](https://github.com/community-scripts/ProxmoxVE/pull/13249))
|
||||||
|
- NextExplorer ([#13252](https://github.com/community-scripts/ProxmoxVE/pull/13252))
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- Turnkey: modernize turnkey.sh with shared libraries [@MickLesk](https://github.com/MickLesk) ([#13242](https://github.com/community-scripts/ProxmoxVE/pull/13242))
|
||||||
|
|
||||||
|
- #### 🔧 Refactor
|
||||||
|
|
||||||
|
- chore: replace helper-scripts.com with community-scripts.com [@MickLesk](https://github.com/MickLesk) ([#13244](https://github.com/community-scripts/ProxmoxVE/pull/13244))
|
||||||
|
|
||||||
|
### 🗑️ Deleted Scripts
|
||||||
|
|
||||||
|
- Remove: Booklore [@MickLesk](https://github.com/MickLesk) ([#13265](https://github.com/community-scripts/ProxmoxVE/pull/13265))
|
||||||
|
|
||||||
|
## 2026-03-23
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- #### 🔧 Refactor
|
||||||
|
|
||||||
|
- core: harden shell scripts against injection and insecure permissions [@MickLesk](https://github.com/MickLesk) ([#13239](https://github.com/community-scripts/ProxmoxVE/pull/13239))
|
||||||
|
|
||||||
|
## 2026-03-22
|
||||||
|
|
||||||
|
### 🆕 New Scripts
|
||||||
|
|
||||||
|
- versitygw ([#13180](https://github.com/community-scripts/ProxmoxVE/pull/13180))
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- Adventurelog: pin DRF <3.15 to fix coreapi module removal [@MickLesk](https://github.com/MickLesk) ([#13194](https://github.com/community-scripts/ProxmoxVE/pull/13194))
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- ConvertX: add libreoffice-writer for ODT/document conversions [@MickLesk](https://github.com/MickLesk) ([#13196](https://github.com/community-scripts/ProxmoxVE/pull/13196))
|
||||||
|
|
||||||
|
- #### 🔧 Refactor
|
||||||
|
|
||||||
|
- iSponsorblockTV: add AVX CPU check before installation [@MickLesk](https://github.com/MickLesk) ([#13197](https://github.com/community-scripts/ProxmoxVE/pull/13197))
|
||||||
|
|
||||||
|
### 💾 Core
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- core: guard against empty IPv6 address in static mode [@MickLesk](https://github.com/MickLesk) ([#13195](https://github.com/community-scripts/ProxmoxVE/pull/13195))
|
||||||
|
|
||||||
|
## 2026-03-21
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- Anytype-server: wait for MongoDB readiness before rs.initiate() [@MickLesk](https://github.com/MickLesk) ([#13165](https://github.com/community-scripts/ProxmoxVE/pull/13165))
|
||||||
|
- Frigate: use correct CPU model fallback path [@MickLesk](https://github.com/MickLesk) ([#13164](https://github.com/community-scripts/ProxmoxVE/pull/13164))
|
||||||
|
- iSponsorBlockTV: Fix release fetching [@tremor021](https://github.com/tremor021) ([#13157](https://github.com/community-scripts/ProxmoxVE/pull/13157))
|
||||||
|
- Isponsorblocktv: use quoted heredoc to prevent unbound variable error during CLI wrapper creation [@Copilot](https://github.com/Copilot) ([#13146](https://github.com/community-scripts/ProxmoxVE/pull/13146))
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- Headscale: Enable TUN [@tremor021](https://github.com/tremor021) ([#13158](https://github.com/community-scripts/ProxmoxVE/pull/13158))
|
||||||
|
|
||||||
|
### 💾 Core
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- core: add missing -searchdomain/-nameserver prefix in base_settings [@MickLesk](https://github.com/MickLesk) ([#13166](https://github.com/community-scripts/ProxmoxVE/pull/13166))
|
||||||
|
|
||||||
|
## 2026-03-20
|
||||||
|
|
||||||
|
### 🆕 New Scripts
|
||||||
|
|
||||||
|
- iSponsorBlockTV ([#13123](https://github.com/community-scripts/ProxmoxVE/pull/13123))
|
||||||
|
- Alpine-Wakapi ([#13119](https://github.com/community-scripts/ProxmoxVE/pull/13119))
|
||||||
|
- teleport ([#13086](https://github.com/community-scripts/ProxmoxVE/pull/13086))
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- Reactive-Resume: add git dependency for v5.0.13+ [@MickLesk](https://github.com/MickLesk) ([#13133](https://github.com/community-scripts/ProxmoxVE/pull/13133))
|
||||||
|
- Scanopy: increase default CPU, RAM, and HDD to prevent OOM during Rust build [@Copilot](https://github.com/Copilot) ([#13130](https://github.com/community-scripts/ProxmoxVE/pull/13130))
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- Immich: v2.6.1 [@vhsdream](https://github.com/vhsdream) ([#13111](https://github.com/community-scripts/ProxmoxVE/pull/13111))
|
||||||
|
- VM's: add input validation and hostname sanitization to all VM scripts [@MickLesk](https://github.com/MickLesk) ([#12973](https://github.com/community-scripts/ProxmoxVE/pull/12973))
|
||||||
|
|
||||||
|
### 🧰 Tools
|
||||||
|
|
||||||
|
- #### 🔧 Refactor
|
||||||
|
|
||||||
|
- Harden code-server addon install script [@MickLesk](https://github.com/MickLesk) ([#13116](https://github.com/community-scripts/ProxmoxVE/pull/13116))
|
||||||
|
|
||||||
|
## 2026-03-19
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- Owncast: increase default disk size from 2GB to 10GB [@Copilot](https://github.com/Copilot) ([#13079](https://github.com/community-scripts/ProxmoxVE/pull/13079))
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- fix: remove extra backslash to match single quoted here-doc [@Zelnes](https://github.com/Zelnes) ([#13108](https://github.com/community-scripts/ProxmoxVE/pull/13108))
|
||||||
|
- Reactive-Resume: Upgrade Node to 24 and enable Corepack [@MickLesk](https://github.com/MickLesk) ([#13093](https://github.com/community-scripts/ProxmoxVE/pull/13093))
|
||||||
|
- Increase Tracearr RAM; derive APP_VERSION [@MickLesk](https://github.com/MickLesk) ([#13087](https://github.com/community-scripts/ProxmoxVE/pull/13087))
|
||||||
|
- ProjectSend: Update application access URL [@tremor021](https://github.com/tremor021) ([#13078](https://github.com/community-scripts/ProxmoxVE/pull/13078))
|
||||||
|
- Dispatcharr: use npm install --no-audit --progress=false [@MickLesk](https://github.com/MickLesk) ([#13074](https://github.com/community-scripts/ProxmoxVE/pull/13074))
|
||||||
|
- core: reorder hwaccel setup and adjust GPU group usermod [@MickLesk](https://github.com/MickLesk) ([#13072](https://github.com/community-scripts/ProxmoxVE/pull/13072))
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- tools.func: display pin reason in release-check messages [@MickLesk](https://github.com/MickLesk) ([#13095](https://github.com/community-scripts/ProxmoxVE/pull/13095))
|
||||||
|
- NocoDB: Unpin Version to latest [@MickLesk](https://github.com/MickLesk) ([#13094](https://github.com/community-scripts/ProxmoxVE/pull/13094))
|
||||||
|
|
||||||
|
### 💾 Core
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- tools.func: use dpkg-query for reliable JDK version detection [@MickLesk](https://github.com/MickLesk) ([#13101](https://github.com/community-scripts/ProxmoxVE/pull/13101))
|
||||||
|
|
||||||
|
### 📚 Documentation
|
||||||
|
|
||||||
|
- Update link from helper-scripts.com to community-scripts.org [@adnanvaldes](https://github.com/adnanvaldes) ([#13098](https://github.com/community-scripts/ProxmoxVE/pull/13098))
|
||||||
|
- github: add PocketBase bot workflow [@MickLesk](https://github.com/MickLesk) ([#13075](https://github.com/community-scripts/ProxmoxVE/pull/13075))
|
||||||
|
|
||||||
|
## 2026-03-18
|
||||||
|
|
||||||
|
### 🆕 New Scripts
|
||||||
|
|
||||||
|
- Alpine-Ntfy [@MickLesk](https://github.com/MickLesk) ([#13048](https://github.com/community-scripts/ProxmoxVE/pull/13048))
|
||||||
|
- Split-Pro ([#12975](https://github.com/community-scripts/ProxmoxVE/pull/12975))
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- Tdarr: use curl_with_retry and correct exit code [@MickLesk](https://github.com/MickLesk) ([#13060](https://github.com/community-scripts/ProxmoxVE/pull/13060))
|
||||||
|
- reitti: fix: v4 [@CrazyWolf13](https://github.com/CrazyWolf13) ([#13039](https://github.com/community-scripts/ProxmoxVE/pull/13039))
|
||||||
|
- Paperless-NGX: increase default RAM to 3GB [@MickLesk](https://github.com/MickLesk) ([#13018](https://github.com/community-scripts/ProxmoxVE/pull/13018))
|
||||||
|
- Plex: restart service after update to apply new version [@MickLesk](https://github.com/MickLesk) ([#13017](https://github.com/community-scripts/ProxmoxVE/pull/13017))
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- tools: centralize GPU group setup via setup_hwaccel [@MickLesk](https://github.com/MickLesk) ([#13044](https://github.com/community-scripts/ProxmoxVE/pull/13044))
|
||||||
|
- Termix: add guacd build and systemd integration [@MickLesk](https://github.com/MickLesk) ([#12999](https://github.com/community-scripts/ProxmoxVE/pull/12999))
|
||||||
|
|
||||||
|
- #### 🔧 Refactor
|
||||||
|
|
||||||
|
- Podman: replace deprecated commands with Quadlets [@MickLesk](https://github.com/MickLesk) ([#13052](https://github.com/community-scripts/ProxmoxVE/pull/13052))
|
||||||
|
- Refactor: Jellyfin repo, ffmpeg package and symlinks [@MickLesk](https://github.com/MickLesk) ([#13045](https://github.com/community-scripts/ProxmoxVE/pull/13045))
|
||||||
|
- pve-scripts-local: Increase default disk size from 4GB to 10GB [@MickLesk](https://github.com/MickLesk) ([#13009](https://github.com/community-scripts/ProxmoxVE/pull/13009))
|
||||||
|
|
||||||
|
### 💾 Core
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- tools.func Implement pg_cron setup for setup_postgresql [@MickLesk](https://github.com/MickLesk) ([#13053](https://github.com/community-scripts/ProxmoxVE/pull/13053))
|
||||||
|
- tools.func: Implement check_for_gh_tag function [@MickLesk](https://github.com/MickLesk) ([#12998](https://github.com/community-scripts/ProxmoxVE/pull/12998))
|
||||||
|
- tools.func: Implement fetch_and_deploy_gh_tag function [@MickLesk](https://github.com/MickLesk) ([#13000](https://github.com/community-scripts/ProxmoxVE/pull/13000))
|
||||||
|
|
||||||
|
## 2026-03-17
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- Gluetun: add OpenVPN process user and cleanup stale config [@MickLesk](https://github.com/MickLesk) ([#13016](https://github.com/community-scripts/ProxmoxVE/pull/13016))
|
||||||
|
- Frigate: check OpenVino model files exist before configuring detector and use curl_with_retry instead of default wget [@MickLesk](https://github.com/MickLesk) ([#13019](https://github.com/community-scripts/ProxmoxVE/pull/13019))
|
||||||
|
|
||||||
|
### 💾 Core
|
||||||
|
|
||||||
|
- #### 🔧 Refactor
|
||||||
|
|
||||||
|
- tools.func: Update `create_self_signed_cert()` [@tremor021](https://github.com/tremor021) ([#13008](https://github.com/community-scripts/ProxmoxVE/pull/13008))
|
||||||
|
|
||||||
|
## 2026-03-16
|
||||||
|
|
||||||
|
### 🆕 New Scripts
|
||||||
|
|
||||||
|
- Gluetun ([#12976](https://github.com/community-scripts/ProxmoxVE/pull/12976))
|
||||||
|
- Anytype-Server ([#12974](https://github.com/community-scripts/ProxmoxVE/pull/12974))
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- Immich: use gcc-13 for compilation & add uv python pre-install with retry logic [@MickLesk](https://github.com/MickLesk) ([#12935](https://github.com/community-scripts/ProxmoxVE/pull/12935))
|
||||||
|
- Tautulli: add setuptools<81 constraint to update script [@MickLesk](https://github.com/MickLesk) ([#12959](https://github.com/community-scripts/ProxmoxVE/pull/12959))
|
||||||
|
- Seerr: add missing build deps [@MickLesk](https://github.com/MickLesk) ([#12960](https://github.com/community-scripts/ProxmoxVE/pull/12960))
|
||||||
|
- fix: yubal update [@CrazyWolf13](https://github.com/CrazyWolf13) ([#12961](https://github.com/community-scripts/ProxmoxVE/pull/12961))
|
||||||
|
|
||||||
|
### 💾 Core
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- hwaccel: remove ROCm install from AMD APU setup [@MickLesk](https://github.com/MickLesk) ([#12958](https://github.com/community-scripts/ProxmoxVE/pull/12958))
|
||||||
|
|
||||||
|
## 2026-03-15
|
||||||
|
|
||||||
|
### 🆕 New Scripts
|
||||||
|
|
||||||
|
- Yamtrack ([#12936](https://github.com/community-scripts/ProxmoxVE/pull/12936))
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- Wishlist: use --frozen-lockfile for pnpm install [@MickLesk](https://github.com/MickLesk) ([#12892](https://github.com/community-scripts/ProxmoxVE/pull/12892))
|
||||||
|
- SparkyFitness: use --legacy-peer-deps for npm install [@MickLesk](https://github.com/MickLesk) ([#12888](https://github.com/community-scripts/ProxmoxVE/pull/12888))
|
||||||
|
- Frigate: add fallback for OpenVino labelmap file [@MickLesk](https://github.com/MickLesk) ([#12889](https://github.com/community-scripts/ProxmoxVE/pull/12889))
|
||||||
|
|
||||||
|
- #### 🔧 Refactor
|
||||||
|
|
||||||
|
- Refactor: ITSM-NG [@MickLesk](https://github.com/MickLesk) ([#12918](https://github.com/community-scripts/ProxmoxVE/pull/12918))
|
||||||
|
- core: unify RELEASE variable for check_for_gh_release and fetch_and_deploy [@MickLesk](https://github.com/MickLesk) ([#12917](https://github.com/community-scripts/ProxmoxVE/pull/12917))
|
||||||
|
- Standardize NSAPP names across VM scripts [@MickLesk](https://github.com/MickLesk) ([#12924](https://github.com/community-scripts/ProxmoxVE/pull/12924))
|
||||||
|
|
||||||
|
### 💾 Core
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- core: retry downloads with exponential backoff [@MickLesk](https://github.com/MickLesk) ([#12896](https://github.com/community-scripts/ProxmoxVE/pull/12896))
|
||||||
|
|
||||||
|
### ❔ Uncategorized
|
||||||
|
|
||||||
|
- [go2rtc] Add ffmpeg dependency to install script [@Copilot](https://github.com/Copilot) ([#12944](https://github.com/community-scripts/ProxmoxVE/pull/12944))
|
||||||
|
|
||||||
|
## 2026-03-14
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- Patchmon: remove v prefix from pinned version [@MickLesk](https://github.com/MickLesk) ([#12891](https://github.com/community-scripts/ProxmoxVE/pull/12891))
|
||||||
|
|
||||||
|
### 💾 Core
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- tools.func: don't abort on AMD repo apt update failure [@MickLesk](https://github.com/MickLesk) ([#12890](https://github.com/community-scripts/ProxmoxVE/pull/12890))
|
||||||
|
|
||||||
|
## 2026-03-13
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- Hotfix: Removed clean install usage from original script. [@nickheyer](https://github.com/nickheyer) ([#12870](https://github.com/community-scripts/ProxmoxVE/pull/12870))
|
||||||
|
|
||||||
|
- #### 🔧 Refactor
|
||||||
|
|
||||||
|
- Discopanel: V2 Support + Script rewrite [@nickheyer](https://github.com/nickheyer) ([#12763](https://github.com/community-scripts/ProxmoxVE/pull/12763))
|
||||||
|
|
||||||
|
### 🧰 Tools
|
||||||
|
|
||||||
|
- update-apps: fix restore path, add PBS support and improve restore messages [@omertahaoztop](https://github.com/omertahaoztop) ([#12528](https://github.com/community-scripts/ProxmoxVE/pull/12528))
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- fix(pve-privilege-converter): handle already stopped container in manage_states [@liuqitoday](https://github.com/liuqitoday) ([#12765](https://github.com/community-scripts/ProxmoxVE/pull/12765))
|
||||||
|
|
||||||
|
### 📚 Documentation
|
||||||
|
|
||||||
|
- Update: Docs/website metadata workflow [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#12858](https://github.com/community-scripts/ProxmoxVE/pull/12858))
|
||||||
|
|
||||||
|
## 2026-03-12
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- manyfold: fix incorrect port in upstream requests by forwarding original host [@anlopo](https://github.com/anlopo) ([#12812](https://github.com/community-scripts/ProxmoxVE/pull/12812))
|
||||||
|
- SparkyFitness: install pnpm dependencies from workspace root [@MickLesk](https://github.com/MickLesk) ([#12792](https://github.com/community-scripts/ProxmoxVE/pull/12792))
|
||||||
|
- n8n: add build-essential to update dependencies [@MickLesk](https://github.com/MickLesk) ([#12795](https://github.com/community-scripts/ProxmoxVE/pull/12795))
|
||||||
|
- Frigate openvino labelmap patch [@semtex1987](https://github.com/semtex1987) ([#12751](https://github.com/community-scripts/ProxmoxVE/pull/12751))
|
||||||
|
|
||||||
|
- #### 🔧 Refactor
|
||||||
|
|
||||||
|
- Pin Patchmon to 1.4.2 [@vhsdream](https://github.com/vhsdream) ([#12789](https://github.com/community-scripts/ProxmoxVE/pull/12789))
|
||||||
|
|
||||||
|
### 💾 Core
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- tools.func: correct PATH escaping in ROCm profile script [@MickLesk](https://github.com/MickLesk) ([#12793](https://github.com/community-scripts/ProxmoxVE/pull/12793))
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- core: add mode=generated for unattended frontend installs [@MickLesk](https://github.com/MickLesk) ([#12807](https://github.com/community-scripts/ProxmoxVE/pull/12807))
|
||||||
|
- core: validate storage availability when loading defaults [@MickLesk](https://github.com/MickLesk) ([#12794](https://github.com/community-scripts/ProxmoxVE/pull/12794))
|
||||||
|
|
||||||
|
- #### 🔧 Refactor
|
||||||
|
|
||||||
|
- tools.func: support older NVIDIA driver versions with 2 segments (xxx.xxx) [@MickLesk](https://github.com/MickLesk) ([#12796](https://github.com/community-scripts/ProxmoxVE/pull/12796))
|
||||||
|
|
||||||
|
### 🧰 Tools
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- Fix PBS microcode naming [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#12834](https://github.com/community-scripts/ProxmoxVE/pull/12834))
|
||||||
|
|
||||||
|
### 📂 Github
|
||||||
|
|
||||||
|
- Cleanup: remove old workflow files [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#12818](https://github.com/community-scripts/ProxmoxVE/pull/12818))
|
||||||
|
- Cleanup: remove frontend, move JSONs to json/ top-level [@MickLesk](https://github.com/MickLesk) ([#12813](https://github.com/community-scripts/ProxmoxVE/pull/12813))
|
||||||
|
|
||||||
|
### ❔ Uncategorized
|
||||||
|
|
||||||
|
- Remove json files [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#12830](https://github.com/community-scripts/ProxmoxVE/pull/12830))
|
||||||
|
|
||||||
|
## 2026-03-11
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- fix: Init telemetry in addon scripts [@MickLesk](https://github.com/MickLesk) ([#12777](https://github.com/community-scripts/ProxmoxVE/pull/12777))
|
||||||
|
- Tracearr: Increase default disk variable from 5 to 10 [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#12762](https://github.com/community-scripts/ProxmoxVE/pull/12762))
|
||||||
|
- Fix Wireguard Dashboard update [@odin568](https://github.com/odin568) ([#12767](https://github.com/community-scripts/ProxmoxVE/pull/12767))
|
||||||
|
|
||||||
|
### 🧰 Tools
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- Coder-Code-Server: Check if config file exists [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#12758](https://github.com/community-scripts/ProxmoxVE/pull/12758))
|
||||||
|
|
||||||
|
## 2026-03-10
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- [Fix] Immich: Pin libvips to 8.17.3 [@vhsdream](https://github.com/vhsdream) ([#12744](https://github.com/community-scripts/ProxmoxVE/pull/12744))
|
||||||
|
|
||||||
|
## 2026-03-09
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- Pin Opencloud to 5.2.0 [@vhsdream](https://github.com/vhsdream) ([#12721](https://github.com/community-scripts/ProxmoxVE/pull/12721))
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- [Hotfix] qBittorrent: Disable UPnP port forwarding by default [@vhsdream](https://github.com/vhsdream) ([#12728](https://github.com/community-scripts/ProxmoxVE/pull/12728))
|
||||||
|
- [Quickfix] Opencloud: ensure correct case for binary [@vhsdream](https://github.com/vhsdream) ([#12729](https://github.com/community-scripts/ProxmoxVE/pull/12729))
|
||||||
|
- Omada: Bump libssl [@MickLesk](https://github.com/MickLesk) ([#12724](https://github.com/community-scripts/ProxmoxVE/pull/12724))
|
||||||
|
- openwebui: Ensure required dependencies [@MickLesk](https://github.com/MickLesk) ([#12717](https://github.com/community-scripts/ProxmoxVE/pull/12717))
|
||||||
|
- Frigate: try an OpenVino model build fallback [@MickLesk](https://github.com/MickLesk) ([#12704](https://github.com/community-scripts/ProxmoxVE/pull/12704))
|
||||||
|
- Change cronjob setup to use www-data user [@opastorello](https://github.com/opastorello) ([#12695](https://github.com/community-scripts/ProxmoxVE/pull/12695))
|
||||||
|
- RustDesk Server: Fix check_for_gh_release function call [@tremor021](https://github.com/tremor021) ([#12694](https://github.com/community-scripts/ProxmoxVE/pull/12694))
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- feat: improve zigbee2mqtt backup handler [@MickLesk](https://github.com/MickLesk) ([#12714](https://github.com/community-scripts/ProxmoxVE/pull/12714))
|
||||||
|
|
||||||
|
- #### 💥 Breaking Changes
|
||||||
|
|
||||||
|
- Reactive Resume: rewrite for v5 using original repo amruthpilla/reactive-resume [@MickLesk](https://github.com/MickLesk) ([#12705](https://github.com/community-scripts/ProxmoxVE/pull/12705))
|
||||||
|
|
||||||
|
### 💾 Core
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- tools: add Alpine (apk) support to ensure_dependencies and is_package_installed [@MickLesk](https://github.com/MickLesk) ([#12703](https://github.com/community-scripts/ProxmoxVE/pull/12703))
|
||||||
|
- tools.func: extend hwaccel with ROCm [@MickLesk](https://github.com/MickLesk) ([#12707](https://github.com/community-scripts/ProxmoxVE/pull/12707))
|
||||||
|
|
||||||
|
### 🌐 Website
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- feat: add CopycatWarningToast component for user warnings [@BramSuurdje](https://github.com/BramSuurdje) ([#12733](https://github.com/community-scripts/ProxmoxVE/pull/12733))
|
||||||
|
|
||||||
|
## 2026-03-08
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- [Fix] Immich: chown install dir before machine-learning update [@vhsdream](https://github.com/vhsdream) ([#12684](https://github.com/community-scripts/ProxmoxVE/pull/12684))
|
||||||
|
- [Fix] Scanopy: Build generate-fixtures [@vhsdream](https://github.com/vhsdream) ([#12686](https://github.com/community-scripts/ProxmoxVE/pull/12686))
|
||||||
|
- fix: rustdeskserver: use correct repo string [@CrazyWolf13](https://github.com/CrazyWolf13) ([#12682](https://github.com/community-scripts/ProxmoxVE/pull/12682))
|
||||||
|
- NZBGet: Fixes for RAR5 handling [@tremor021](https://github.com/tremor021) ([#12675](https://github.com/community-scripts/ProxmoxVE/pull/12675))
|
||||||
|
|
||||||
|
### 🌐 Website
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- LXC-Execute: Fix slug [@tremor021](https://github.com/tremor021) ([#12681](https://github.com/community-scripts/ProxmoxVE/pull/12681))
|
||||||
|
|
||||||
|
## 2026-03-07
|
||||||
|
|
||||||
|
### 🆕 New Scripts
|
||||||
|
|
||||||
|
- ImmichFrame ([#12653](https://github.com/community-scripts/ProxmoxVE/pull/12653))
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- Grocy: bump PHP version from 8.3 to 8.5 [@MickLesk](https://github.com/MickLesk) ([#12651](https://github.com/community-scripts/ProxmoxVE/pull/12651))
|
||||||
|
- Check for influxdb3 installation in update_script [@odin568](https://github.com/odin568) ([#12648](https://github.com/community-scripts/ProxmoxVE/pull/12648))
|
||||||
|
- Update Rdtclient to dotnet 10.0 [@asylumexp](https://github.com/asylumexp) ([#12638](https://github.com/community-scripts/ProxmoxVE/pull/12638))
|
||||||
|
- fix(immich): fix update script failing to add Debian testing repo when preferences file already exists [@Copilot](https://github.com/Copilot) ([#12631](https://github.com/community-scripts/ProxmoxVE/pull/12631))
|
||||||
|
|
||||||
|
### 💾 Core
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- tools: add interactive GitHub PAT prompt on rate limit / auth failure [@MickLesk](https://github.com/MickLesk) ([#12652](https://github.com/community-scripts/ProxmoxVE/pull/12652))
|
||||||
|
|
||||||
|
### 🌐 Website
|
||||||
|
|
||||||
|
- #### 📝 Script Information
|
||||||
|
|
||||||
|
- Papra: update repository URL to papra-hq/papra [@MickLesk](https://github.com/MickLesk) ([#12650](https://github.com/community-scripts/ProxmoxVE/pull/12650))
|
||||||
|
|
||||||
|
## 2026-03-06
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- RustDesk Server: Fix update script [@tremor021](https://github.com/tremor021) ([#12625](https://github.com/community-scripts/ProxmoxVE/pull/12625))
|
||||||
|
- [Node-RED] Restart service after update [@Aurelien30000](https://github.com/Aurelien30000) ([#12621](https://github.com/community-scripts/ProxmoxVE/pull/12621))
|
||||||
|
- wealthfolio: update cors [@CrazyWolf13](https://github.com/CrazyWolf13) ([#12617](https://github.com/community-scripts/ProxmoxVE/pull/12617))
|
||||||
|
- CryptPad: Better update handling [@tremor021](https://github.com/tremor021) ([#12611](https://github.com/community-scripts/ProxmoxVE/pull/12611))
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- RustDesk Server: Switch to updated repository [@tremor021](https://github.com/tremor021) ([#12083](https://github.com/community-scripts/ProxmoxVE/pull/12083))
|
||||||
|
|
||||||
|
- #### 💥 Breaking Changes
|
||||||
|
|
||||||
|
- Semaphore: Move from BoltDB to SQLite [@tremor021](https://github.com/tremor021) ([#12624](https://github.com/community-scripts/ProxmoxVE/pull/12624))
|
||||||
|
|
||||||
|
## 2026-03-05
|
||||||
|
|
||||||
|
### 🆕 New Scripts
|
||||||
|
|
||||||
|
- ddclient ([#12587](https://github.com/community-scripts/ProxmoxVE/pull/12587))
|
||||||
|
- Netbird ([#12585](https://github.com/community-scripts/ProxmoxVE/pull/12585))
|
||||||
|
- Papra ([#12577](https://github.com/community-scripts/ProxmoxVE/pull/12577))
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- fluid-calendar: add build-essential to install and update dependencies [@Copilot](https://github.com/Copilot) ([#12602](https://github.com/community-scripts/ProxmoxVE/pull/12602))
|
||||||
|
- Refactor: BentoPDF [@vhsdream](https://github.com/vhsdream) ([#12597](https://github.com/community-scripts/ProxmoxVE/pull/12597))
|
||||||
|
- Tianji: Fix the bug introduced by the refactor [@tremor021](https://github.com/tremor021) ([#12564](https://github.com/community-scripts/ProxmoxVE/pull/12564))
|
||||||
|
- PowerDNS: use 'launch=' instead of 'launch+=' for gsqlite3 backend [@MickLesk](https://github.com/MickLesk) ([#12579](https://github.com/community-scripts/ProxmoxVE/pull/12579))
|
||||||
|
|
||||||
|
### 🗑️ Deleted Scripts
|
||||||
|
|
||||||
|
- Suwayomi-Server: remove due to inactivity and very low usage [@MickLesk](https://github.com/MickLesk) ([#12596](https://github.com/community-scripts/ProxmoxVE/pull/12596))
|
||||||
|
|
||||||
|
### 💾 Core
|
||||||
|
|
||||||
|
- #### 🔧 Refactor
|
||||||
|
|
||||||
|
- core: add var_os / var_version to whitelist for app.vars [@MickLesk](https://github.com/MickLesk) ([#12576](https://github.com/community-scripts/ProxmoxVE/pull/12576))
|
||||||
|
|
||||||
|
## 2026-03-04
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- fix: gitea-mirror [@CrazyWolf13](https://github.com/CrazyWolf13) ([#12549](https://github.com/community-scripts/ProxmoxVE/pull/12549))
|
||||||
|
- fix(immich): correct LibRaw clone URL to official upstream [@DenislavDenev](https://github.com/DenislavDenev) ([#12526](https://github.com/community-scripts/ProxmoxVE/pull/12526))
|
||||||
|
- update: stirling-pdf: java 25 [@CrazyWolf13](https://github.com/CrazyWolf13) ([#12552](https://github.com/community-scripts/ProxmoxVE/pull/12552))
|
||||||
|
- Docmost: register NoopAuditService globally when EE submodule is missing [@MickLesk](https://github.com/MickLesk) ([#12551](https://github.com/community-scripts/ProxmoxVE/pull/12551))
|
||||||
|
- jellyseer/overseer migration corrupting /usr/bin/update [@MickLesk](https://github.com/MickLesk) ([#12539](https://github.com/community-scripts/ProxmoxVE/pull/12539))
|
||||||
|
- PowerDNS: use gsqlite3 backend instead of BIND [@MickLesk](https://github.com/MickLesk) ([#12538](https://github.com/community-scripts/ProxmoxVE/pull/12538))
|
||||||
|
- addon migrations: /usr/bin/update replacement to prevent syntax error [@MickLesk](https://github.com/MickLesk) ([#12540](https://github.com/community-scripts/ProxmoxVE/pull/12540))
|
||||||
|
|
||||||
|
- #### 🔧 Refactor
|
||||||
|
|
||||||
|
- Fluid-Calendar: NodeJS bump [@tremor021](https://github.com/tremor021) ([#12558](https://github.com/community-scripts/ProxmoxVE/pull/12558))
|
||||||
|
- Refactor: LiteLLM [@tremor021](https://github.com/tremor021) ([#12550](https://github.com/community-scripts/ProxmoxVE/pull/12550))
|
||||||
|
|
||||||
|
### 💾 Core
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- tools: fall back to distro packages for psql [@MickLesk](https://github.com/MickLesk) ([#12542](https://github.com/community-scripts/ProxmoxVE/pull/12542))
|
||||||
|
- fix: whitelist var_searchdomain and fix the handling of var_ns and va… [@tommoyer](https://github.com/tommoyer) ([#12521](https://github.com/community-scripts/ProxmoxVE/pull/12521))
|
||||||
|
|
||||||
|
## 2026-03-03
|
||||||
|
|
||||||
|
### 🆕 New Scripts
|
||||||
|
|
||||||
|
- Tinyauth: v5 Support & add Debian Version [@MickLesk](https://github.com/MickLesk) ([#12501](https://github.com/community-scripts/ProxmoxVE/pull/12501))
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- cross-seed: install build-essential to resolve missing `make` error [@Copilot](https://github.com/Copilot) ([#12522](https://github.com/community-scripts/ProxmoxVE/pull/12522))
|
||||||
|
- meshcentral: increased disk space to 4GB [@MickLesk](https://github.com/MickLesk) ([#12509](https://github.com/community-scripts/ProxmoxVE/pull/12509))
|
||||||
|
|
||||||
|
- #### 🔧 Refactor
|
||||||
|
|
||||||
|
- opnsense-vm: harden temp dir, bridge detection and network selection [@MickLesk](https://github.com/MickLesk) ([#12513](https://github.com/community-scripts/ProxmoxVE/pull/12513))
|
||||||
|
|
||||||
|
### 🗑️ Deleted Scripts
|
||||||
|
|
||||||
|
- Remove Unifi Network Server scripts (dead APT repo) [@Copilot](https://github.com/Copilot) ([#12500](https://github.com/community-scripts/ProxmoxVE/pull/12500))
|
||||||
|
|
||||||
|
### 💾 Core
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- core: recovery - add ENOSPC disk-full detection with auto-retry using * 2 hdd [@MickLesk](https://github.com/MickLesk) ([#12511](https://github.com/community-scripts/ProxmoxVE/pull/12511))
|
||||||
|
|
||||||
|
### 📚 Documentation
|
||||||
|
|
||||||
|
- Fix config_path casing in reactive-resume.json [@ScubyG](https://github.com/ScubyG) ([#12525](https://github.com/community-scripts/ProxmoxVE/pull/12525))
|
||||||
|
|
||||||
|
### 🌐 Website
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- Revert #11534 PR that messed up search [@BramSuurdje](https://github.com/BramSuurdje) ([#12492](https://github.com/community-scripts/ProxmoxVE/pull/12492))
|
||||||
|
|
||||||
|
## 2026-03-02
|
||||||
|
|
||||||
|
### 🆕 New Scripts
|
||||||
|
|
||||||
|
- PowerDNS ([#12481](https://github.com/community-scripts/ProxmoxVE/pull/12481))
|
||||||
|
- Profilarr ([#12441](https://github.com/community-scripts/ProxmoxVE/pull/12441))
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- Tracearr: prepare for imminent v1.4.19 release [@durzo](https://github.com/durzo) ([#12413](https://github.com/community-scripts/ProxmoxVE/pull/12413))
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- Frigate: Bump to v0.17 [@MickLesk](https://github.com/MickLesk) ([#12474](https://github.com/community-scripts/ProxmoxVE/pull/12474))
|
||||||
|
|
||||||
|
- #### 💥 Breaking Changes
|
||||||
|
|
||||||
|
- Migrate: DokPloy, Komodo, Coolify, Dockge, Runtipi to Addons [@MickLesk](https://github.com/MickLesk) ([#12275](https://github.com/community-scripts/ProxmoxVE/pull/12275))
|
||||||
|
|
||||||
|
- #### 🔧 Refactor
|
||||||
|
|
||||||
|
- ref: replace generic exit 1 with specific exit codes in ct & install [@MickLesk](https://github.com/MickLesk) ([#12475](https://github.com/community-scripts/ProxmoxVE/pull/12475))
|
||||||
|
|
||||||
|
### 💾 Core
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- tools.func: Improve stability with retry logic, caching, and debug mode [@MickLesk](https://github.com/MickLesk) ([#10351](https://github.com/community-scripts/ProxmoxVE/pull/10351))
|
||||||
|
|
||||||
|
- #### 🔧 Refactor
|
||||||
|
|
||||||
|
- core: standardize exit codes and add mappings [@MickLesk](https://github.com/MickLesk) ([#12467](https://github.com/community-scripts/ProxmoxVE/pull/12467))
|
||||||
|
|
||||||
|
### 🌐 Website
|
||||||
|
|
||||||
|
- frontend: improve detail view badges, addon texts, and HTML title [@MickLesk](https://github.com/MickLesk) ([#12461](https://github.com/community-scripts/ProxmoxVE/pull/12461))
|
||||||
|
|
||||||
|
## 2026-03-01
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- Sparkyfitness: use pnpm [@tomfrenzel](https://github.com/tomfrenzel) ([#12445](https://github.com/community-scripts/ProxmoxVE/pull/12445))
|
||||||
|
- OpenArchiver: Fix installation [@tremor021](https://github.com/tremor021) ([#12447](https://github.com/community-scripts/ProxmoxVE/pull/12447))
|
||||||
Generated
+343
@@ -0,0 +1,343 @@
|
|||||||
|
## 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
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- Immich: Ensure newline before appending IMMICH_HELMET_FILE to .env [@MickLesk](https://github.com/MickLesk) ([#13667](https://github.com/community-scripts/ProxmoxVE/pull/13667))
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- BentoPDF: replace http-server with nginx to fix WASM initialization timeout [@MickLesk](https://github.com/MickLesk) ([#13625](https://github.com/community-scripts/ProxmoxVE/pull/13625))
|
||||||
|
- Element Synapse: Add MatrixRTC configuration for Element Call support [@MickLesk](https://github.com/MickLesk) ([#13665](https://github.com/community-scripts/ProxmoxVE/pull/13665))
|
||||||
|
- RomM: Use ROMM_BASE_PATH from .env for symlinks and nginx config [@MickLesk](https://github.com/MickLesk) ([#13666](https://github.com/community-scripts/ProxmoxVE/pull/13666))
|
||||||
|
- Immich: Pin version to 2.7.4 [@vhsdream](https://github.com/vhsdream) ([#13661](https://github.com/community-scripts/ProxmoxVE/pull/13661))
|
||||||
|
|
||||||
|
- #### 🔧 Refactor
|
||||||
|
|
||||||
|
- Crafty Controller: Wait for credentials file instead of fixed sleep [@MickLesk](https://github.com/MickLesk) ([#13670](https://github.com/community-scripts/ProxmoxVE/pull/13670))
|
||||||
|
- Refactor: Alpine-Wakapi [@tremor021](https://github.com/tremor021) ([#13656](https://github.com/community-scripts/ProxmoxVE/pull/13656))
|
||||||
|
|
||||||
|
## 2026-04-10
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- fix: ensure trailing newline in redis.conf before appending bind directive [@Copilot](https://github.com/Copilot) ([#13647](https://github.com/community-scripts/ProxmoxVE/pull/13647))
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- Immich: Pin version to 2.7.3 [@vhsdream](https://github.com/vhsdream) ([#13631](https://github.com/community-scripts/ProxmoxVE/pull/13631))
|
||||||
|
- Homarr: bind Redis to localhost only [@MickLesk](https://github.com/MickLesk) ([#13552](https://github.com/community-scripts/ProxmoxVE/pull/13552))
|
||||||
|
|
||||||
|
### 💾 Core
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- tools.func: prevent script crash when entering GitHub token after rate limit [@MickLesk](https://github.com/MickLesk) ([#13638](https://github.com/community-scripts/ProxmoxVE/pull/13638))
|
||||||
|
|
||||||
|
### 🧰 Tools
|
||||||
|
|
||||||
|
- #### 🔧 Refactor
|
||||||
|
|
||||||
|
- addons: Filebrowser & Filebrowser-Quantum get warning if host install [@MickLesk](https://github.com/MickLesk) ([#13639](https://github.com/community-scripts/ProxmoxVE/pull/13639))
|
||||||
|
|
||||||
|
## 2026-04-09
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- boostack: add: git [@CrazyWolf13](https://github.com/CrazyWolf13) ([#13620](https://github.com/community-scripts/ProxmoxVE/pull/13620))
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- Update OPNsense version from 25.7 to 26.1 [@tdn131](https://github.com/tdn131) ([#13626](https://github.com/community-scripts/ProxmoxVE/pull/13626))
|
||||||
|
- CheckMK: Bump Default OS to 13 (trixie) + dynamic codename + fix RELEASE-Tag Fetching [@MickLesk](https://github.com/MickLesk) ([#13610](https://github.com/community-scripts/ProxmoxVE/pull/13610))
|
||||||
|
|
||||||
|
## 2026-04-08
|
||||||
|
|
||||||
|
### 🆕 New Scripts
|
||||||
|
|
||||||
|
- IronClaw | Alpine-IronClaw ([#13591](https://github.com/community-scripts/ProxmoxVE/pull/13591))
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- immich: disable upgrade-insecure-requests CSP directive [@MickLesk](https://github.com/MickLesk) ([#13600](https://github.com/community-scripts/ProxmoxVE/pull/13600))
|
||||||
|
- Immich: v2.7.2 [@vhsdream](https://github.com/vhsdream) ([#13579](https://github.com/community-scripts/ProxmoxVE/pull/13579))
|
||||||
|
- Update flaresolverr-install.sh [@maztheman](https://github.com/maztheman) ([#13584](https://github.com/community-scripts/ProxmoxVE/pull/13584))
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- bambuddy: add mkdir before data restore & add ffmpeg dependency [@MickLesk](https://github.com/MickLesk) ([#13601](https://github.com/community-scripts/ProxmoxVE/pull/13601))
|
||||||
|
|
||||||
|
- #### 🔧 Refactor
|
||||||
|
|
||||||
|
- feat: update UHF Server script to use setup_ffmpeg [@zackwithak13](https://github.com/zackwithak13) ([#13564](https://github.com/community-scripts/ProxmoxVE/pull/13564))
|
||||||
|
|
||||||
|
### 💾 Core
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- core: add script page badges to descriptions | change donate URL [@MickLesk](https://github.com/MickLesk) ([#13596](https://github.com/community-scripts/ProxmoxVE/pull/13596))
|
||||||
|
|
||||||
|
## 2026-04-07
|
||||||
|
|
||||||
|
### 🗑️ Deleted Scripts
|
||||||
|
|
||||||
|
- Remove low-install-count CT scripts and installers [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#13570](https://github.com/community-scripts/ProxmoxVE/pull/13570))
|
||||||
|
|
||||||
|
### 💾 Core
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- core: improve resilience for top Proxmox error codes (209, 215, 118, 206) [@MickLesk](https://github.com/MickLesk) ([#13575](https://github.com/community-scripts/ProxmoxVE/pull/13575))
|
||||||
|
|
||||||
|
## 2026-04-06
|
||||||
|
|
||||||
|
### 🆕 New Scripts
|
||||||
|
|
||||||
|
- OpenThread Border Router ([#13536](https://github.com/community-scripts/ProxmoxVE/pull/13536))
|
||||||
|
- Homelable ([#13539](https://github.com/community-scripts/ProxmoxVE/pull/13539))
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- Papra: check env before copy [@MickLesk](https://github.com/MickLesk) ([#13553](https://github.com/community-scripts/ProxmoxVE/pull/13553))
|
||||||
|
- changedetection: fix: typing_extensions error [@CrazyWolf13](https://github.com/CrazyWolf13) ([#13548](https://github.com/community-scripts/ProxmoxVE/pull/13548))
|
||||||
|
- kasm: fix: fetch latest version [@CrazyWolf13](https://github.com/CrazyWolf13) ([#13547](https://github.com/community-scripts/ProxmoxVE/pull/13547))
|
||||||
|
|
||||||
|
## 2026-04-05
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- Grist: remove install:ee step (private repo, not needed for grist-core) [@MickLesk](https://github.com/MickLesk) ([#13526](https://github.com/community-scripts/ProxmoxVE/pull/13526))
|
||||||
|
- Nginx Proxy Manager: ensure /tmp/nginx/body exists via openresty service [@MickLesk](https://github.com/MickLesk) ([#13528](https://github.com/community-scripts/ProxmoxVE/pull/13528))
|
||||||
|
- MotionEye: run as root to enable SMB share support [@MickLesk](https://github.com/MickLesk) ([#13527](https://github.com/community-scripts/ProxmoxVE/pull/13527))
|
||||||
|
|
||||||
|
### 💾 Core
|
||||||
|
|
||||||
|
- #### 🔧 Refactor
|
||||||
|
|
||||||
|
- core: silent() function - use return instead of exit to allow || true error handling [@MickLesk](https://github.com/MickLesk) ([#13529](https://github.com/community-scripts/ProxmoxVE/pull/13529))
|
||||||
|
|
||||||
|
## 2026-04-04
|
||||||
|
|
||||||
|
### 🧰 Tools
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- komodo: set `PERIPHERY_CORE_PUBLIC_KEYS` to default value if absent [@4ndv](https://github.com/4ndv) ([#13519](https://github.com/community-scripts/ProxmoxVE/pull/13519))
|
||||||
|
|
||||||
|
## 2026-04-03
|
||||||
|
|
||||||
|
### 🆕 New Scripts
|
||||||
|
|
||||||
|
- netboot.xyz ([#13480](https://github.com/community-scripts/ProxmoxVE/pull/13480))
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- OpenWRT-VM: use poweroff instead of halt to properly stop VM [@MickLesk](https://github.com/MickLesk) ([#13504](https://github.com/community-scripts/ProxmoxVE/pull/13504))
|
||||||
|
- NginxProxyManager: fix openresty restart by setting user root before reload [@MickLesk](https://github.com/MickLesk) ([#13500](https://github.com/community-scripts/ProxmoxVE/pull/13500))
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- Crafty Controller: add Java 25 for Minecraft 1.26.1+ [@MickLesk](https://github.com/MickLesk) ([#13502](https://github.com/community-scripts/ProxmoxVE/pull/13502))
|
||||||
|
- Wealthfolio: update to v3.2.1 and Node.js 24 [@afadil](https://github.com/afadil) ([#13486](https://github.com/community-scripts/ProxmoxVE/pull/13486))
|
||||||
|
|
||||||
|
### 💾 Core
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- core.func: prevent profile.d scripts from aborting on non-zero exit [@MickLesk](https://github.com/MickLesk) ([#13503](https://github.com/community-scripts/ProxmoxVE/pull/13503))
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- APT Proxy: Support full URLs (http/https with custom ports) [@MickLesk](https://github.com/MickLesk) ([#13474](https://github.com/community-scripts/ProxmoxVE/pull/13474))
|
||||||
|
|
||||||
|
### 🧰 Tools
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- PVE LXC-Updater: pipe apt list through cat to prevent pager hang [@MickLesk](https://github.com/MickLesk) ([#13501](https://github.com/community-scripts/ProxmoxVE/pull/13501))
|
||||||
|
|
||||||
|
## 2026-04-02
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- Grist: Guard backup restore for empty docs/db files [@MickLesk](https://github.com/MickLesk) ([#13472](https://github.com/community-scripts/ProxmoxVE/pull/13472))
|
||||||
|
- fix(zigbee2mqtt): suppress grep error when pnpm-workspace.yaml is absent on update [@Copilot](https://github.com/Copilot) ([#13476](https://github.com/community-scripts/ProxmoxVE/pull/13476))
|
||||||
|
|
||||||
|
### 🧰 Tools
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- Cron LXC Updater: Add full PATH for cron environment [@MickLesk](https://github.com/MickLesk) ([#13473](https://github.com/community-scripts/ProxmoxVE/pull/13473))
|
||||||
|
|
||||||
|
## 2026-04-01
|
||||||
|
|
||||||
|
### 🆕 New Scripts
|
||||||
|
|
||||||
|
- DrawDB ([#13454](https://github.com/community-scripts/ProxmoxVE/pull/13454))
|
||||||
|
|
||||||
|
### 🧰 Tools
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- Filebrowser: make noauth setup use correct database [@MickLesk](https://github.com/MickLesk) ([#13457](https://github.com/community-scripts/ProxmoxVE/pull/13457))
|
||||||
Generated
+1
-1
@@ -22,6 +22,6 @@ Fixes #
|
|||||||
- [ ] ✨ **New feature** – Adds new, non-breaking functionality.
|
- [ ] ✨ **New feature** – Adds new, non-breaking functionality.
|
||||||
- [ ] 💥 **Breaking change** – Alters existing functionality in a way that may require updates.
|
- [ ] 💥 **Breaking change** – Alters existing functionality in a way that may require updates.
|
||||||
- [ ] 🆕 **New script** – A fully functional and tested script or script set.
|
- [ ] 🆕 **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.
|
- [ ] 🔧 **Refactoring / Code Cleanup** – Improves readability or maintainability without changing functionality.
|
||||||
- [ ] 📝 **Documentation update** – Changes to `README`, `AppName.md`, `CONTRIBUTING.md`, or other docs.
|
- [ ] 📝 **Documentation update** – Changes to `README`, `AppName.md`, `CONTRIBUTING.md`, or other docs.
|
||||||
|
|||||||
-68
@@ -1,68 +0,0 @@
|
|||||||
FROM mcr.microsoft.com/dotnet/runtime-deps:8.0-jammy as build
|
|
||||||
|
|
||||||
ARG TARGETOS
|
|
||||||
ARG TARGETARCH
|
|
||||||
ARG DOCKER_VERSION=27.5.1
|
|
||||||
ARG BUILDX_VERSION=0.20.1
|
|
||||||
ARG RUNNER_ARCH="x64"
|
|
||||||
|
|
||||||
RUN apt update -y && apt install sudo curl unzip -y
|
|
||||||
|
|
||||||
WORKDIR /actions-runner
|
|
||||||
|
|
||||||
RUN RUNNER_VERSION=$(curl -s https://api.github.com/repos/actions/runner/releases/latest | grep "tag_name" | head -n 1 | awk '{print substr($2, 3, length($2)-4)}') \
|
|
||||||
&& curl -f -L -o runner.tar.gz https://github.com/actions/runner/releases/download/v${RUNNER_VERSION}/actions-runner-linux-${RUNNER_ARCH}-${RUNNER_VERSION}.tar.gz \
|
|
||||||
&& tar xzf ./runner.tar.gz \
|
|
||||||
&& rm runner.tar.gz
|
|
||||||
|
|
||||||
RUN RUNNER_CONTAINER_HOOKS_VERSION=$(curl -s https://api.github.com/repos/actions/runner-container-hooks/releases/latest | grep "tag_name" | head -n 1 | awk '{print substr($2, 3, length($2)-4)}') \
|
|
||||||
&& curl -f -L -o runner-container-hooks.zip https://github.com/actions/runner-container-hooks/releases/download/v${RUNNER_CONTAINER_HOOKS_VERSION}/actions-runner-hooks-k8s-${RUNNER_CONTAINER_HOOKS_VERSION}.zip \
|
|
||||||
&& unzip ./runner-container-hooks.zip -d ./k8s \
|
|
||||||
&& rm runner-container-hooks.zip
|
|
||||||
|
|
||||||
RUN export RUNNER_ARCH=${TARGETARCH} \
|
|
||||||
&& if [ "$RUNNER_ARCH" = "amd64" ]; then export DOCKER_ARCH=x86_64 ; fi \
|
|
||||||
&& if [ "$RUNNER_ARCH" = "arm64" ]; then export DOCKER_ARCH=aarch64 ; fi \
|
|
||||||
&& curl -fLo docker.tgz https://download.docker.com/${TARGETOS}/static/stable/${DOCKER_ARCH}/docker-${DOCKER_VERSION}.tgz \
|
|
||||||
&& tar zxvf docker.tgz \
|
|
||||||
&& rm -rf docker.tgz \
|
|
||||||
&& mkdir -p /usr/local/lib/docker/cli-plugins \
|
|
||||||
&& curl -fLo /usr/local/lib/docker/cli-plugins/docker-buildx \
|
|
||||||
"https://github.com/docker/buildx/releases/download/v${BUILDX_VERSION}/buildx-v${BUILDX_VERSION}.linux-${TARGETARCH}" \
|
|
||||||
&& chmod +x /usr/local/lib/docker/cli-plugins/docker-buildx
|
|
||||||
|
|
||||||
FROM mcr.microsoft.com/dotnet/runtime-deps:8.0-jammy
|
|
||||||
|
|
||||||
ENV DEBIAN_FRONTEND=noninteractive
|
|
||||||
ENV RUNNER_MANUALLY_TRAP_SIG=1
|
|
||||||
ENV ACTIONS_RUNNER_PRINT_LOG_TO_STDOUT=1
|
|
||||||
ENV ImageOS=ubuntu22
|
|
||||||
|
|
||||||
RUN apt update -y \
|
|
||||||
&& apt install -y --no-install-recommends sudo lsb-release gpg-agent software-properties-common curl jq unzip \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
RUN add-apt-repository ppa:git-core/ppa \
|
|
||||||
&& apt update -y \
|
|
||||||
&& apt install -y git \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
RUN adduser --disabled-password --gecos "" --uid 1001 runner \
|
|
||||||
&& groupadd docker --gid 123 \
|
|
||||||
&& usermod -aG sudo runner \
|
|
||||||
&& usermod -aG docker runner \
|
|
||||||
&& echo "%sudo ALL=(ALL:ALL) NOPASSWD:ALL" > /etc/sudoers \
|
|
||||||
&& echo "Defaults env_keep += \"DEBIAN_FRONTEND\"" >> /etc/sudoers
|
|
||||||
|
|
||||||
# Install own dependencies in final image
|
|
||||||
RUN curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \
|
|
||||||
&& apt-get install -y nodejs \
|
|
||||||
&& apt-get install -y gh jq git
|
|
||||||
|
|
||||||
WORKDIR /home/runner
|
|
||||||
|
|
||||||
COPY --chown=runner:docker --from=build /actions-runner .
|
|
||||||
COPY --from=build /usr/local/lib/docker/cli-plugins/docker-buildx /usr/local/lib/docker/cli-plugins/docker-buildx
|
|
||||||
RUN install -o root -g root -m 755 docker/* /usr/bin/ && rm -rf docker
|
|
||||||
|
|
||||||
USER runner
|
|
||||||
Generated
+1
-1
@@ -93,7 +93,7 @@ jobs:
|
|||||||
const websiteRegex = new RegExp(`- \\[(x|X)\\]\\s*${escapedWebsite}`, "i");
|
const websiteRegex = new RegExp(`- \\[(x|X)\\]\\s*${escapedWebsite}`, "i");
|
||||||
|
|
||||||
if (websiteRegex.test(prBody)) {
|
if (websiteRegex.test(prBody)) {
|
||||||
const hasJson = prFiles.some((f) => f.filename.startsWith("frontend/public/json/"));
|
const hasJson = prFiles.some((f) => f.filename.startsWith("json/"));
|
||||||
const hasUpdateScript = labelsToAdd.has("update script");
|
const hasUpdateScript = labelsToAdd.has("update script");
|
||||||
const hasContentLabel = ["bugfix", "feature", "refactor"].some((l) => labelsToAdd.has(l));
|
const hasContentLabel = ["bugfix", "feature", "refactor"].some((l) => labelsToAdd.has(l));
|
||||||
|
|
||||||
|
|||||||
-55
@@ -1,55 +0,0 @@
|
|||||||
name: Auto-Close Wrong Template Issues
|
|
||||||
on:
|
|
||||||
issues:
|
|
||||||
types: [opened]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
close_tteck_issues:
|
|
||||||
if: github.repository == 'community-scripts/ProxmoxVE'
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Auto-close if wrong Template issue detected
|
|
||||||
uses: actions/github-script@v7
|
|
||||||
with:
|
|
||||||
script: |
|
|
||||||
const issue = context.payload.issue;
|
|
||||||
const content = `${issue.title}\n${issue.body}`;
|
|
||||||
const issueNumber = issue.number;
|
|
||||||
|
|
||||||
// Regex patterns (case-insensitive, flexible versioning)
|
|
||||||
const patterns = [
|
|
||||||
/Template\s+debian-13-standard_[\d.]+-[\d]+_amd64\.tar\.zst\s*\[(online|local)\]/i,
|
|
||||||
/Template\s+debian-13-standard_[\d.]+-[\d]+_amd64\.tar\.zst\s+is\s+missing\s+or\s+corrupted/i,
|
|
||||||
/Container\s+creation\s+failed\.?\s+Checking\s+if\s+template\s+is\s+corrupted\s+or\s+incomplete/i,
|
|
||||||
/Template\s+is\s+valid,\s+but\s+container\s+creation\s+still\s+failed/i,
|
|
||||||
/exit\s+code\s+0:\s+while\s+executing\s+command\s+bash\s+-c\s+"\$?\(curl\s+-fsSL\s+https:\/\/raw\.githubusercontent\.com\/[\w/-]+\/create_lxc\.sh\)"/i
|
|
||||||
];
|
|
||||||
|
|
||||||
const matched = patterns.some((regex) => regex.test(content));
|
|
||||||
|
|
||||||
if (matched) {
|
|
||||||
const message = "👋 Hello!\n\n" +
|
|
||||||
"It looks like you are referencing a **container creation issue with a Debian 13 template** (e.g. `debian-13-standard_13.x-x_amd64.tar.zst`).\n\n" +
|
|
||||||
"We receive many similar reports about this, and it's not related to the scripts themselves but to **a Proxmox base template bug**.\n\n" +
|
|
||||||
"Please refer to [discussion #8126](https://github.com/community-scripts/ProxmoxVE/discussions/8126) for details.\n" +
|
|
||||||
"If your issue persists after following the guidance there, feel free to reopen this issue.\n\n" +
|
|
||||||
"_This issue was automatically closed by a bot._";
|
|
||||||
|
|
||||||
await github.rest.issues.createComment({
|
|
||||||
...context.repo,
|
|
||||||
issue_number: issueNumber,
|
|
||||||
body: message
|
|
||||||
});
|
|
||||||
|
|
||||||
await github.rest.issues.addLabels({
|
|
||||||
...context.repo,
|
|
||||||
issue_number: issueNumber,
|
|
||||||
labels: ["not planned"]
|
|
||||||
});
|
|
||||||
|
|
||||||
await github.rest.issues.update({
|
|
||||||
...context.repo,
|
|
||||||
issue_number: issueNumber,
|
|
||||||
state: "closed"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
-126
@@ -1,126 +0,0 @@
|
|||||||
name: Crawl Versions from newreleases.io
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
schedule:
|
|
||||||
# Runs at 12:00 AM and 12:00 PM UTC
|
|
||||||
- cron: "0 0,12 * * *"
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
pull-requests: write
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
crawl-versions:
|
|
||||||
if: github.repository == 'community-scripts/ProxmoxVE'
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout Repository
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
with:
|
|
||||||
repository: community-scripts/ProxmoxVE
|
|
||||||
ref: main
|
|
||||||
|
|
||||||
- name: Generate a token
|
|
||||||
id: generate-token
|
|
||||||
uses: actions/create-github-app-token@v1
|
|
||||||
with:
|
|
||||||
app-id: ${{ vars.APP_ID }}
|
|
||||||
private-key: ${{ secrets.APP_PRIVATE_KEY }}
|
|
||||||
|
|
||||||
- name: Crawl from newreleases.io
|
|
||||||
env:
|
|
||||||
token: ${{ secrets.NEWRELEASES_TOKEN }}
|
|
||||||
run: |
|
|
||||||
page=1
|
|
||||||
projects_file="project_json"
|
|
||||||
output_file="frontend/public/json/versions.json"
|
|
||||||
|
|
||||||
echo "[]" > $output_file
|
|
||||||
|
|
||||||
while true; do
|
|
||||||
|
|
||||||
echo "Start loop on page: $page"
|
|
||||||
|
|
||||||
projects=$(curl -s -H "X-Key: $token" "https://api.newreleases.io/v1/projects?page=$page")
|
|
||||||
total_pages=$(echo "$projects" | jq -r '.total_pages')
|
|
||||||
|
|
||||||
if [ -z "$total_pages" ] || [ "$total_pages" -eq 0 ]; then
|
|
||||||
echo "No pages available. Exiting."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
if [ $page == $total_pages ]; then
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "$projects" ] || ! echo "$projects" | jq -e '.projects' > /dev/null; then
|
|
||||||
echo "No more projects or invalid response. Exiting."
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "$projects" > "$projects_file"
|
|
||||||
|
|
||||||
jq -r '.projects[] | "\(.id) \(.name)"' "$projects_file" | while read -r id name; do
|
|
||||||
version=$(curl -s -H "X-Key: $token" "https://api.newreleases.io/v1/projects/$id/latest-release")
|
|
||||||
version_data=$(echo "$version" | jq -r '.version // empty')
|
|
||||||
date=$(echo "$version" | jq -r '.date // empty')
|
|
||||||
if [ -n "$version_data" ]; then
|
|
||||||
jq --arg name "$name" --arg version "$version_data" --arg date "$date" \
|
|
||||||
'. += [{"name": $name, "version": $version, "date": $date}]' "$output_file" > "$output_file.tmp" && mv "$output_file.tmp" "$output_file"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
((page++))
|
|
||||||
done
|
|
||||||
|
|
||||||
- name: Commit JSON
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
|
|
||||||
run: |
|
|
||||||
git config --global user.email "github-actions[bot]@users.noreply.github.com"
|
|
||||||
git config --global user.name "GitHub Actions[bot]"
|
|
||||||
git checkout -b update_versions || git checkout update_versions
|
|
||||||
git add frontend/public/json/versions.json
|
|
||||||
if git diff --cached --quiet; then
|
|
||||||
echo "No changes detected."
|
|
||||||
echo "changed=false" >> "$GITHUB_ENV"
|
|
||||||
exit 0
|
|
||||||
else
|
|
||||||
echo "Changes detected:"
|
|
||||||
git diff --stat --cached
|
|
||||||
echo "changed=true" >> "$GITHUB_ENV"
|
|
||||||
fi
|
|
||||||
git commit -m "Update versions.json"
|
|
||||||
git push origin update_versions --force
|
|
||||||
gh pr create --title "[Github Action] Update versions.json" --body "Update versions.json, crawled from newreleases.io" --base main --head update_versions --label "automated pr"
|
|
||||||
|
|
||||||
- name: Approve pull request
|
|
||||||
if: env.changed == 'true'
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
run: |
|
|
||||||
PR_NUMBER=$(gh pr list --head "update_versions" --json number --jq '.[].number')
|
|
||||||
if [ -n "$PR_NUMBER" ]; then
|
|
||||||
gh pr review $PR_NUMBER --approve
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Approve pull request and merge
|
|
||||||
if: env.changed == 'true'
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.PAT_AUTOMERGE }}
|
|
||||||
run: |
|
|
||||||
PR_NUMBER=$(gh pr list --head "update_versions" --json number --jq '.[].number')
|
|
||||||
if [ -n "$PR_NUMBER" ]; then
|
|
||||||
gh pr review $PR_NUMBER --approve
|
|
||||||
gh pr merge $PR_NUMBER --squash --admin
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Re-approve pull request after update
|
|
||||||
if: env.changed == 'true'
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
run: |
|
|
||||||
PR_NUMBER=$(gh pr list --head "update_versions" --json number --jq '.[].number')
|
|
||||||
if [ -n "$PR_NUMBER" ]; then
|
|
||||||
gh pr review $PR_NUMBER --approve
|
|
||||||
fi
|
|
||||||
Generated
-175
@@ -1,175 +0,0 @@
|
|||||||
name: Run Scripts on PVE Node for testing
|
|
||||||
permissions:
|
|
||||||
pull-requests: write
|
|
||||||
on:
|
|
||||||
pull_request_target:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
paths:
|
|
||||||
- "install/**.sh"
|
|
||||||
- "ct/**.sh"
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
run-install-script:
|
|
||||||
if: github.repository == 'community-scripts/ProxmoxVE'
|
|
||||||
runs-on: pvenode
|
|
||||||
steps:
|
|
||||||
- name: Checkout PR branch
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
ref: ${{ github.event.pull_request.head.ref }}
|
|
||||||
repository: ${{ github.event.pull_request.head.repo.full_name }}
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Add Git safe directory
|
|
||||||
run: |
|
|
||||||
git config --global --add safe.directory /__w/ProxmoxVE/ProxmoxVE
|
|
||||||
|
|
||||||
- name: Set up GH_TOKEN
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
run: |
|
|
||||||
echo "GH_TOKEN=${GH_TOKEN}" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Get Changed Files
|
|
||||||
run: |
|
|
||||||
CHANGED_FILES=$(gh pr diff ${{ github.event.pull_request.number }} --repo ${{ github.repository }} --name-only)
|
|
||||||
CHANGED_FILES=$(echo "$CHANGED_FILES" | tr '\n' ' ')
|
|
||||||
echo "Changed files: $CHANGED_FILES"
|
|
||||||
echo "SCRIPT=$CHANGED_FILES" >> $GITHUB_ENV
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Get scripts
|
|
||||||
id: check-install-script
|
|
||||||
run: |
|
|
||||||
ALL_FILES=()
|
|
||||||
ADDED_FILES=()
|
|
||||||
for FILE in ${{ env.SCRIPT }}; do
|
|
||||||
if [[ $FILE =~ ^install/.*-install\.sh$ ]] || [[ $FILE =~ ^ct/.*\.sh$ ]]; then
|
|
||||||
STRIPPED_NAME=$(basename "$FILE" | sed 's/-install//' | sed 's/\.sh$//')
|
|
||||||
if [[ ! " ${ADDED_FILES[@]} " =~ " $STRIPPED_NAME " ]]; then
|
|
||||||
ALL_FILES+=("$FILE")
|
|
||||||
ADDED_FILES+=("$STRIPPED_NAME") # Mark this base file as added (without the path)
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
ALL_FILES=$(echo "${ALL_FILES[@]}" | xargs)
|
|
||||||
echo "$ALL_FILES"
|
|
||||||
echo "ALL_FILES=$ALL_FILES" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Run scripts
|
|
||||||
id: run-install
|
|
||||||
continue-on-error: true
|
|
||||||
run: |
|
|
||||||
set +e
|
|
||||||
#run for each files in /ct
|
|
||||||
for FILE in ${{ env.ALL_FILES }}; do
|
|
||||||
STRIPPED_NAME=$(basename "$FILE" | sed 's/-install//' | sed 's/\.sh$//')
|
|
||||||
echo "Running Test for: $STRIPPED_NAME"
|
|
||||||
if grep -E -q 'read\s+-r\s+-p\s+".*"\s+\w+' "$FILE"; then
|
|
||||||
echo "The script contains an interactive prompt. Skipping execution."
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
if [[ $FILE =~ ^install/.*-install\.sh$ ]]; then
|
|
||||||
CT_SCRIPT="ct/$STRIPPED_NAME.sh"
|
|
||||||
if [[ ! -f $CT_SCRIPT ]]; then
|
|
||||||
echo "No CT script found for $STRIPPED_NAME"
|
|
||||||
ERROR_MSG="No CT script found for $FILE"
|
|
||||||
echo "$ERROR_MSG" > result_$STRIPPED_NAME.log
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
if grep -E -q 'read\s+-r\s+-p\s+".*"\s+\w+' "install/$STRIPPED_NAME-install.sh"; then
|
|
||||||
echo "The script contains an interactive prompt. Skipping execution."
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
echo "Found CT script for $STRIPPED_NAME"
|
|
||||||
chmod +x "$CT_SCRIPT"
|
|
||||||
RUNNING_FILE=$CT_SCRIPT
|
|
||||||
elif [[ $FILE =~ ^ct/.*\.sh$ ]]; then
|
|
||||||
INSTALL_SCRIPT="install/$STRIPPED_NAME-install.sh"
|
|
||||||
if [[ ! -f $INSTALL_SCRIPT ]]; then
|
|
||||||
echo "No install script found for $STRIPPED_NAME"
|
|
||||||
ERROR_MSG="No install script found for $FILE"
|
|
||||||
echo "$ERROR_MSG" > result_$STRIPPED_NAME.log
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
echo "Found install script for $STRIPPED_NAME"
|
|
||||||
chmod +x "$INSTALL_SCRIPT"
|
|
||||||
RUNNING_FILE=$FILE
|
|
||||||
if grep -E -q 'read\s+-r\s+-p\s+".*"\s+\w+' "ct/$STRIPPED_NAME.sh"; then
|
|
||||||
echo "The script contains an interactive prompt. Skipping execution."
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
git remote add community-scripts https://github.com/community-scripts/ProxmoxVE.git
|
|
||||||
git fetch community-scripts
|
|
||||||
rm -f .github/workflows/scripts/app-test/pr-build.func || true
|
|
||||||
rm -f .github/workflows/scripts/app-test/pr-install.func || true
|
|
||||||
rm -f .github/workflows/scripts/app-test/pr-alpine-install.func || true
|
|
||||||
rm -f .github/workflows/scripts/app-test/pr-create-lxc.sh || true
|
|
||||||
git checkout community-scripts/main -- .github/workflows/scripts/app-test/pr-build.func
|
|
||||||
git checkout community-scripts/main -- .github/workflows/scripts/app-test/pr-install.func
|
|
||||||
git checkout community-scripts/main -- .github/workflows/scripts/app-test/pr-alpine-install.func
|
|
||||||
git checkout community-scripts/main -- .github/workflows/scripts/app-test/pr-create-lxc.sh
|
|
||||||
chmod +x $RUNNING_FILE
|
|
||||||
chmod +x .github/workflows/scripts/app-test/pr-create-lxc.sh
|
|
||||||
chmod +x .github/workflows/scripts/app-test/pr-install.func
|
|
||||||
chmod +x .github/workflows/scripts/app-test/pr-alpine-install.func
|
|
||||||
chmod +x .github/workflows/scripts/app-test/pr-build.func
|
|
||||||
sed -i 's|source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)|source .github/workflows/scripts/app-test/pr-build.func|g' "$RUNNING_FILE"
|
|
||||||
echo "Executing $RUNNING_FILE"
|
|
||||||
ERROR_MSG=$(./$RUNNING_FILE 2>&1 > /dev/null)
|
|
||||||
echo "Finished running $FILE"
|
|
||||||
if [ -n "$ERROR_MSG" ]; then
|
|
||||||
echo "ERROR in $STRIPPED_NAME: $ERROR_MSG"
|
|
||||||
echo "$ERROR_MSG" > result_$STRIPPED_NAME.log
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
set -e # Restore exit-on-error
|
|
||||||
|
|
||||||
- name: Cleanup PVE Node
|
|
||||||
run: |
|
|
||||||
containers=$(pct list | tail -n +2 | awk '{print $0 " " $4}' | awk '{print $1}')
|
|
||||||
|
|
||||||
for container_id in $containers; do
|
|
||||||
status=$(pct status $container_id | awk '{print $2}')
|
|
||||||
if [[ $status == "running" ]]; then
|
|
||||||
pct stop $container_id
|
|
||||||
pct destroy $container_id
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
- name: Post error comments
|
|
||||||
run: |
|
|
||||||
ERROR="false"
|
|
||||||
SEARCH_LINE=".github/workflows/scripts/app-test/pr-build.func: line 255:"
|
|
||||||
|
|
||||||
# Get all existing comments on the PR
|
|
||||||
EXISTING_COMMENTS=$(gh pr view ${{ github.event.pull_request.number }} --repo ${{ github.repository }} --json comments --jq '.comments[].body')
|
|
||||||
|
|
||||||
for FILE in ${{ env.ALL_FILES }}; do
|
|
||||||
STRIPPED_NAME=$(basename "$FILE" | sed 's/-install//' | sed 's/\.sh$//')
|
|
||||||
if [[ ! -f result_$STRIPPED_NAME.log ]]; then
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
ERROR_MSG=$(cat result_$STRIPPED_NAME.log)
|
|
||||||
|
|
||||||
if [ -n "$ERROR_MSG" ]; then
|
|
||||||
CLEANED_ERROR_MSG=$(echo "$ERROR_MSG" | sed "s|$SEARCH_LINE.*||")
|
|
||||||
COMMENT_BODY=":warning: The script _**$FILE**_ failed with the following message: <br> <div><strong>${CLEANED_ERROR_MSG}</strong></div>"
|
|
||||||
|
|
||||||
# Check if the comment already exists
|
|
||||||
if echo "$EXISTING_COMMENTS" | grep -qF "$COMMENT_BODY"; then
|
|
||||||
echo "Skipping duplicate comment for $FILE"
|
|
||||||
else
|
|
||||||
echo "Posting error message for $FILE"
|
|
||||||
gh pr comment ${{ github.event.pull_request.number }} \
|
|
||||||
--repo ${{ github.repository }} \
|
|
||||||
--body "$COMMENT_BODY"
|
|
||||||
ERROR="true"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
echo "ERROR=$ERROR" >> $GITHUB_ENV
|
|
||||||
Generated
-243
@@ -1,243 +0,0 @@
|
|||||||
name: Script Format Check
|
|
||||||
permissions:
|
|
||||||
pull-requests: write
|
|
||||||
on:
|
|
||||||
pull_request_target:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
paths:
|
|
||||||
- "install/*.sh"
|
|
||||||
- "ct/*.sh"
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
run-install-script:
|
|
||||||
if: github.repository == 'community-scripts/ProxmoxVE'
|
|
||||||
runs-on: pvenode
|
|
||||||
steps:
|
|
||||||
- name: Checkout PR branch (supports forks)
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
ref: ${{ github.event.pull_request.head.ref }}
|
|
||||||
repository: ${{ github.event.pull_request.head.repo.full_name }}
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Add Git safe directory
|
|
||||||
run: |
|
|
||||||
git config --global --add safe.directory /__w/ProxmoxVE/ProxmoxVE
|
|
||||||
|
|
||||||
- name: Set up GH_TOKEN
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
run: |
|
|
||||||
echo "GH_TOKEN=${GH_TOKEN}" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Get Changed Files
|
|
||||||
run: |
|
|
||||||
CHANGED_FILES=$(gh pr diff ${{ github.event.pull_request.number }} --repo ${{ github.repository }} --name-only)
|
|
||||||
CHANGED_FILES=$(echo "$CHANGED_FILES" | tr '\n' ' ')
|
|
||||||
echo "Changed files: $CHANGED_FILES"
|
|
||||||
echo "SCRIPT=$CHANGED_FILES" >> $GITHUB_ENV
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Check scripts
|
|
||||||
id: run-install
|
|
||||||
continue-on-error: true
|
|
||||||
run: |
|
|
||||||
for FILE in ${{ env.SCRIPT }}; do
|
|
||||||
STRIPPED_NAME=$(basename "$FILE" | sed 's/-install//' | sed 's/\.sh$//')
|
|
||||||
echo "Running Test for: $STRIPPED_NAME"
|
|
||||||
FILE_STRIPPED="${FILE##*/}"
|
|
||||||
LOG_FILE="result_$FILE_STRIPPED.log"
|
|
||||||
|
|
||||||
if [[ $FILE =~ ^ct/.*\.sh$ ]]; then
|
|
||||||
|
|
||||||
FIRST_LINE=$(sed -n '1p' "$FILE")
|
|
||||||
[[ "$FIRST_LINE" != "#!/usr/bin/env bash" ]] && echo "Line 1 was $FIRST_LINE | Should be: #!/usr/bin/env bash" >> "$LOG_FILE"
|
|
||||||
SECOND_LINE=$(sed -n '2p' "$FILE")
|
|
||||||
[[ "$SECOND_LINE" != "source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)" ]] &&
|
|
||||||
echo "Line 2 was $SECOND_LINE | Should be: source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)" >> "$LOG_FILE"
|
|
||||||
THIRD_LINE=$(sed -n '3p' "$FILE")
|
|
||||||
if ! [[ "$THIRD_LINE" =~ ^#\ Copyright\ \(c\)\ [0-9]{4}-[0-9]{4}\ community-scripts\ ORG$ || "$THIRD_LINE" =~ ^Copyright\ \(c\)\ [0-9]{4}-[0-9]{4}\ tteck$ ]]; then
|
|
||||||
echo "Line 3 was $THIRD_LINE | Should be: # Copyright (c) 2021-2026 community-scripts ORG" >> "$LOG_FILE"
|
|
||||||
fi
|
|
||||||
|
|
||||||
EXPECTED_AUTHOR="# Author:"
|
|
||||||
EXPECTED_LICENSE="# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE"
|
|
||||||
EXPECTED_SOURCE="# Source:"
|
|
||||||
EXPECTED_EMPTY=""
|
|
||||||
|
|
||||||
for i in {4..7}; do
|
|
||||||
LINE=$(sed -n "${i}p" "$FILE")
|
|
||||||
|
|
||||||
case $i in
|
|
||||||
4)
|
|
||||||
[[ $LINE == $EXPECTED_AUTHOR* ]] || printf "Line %d was: '%s' | Should start with: '%s'\n" "$i" "$LINE" "$EXPECTED_AUTHOR" >> $LOG_FILE
|
|
||||||
;;
|
|
||||||
5)
|
|
||||||
[[ "$LINE" == "$EXPECTED_LICENSE" ]] || printf "Line %d was: '%s' | Should be: '%s'\n" "$i" "$LINE" "$EXPECTED_LICENSE" >> $LOG_FILE
|
|
||||||
;;
|
|
||||||
6)
|
|
||||||
[[ $LINE == $EXPECTED_SOURCE* ]] || printf "Line %d was: '%s' | Should start with: '%s'\n" "$i" "$LINE" "$EXPECTED_SOURCE" >> $LOG_FILE
|
|
||||||
;;
|
|
||||||
7)
|
|
||||||
[[ -z $LINE ]] || printf "Line %d was: '%s' | Should be empty\n" "$i" "$LINE" >> $LOG_FILE
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
|
|
||||||
EXPECTED_PREFIXES=(
|
|
||||||
"APP="
|
|
||||||
"var_tags="
|
|
||||||
"var_cpu=" # Must be a number
|
|
||||||
"var_ram=" # Must be a number
|
|
||||||
"var_disk=" # Must be a number
|
|
||||||
"var_os=" # Must be debian, alpine, or ubuntu
|
|
||||||
"var_version="
|
|
||||||
"var_unprivileged=" # Must be 0 or 1
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
for i in {8..15}; do
|
|
||||||
LINE=$(sed -n "${i}p" "$FILE")
|
|
||||||
INDEX=$((i - 8))
|
|
||||||
|
|
||||||
case $INDEX in
|
|
||||||
2|3|4) # var_cpu, var_ram, var_disk (must be numbers)
|
|
||||||
if [[ "$LINE" =~ ^${EXPECTED_PREFIXES[$INDEX]}([0-9]+)$ ]]; then
|
|
||||||
continue # Valid
|
|
||||||
else
|
|
||||||
echo "Line $i was '$LINE' | Should be: '${EXPECTED_PREFIXES[$INDEX]}<NUMBER>'" >> "$LOG_FILE"
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
5) # var_os (must be debian, alpine, or ubuntu)
|
|
||||||
if [[ "$LINE" =~ ^var_os=(debian|alpine|ubuntu)$ ]]; then
|
|
||||||
continue # Valid
|
|
||||||
else
|
|
||||||
echo "Line $i was '$LINE' | Should be: 'var_os=[debian|alpine|ubuntu]'" >> "$LOG_FILE"
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
7) # var_unprivileged (must be 0 or 1)
|
|
||||||
if [[ "$LINE" =~ ^var_unprivileged=[01]$ ]]; then
|
|
||||||
continue # Valid
|
|
||||||
else
|
|
||||||
echo "Line $i was '$LINE' | Should be: 'var_unprivileged=[0|1]'" >> "$LOG_FILE"
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
*) # Other lines (must start with expected prefix)
|
|
||||||
if [[ "$LINE" == ${EXPECTED_PREFIXES[$INDEX]}* ]]; then
|
|
||||||
continue # Valid
|
|
||||||
else
|
|
||||||
echo "Line $i was '$LINE' | Should start with '${EXPECTED_PREFIXES[$INDEX]}'" >> "$LOG_FILE"
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
for i in {16..20}; do
|
|
||||||
LINE=$(sed -n "${i}p" "$FILE")
|
|
||||||
EXPECTED=(
|
|
||||||
"header_info \"$APP\""
|
|
||||||
"variables"
|
|
||||||
"color"
|
|
||||||
"catch_errors"
|
|
||||||
"function update_script() {"
|
|
||||||
)
|
|
||||||
[[ "$LINE" != "${EXPECTED[$((i-16))]}" ]] && echo "Line $i was $LINE | Should be: ${EXPECTED[$((i-16))]}" >> "$LOG_FILE"
|
|
||||||
done
|
|
||||||
cat "$LOG_FILE"
|
|
||||||
elif [[ $FILE =~ ^install/.*-install\.sh$ ]]; then
|
|
||||||
|
|
||||||
FIRST_LINE=$(sed -n '1p' "$FILE")
|
|
||||||
[[ "$FIRST_LINE" != "#!/usr/bin/env bash" ]] && echo "Line 1 was $FIRST_LINE | Should be: #!/usr/bin/env bash" >> "$LOG_FILE"
|
|
||||||
|
|
||||||
SECOND_LINE=$(sed -n '2p' "$FILE")
|
|
||||||
[[ -n "$SECOND_LINE" ]] && echo "Line 2 should be empty" >> "$LOG_FILE"
|
|
||||||
|
|
||||||
THIRD_LINE=$(sed -n '3p' "$FILE")
|
|
||||||
if ! [[ "$THIRD_LINE" =~ ^#\ Copyright\ \(c\)\ [0-9]{4}-[0-9]{4}\ community-scripts\ ORG$ || "$THIRD_LINE" =~ ^Copyright\ \(c\)\ [0-9]{4}-[0-9]{4}\ tteck$ ]]; then
|
|
||||||
echo "Line 3 was $THIRD_LINE | Should be: # Copyright (c) 2021-2026 community-scripts ORG" >> "$LOG_FILE"
|
|
||||||
fi
|
|
||||||
|
|
||||||
EXPECTED_AUTHOR="# Author:"
|
|
||||||
EXPECTED_LICENSE="# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE"
|
|
||||||
EXPECTED_SOURCE="# Source:"
|
|
||||||
EXPECTED_EMPTY=""
|
|
||||||
|
|
||||||
for i in {4..7}; do
|
|
||||||
LINE=$(sed -n "${i}p" "$FILE")
|
|
||||||
|
|
||||||
case $i in
|
|
||||||
4)
|
|
||||||
[[ $LINE == $EXPECTED_AUTHOR* ]] || printf "Line %d was: '%s' | Should start with: '%s'\n" "$i" "$LINE" "$EXPECTED_AUTHOR" >> $LOG_FILE
|
|
||||||
;;
|
|
||||||
5)
|
|
||||||
[[ "$LINE" == "$EXPECTED_LICENSE" ]] || printf "Line %d was: '%s' | Should be: '%s'\n" "$i" "$LINE" "$EXPECTED_LICENSE" >> $LOG_FILE
|
|
||||||
;;
|
|
||||||
6)
|
|
||||||
[[ $LINE == $EXPECTED_SOURCE* ]] || printf "Line %d was: '%s' | Should start with: '%s'\n" "$i" "$LINE" "$EXPECTED_SOURCE" >> $LOG_FILE
|
|
||||||
;;
|
|
||||||
7)
|
|
||||||
[[ -z $LINE ]] || printf "Line %d was: '%s' | Should be empty\n" "$i" "$LINE" >> $LOG_FILE
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
[[ "$(sed -n '8p' "$FILE")" != 'source /dev/stdin <<< "$FUNCTIONS_FILE_PATH"' ]] && echo 'Line 8 should be: source /dev/stdin <<< "$FUNCTIONS_FILE_PATH"' >> "$LOG_FILE"
|
|
||||||
|
|
||||||
for i in {9..14}; do
|
|
||||||
LINE=$(sed -n "${i}p" "$FILE")
|
|
||||||
EXPECTED=(
|
|
||||||
"color"
|
|
||||||
"verb_ip6"
|
|
||||||
"catch_errors"
|
|
||||||
"setting_up_container"
|
|
||||||
"network_check"
|
|
||||||
"update_os"
|
|
||||||
)
|
|
||||||
[[ "$LINE" != "${EXPECTED[$((i-9))]}" ]] && echo "Line $i was $LINE | Should be: ${EXPECTED[$((i-9))]}" >> "$LOG_FILE"
|
|
||||||
done
|
|
||||||
|
|
||||||
[[ -n "$(sed -n '15p' "$FILE")" ]] && echo "Line 15 should be empty" >> "$LOG_FILE"
|
|
||||||
[[ "$(sed -n '16p' "$FILE")" != 'msg_info "Installing Dependencies"' ]] && echo 'Line 16 should be: msg_info "Installing Dependencies"' >> "$LOG_FILE"
|
|
||||||
|
|
||||||
LAST_3_LINES=$(tail -n 3 "$FILE")
|
|
||||||
[[ "$LAST_3_LINES" != *"$STD apt-get -y autoremove"* ]] && echo 'Third to last line should be: $STD apt-get -y autoremove' >> "$LOG_FILE"
|
|
||||||
[[ "$LAST_3_LINES" != *"$STD apt-get -y autoclean"* ]] && echo 'Second to last line should be: $STD apt-get -y clean' >> "$LOG_FILE"
|
|
||||||
[[ "$LAST_3_LINES" != *'msg_ok "Cleaned"'* ]] && echo 'Last line should be: msg_ok "Cleaned"' >> "$LOG_FILE"
|
|
||||||
cat "$LOG_FILE"
|
|
||||||
fi
|
|
||||||
|
|
||||||
done
|
|
||||||
|
|
||||||
- name: Post error comments
|
|
||||||
run: |
|
|
||||||
ERROR="false"
|
|
||||||
for FILE in ${{ env.SCRIPT }}; do
|
|
||||||
FILE_STRIPPED="${FILE##*/}"
|
|
||||||
LOG_FILE="result_$FILE_STRIPPED.log"
|
|
||||||
echo $LOG_FILE
|
|
||||||
if [[ ! -f $LOG_FILE ]]; then
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
ERROR_MSG=$(cat $LOG_FILE)
|
|
||||||
|
|
||||||
if [ -n "$ERROR_MSG" ]; then
|
|
||||||
echo "Posting error message for $FILE"
|
|
||||||
echo ${ERROR_MSG}
|
|
||||||
gh pr comment ${{ github.event.pull_request.number }} \
|
|
||||||
--repo ${{ github.repository }} \
|
|
||||||
--body ":warning: The script _**$FILE**_ has the following formatting errors: <br> <div><strong>${ERROR_MSG}</strong></div>"
|
|
||||||
|
|
||||||
|
|
||||||
ERROR="true"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
echo "ERROR=$ERROR" >> $GITHUB_ENV
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Fail if error
|
|
||||||
if: ${{ env.ERROR == 'true' }}
|
|
||||||
run: exit 1
|
|
||||||
-158
@@ -1,158 +0,0 @@
|
|||||||
name: Validate filenames
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request_target:
|
|
||||||
paths:
|
|
||||||
- "ct/*.sh"
|
|
||||||
- "install/*.sh"
|
|
||||||
- "frontend/public/json/*.json"
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
check-files:
|
|
||||||
if: github.repository == 'community-scripts/ProxmoxVE'
|
|
||||||
name: Check changed files
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
pull-requests: write
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Get pull request information
|
|
||||||
if: github.event_name == 'pull_request_target'
|
|
||||||
uses: actions/github-script@v7
|
|
||||||
id: pr
|
|
||||||
with:
|
|
||||||
script: |
|
|
||||||
const { data: pullRequest } = await github.rest.pulls.get({
|
|
||||||
...context.repo,
|
|
||||||
pull_number: context.payload.pull_request.number,
|
|
||||||
});
|
|
||||||
return pullRequest;
|
|
||||||
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0 # Ensure the full history is fetched for accurate diffing
|
|
||||||
ref: ${{ github.event_name == 'pull_request_target' && fromJSON(steps.pr.outputs.result).merge_commit_sha || '' }}
|
|
||||||
|
|
||||||
- name: Get changed files
|
|
||||||
id: changed-files
|
|
||||||
run: |
|
|
||||||
if ${{ github.event_name == 'pull_request_target' }}; then
|
|
||||||
echo "files=$(git diff --name-only ${{ github.event.pull_request.base.sha }} ${{ steps.pr.outputs.result && fromJSON(steps.pr.outputs.result).merge_commit_sha }} | xargs)" >> $GITHUB_OUTPUT
|
|
||||||
else
|
|
||||||
echo "files=$(git diff --name-only ${{ github.event.before }} ${{ github.event.after }} | xargs)" >> $GITHUB_OUTPUT
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: "Validate filenames in ct and install directory"
|
|
||||||
if: always() && steps.changed-files.outputs.files != ''
|
|
||||||
id: check-scripts
|
|
||||||
run: |
|
|
||||||
CHANGED_FILES=$(printf "%s\n" ${{ steps.changed-files.outputs.files }} | { grep -E '^(ct|install)/.*\.sh$' || true; })
|
|
||||||
|
|
||||||
NON_COMPLIANT_FILES=""
|
|
||||||
for FILE in $CHANGED_FILES; do
|
|
||||||
BASENAME=$(echo "$(basename "${FILE%.*}")")
|
|
||||||
if [[ ! "$BASENAME" =~ ^[a-z0-9-]+$ ]]; then
|
|
||||||
NON_COMPLIANT_FILES="$NON_COMPLIANT_FILES $FILE"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ -n "$NON_COMPLIANT_FILES" ]; then
|
|
||||||
echo "files=$NON_COMPLIANT_FILES" >> $GITHUB_OUTPUT
|
|
||||||
echo "Non-compliant filenames found, change to lowercase:"
|
|
||||||
for FILE in $NON_COMPLIANT_FILES; do
|
|
||||||
echo "$FILE"
|
|
||||||
done
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: "Validate filenames in json directory."
|
|
||||||
if: always() && steps.changed-files.outputs.files != ''
|
|
||||||
id: check-json
|
|
||||||
run: |
|
|
||||||
CHANGED_FILES=$(printf "%s\n" ${{ steps.changed-files.outputs.files }} | { grep -E '^json/.*\.json$' || true; })
|
|
||||||
|
|
||||||
NON_COMPLIANT_FILES=""
|
|
||||||
for FILE in $CHANGED_FILES; do
|
|
||||||
BASENAME=$(echo "$(basename "${FILE%.*}")")
|
|
||||||
if [[ ! "$BASENAME" =~ ^[a-z0-9-]+$ ]]; then
|
|
||||||
NON_COMPLIANT_FILES="$NON_COMPLIANT_FILES $FILE"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ -n "$NON_COMPLIANT_FILES" ]; then
|
|
||||||
echo "files=$NON_COMPLIANT_FILES" >> $GITHUB_OUTPUT
|
|
||||||
echo "Non-compliant filenames found, change to lowercase:"
|
|
||||||
for FILE in $NON_COMPLIANT_FILES; do
|
|
||||||
echo "$FILE"
|
|
||||||
done
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Post results and comment
|
|
||||||
if: always() && steps.check-scripts.outputs.files != '' && steps.check-json.outputs.files != '' && github.event_name == 'pull_request_target'
|
|
||||||
uses: actions/github-script@v7
|
|
||||||
with:
|
|
||||||
script: |
|
|
||||||
const result = "${{ job.status }}" === "success" ? "success" : "failure";
|
|
||||||
const nonCompliantFiles = {
|
|
||||||
script: "${{ steps.check-scripts.outputs.files }}",
|
|
||||||
JSON: "${{ steps.check-json.outputs.files }}",
|
|
||||||
};
|
|
||||||
|
|
||||||
const issueNumber = context.payload.pull_request
|
|
||||||
? context.payload.pull_request.number
|
|
||||||
: null;
|
|
||||||
const commentIdentifier = "validate-filenames";
|
|
||||||
let newCommentBody = `<!-- ${commentIdentifier}-start -->\n### Filename validation\n\n`;
|
|
||||||
|
|
||||||
if (result === "failure") {
|
|
||||||
newCommentBody += ":x: We found issues in the following changed files:\n\n";
|
|
||||||
for (const [check, files] of Object.entries(nonCompliantFiles)) {
|
|
||||||
if (files) {
|
|
||||||
newCommentBody += `**${check.charAt(0).toUpperCase() + check.slice(1)} filename invalid:**\n${files
|
|
||||||
.trim()
|
|
||||||
.split(" ")
|
|
||||||
.map((file) => `- ${file}`)
|
|
||||||
.join("\n")}\n\n`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
newCommentBody +=
|
|
||||||
"Please change the filenames to lowercase and use only alphanumeric characters and dashes.\n";
|
|
||||||
} else {
|
|
||||||
newCommentBody += `:rocket: All files passed filename validation!\n`;
|
|
||||||
}
|
|
||||||
|
|
||||||
newCommentBody += `\n\n<!-- ${commentIdentifier}-end -->`;
|
|
||||||
|
|
||||||
if (issueNumber) {
|
|
||||||
const { data: comments } = await github.rest.issues.listComments({
|
|
||||||
...context.repo,
|
|
||||||
issue_number: issueNumber,
|
|
||||||
});
|
|
||||||
|
|
||||||
const existingComment = comments.find(
|
|
||||||
(comment) => comment.user.login === "github-actions[bot]",
|
|
||||||
);
|
|
||||||
|
|
||||||
if (existingComment) {
|
|
||||||
if (existingComment.body.includes(commentIdentifier)) {
|
|
||||||
const re = new RegExp(String.raw`<!-- ${commentIdentifier}-start -->[\s\S]*?<!-- ${commentIdentifier}-end -->`, "");
|
|
||||||
newCommentBody = existingComment.body.replace(re, newCommentBody);
|
|
||||||
} else {
|
|
||||||
newCommentBody = existingComment.body + '\n\n---\n\n' + newCommentBody;
|
|
||||||
}
|
|
||||||
|
|
||||||
await github.rest.issues.updateComment({
|
|
||||||
...context.repo,
|
|
||||||
comment_id: existingComment.id,
|
|
||||||
body: newCommentBody,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
await github.rest.issues.createComment({
|
|
||||||
...context.repo,
|
|
||||||
issue_number: issueNumber,
|
|
||||||
body: newCommentBody,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+457
@@ -0,0 +1,457 @@
|
|||||||
|
name: Check Node.js Version Drift
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
schedule:
|
||||||
|
# Runs weekly on Monday at 06:00 UTC
|
||||||
|
- cron: "0 6 * * 1"
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
issues: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
check-node-versions:
|
||||||
|
if: github.repository == 'community-scripts/ProxmoxVE'
|
||||||
|
runs-on: coolify-runner
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout Repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
ref: main
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
sudo apt-get update -qq
|
||||||
|
sudo apt-get install -y -qq jq curl > /dev/null 2>&1
|
||||||
|
|
||||||
|
- name: Check upstream Node.js versions
|
||||||
|
id: check
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
echo "================================================"
|
||||||
|
echo " Checking Node.js version drift in install scripts"
|
||||||
|
echo "================================================"
|
||||||
|
|
||||||
|
# Alpine version -> Node major cache (populated on demand)
|
||||||
|
declare -A ALPINE_NODE_CACHE
|
||||||
|
|
||||||
|
# Resolve Node.js major version from Alpine package registry
|
||||||
|
# Usage: resolve_alpine_node "3.21" => sets REPLY to major version (e.g. "22")
|
||||||
|
resolve_alpine_node() {
|
||||||
|
local alpine_ver="$1"
|
||||||
|
if [[ -n "${ALPINE_NODE_CACHE[$alpine_ver]+x}" ]]; then
|
||||||
|
REPLY="${ALPINE_NODE_CACHE[$alpine_ver]}"
|
||||||
|
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 "")
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
local major=""
|
||||||
|
if [[ -n "$full_ver" ]]; then
|
||||||
|
major="${full_ver%%.*}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
ALPINE_NODE_CACHE[$alpine_ver]="$major"
|
||||||
|
REPLY="$major"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Extract Node major from a Dockerfile content
|
||||||
|
# Sets: DF_NODE_MAJOR, DF_SOURCE (description of where we found it)
|
||||||
|
extract_dockerfile_node() {
|
||||||
|
local content="$1"
|
||||||
|
DF_NODE_MAJOR=""
|
||||||
|
DF_SOURCE=""
|
||||||
|
|
||||||
|
# 1) FROM node:XX (e.g. node:24-alpine, node:22.9.0-bookworm-slim, node:20)
|
||||||
|
local node_from
|
||||||
|
node_from=$(echo "$content" | grep -oP '(?i)FROM\s+(--platform=[^\s]+\s+)?node:\K[0-9]+' | head -1 || echo "")
|
||||||
|
if [[ -n "$node_from" ]]; then
|
||||||
|
DF_NODE_MAJOR="$node_from"
|
||||||
|
DF_SOURCE="FROM node:${node_from}"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 2) nodesource/setup_XX.x
|
||||||
|
local nodesource
|
||||||
|
nodesource=$(echo "$content" | grep -oP 'nodesource/setup_\K[0-9]+' | head -1 || echo "")
|
||||||
|
if [[ -n "$nodesource" ]]; then
|
||||||
|
DF_NODE_MAJOR="$nodesource"
|
||||||
|
DF_SOURCE="nodesource/setup_${nodesource}.x"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 3) FROM alpine:X.Y — resolve via Alpine packages
|
||||||
|
local alpine_ver
|
||||||
|
alpine_ver=$(echo "$content" | grep -oP '(?i)FROM\s+(--platform=[^\s]+\s+)?alpine:\K[0-9]+\.[0-9]+' | head -1 || echo "")
|
||||||
|
if [[ -n "$alpine_ver" ]]; then
|
||||||
|
resolve_alpine_node "$alpine_ver"
|
||||||
|
if [[ -n "$REPLY" ]]; then
|
||||||
|
DF_NODE_MAJOR="$REPLY"
|
||||||
|
DF_SOURCE="alpine:${alpine_ver} (pkg: nodejs ${DF_NODE_MAJOR})"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Extract Node major from engines.node in package.json
|
||||||
|
# Sets: ENGINES_NODE_RAW (raw string), ENGINES_MIN_MAJOR, ENGINES_IS_MINIMUM
|
||||||
|
extract_engines_node() {
|
||||||
|
local content="$1"
|
||||||
|
ENGINES_NODE_RAW=""
|
||||||
|
ENGINES_MIN_MAJOR=""
|
||||||
|
ENGINES_IS_MINIMUM="false"
|
||||||
|
|
||||||
|
ENGINES_NODE_RAW=$(echo "$content" | jq -r '.engines.node // empty' 2>/dev/null || echo "")
|
||||||
|
if [[ -z "$ENGINES_NODE_RAW" ]]; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Detect if constraint is a minimum (>=, ^) vs exact pinning
|
||||||
|
if [[ "$ENGINES_NODE_RAW" =~ ^(\>=|\^|\~) ]]; then
|
||||||
|
ENGINES_IS_MINIMUM="true"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Extract the first number (major) from the constraint
|
||||||
|
# Handles: ">=24.13.1", "^22", ">=18.0.0", ">=18.15.0 <19 || ^20", etc.
|
||||||
|
ENGINES_MIN_MAJOR=$(echo "$ENGINES_NODE_RAW" | grep -oP '\d+' | head -1 || echo "")
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if our_version satisfies an engines.node constraint
|
||||||
|
# Returns 0 if satisfied, 1 if not
|
||||||
|
# Usage: version_satisfies_engines "22" ">=18.0.0" "true"
|
||||||
|
version_satisfies_engines() {
|
||||||
|
local our="$1"
|
||||||
|
local min_major="$2"
|
||||||
|
local is_minimum="$3"
|
||||||
|
|
||||||
|
if [[ -z "$min_major" || -z "$our" ]]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$is_minimum" == "true" ]]; then
|
||||||
|
# >= or ^ constraint: our version must be >= min_major
|
||||||
|
if [[ "$our" -ge "$min_major" ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Search for files in subdirectories via GitHub API tree
|
||||||
|
# Usage: find_repo_file "owner/repo" "branch" "filename" => sets REPLY to raw URL or empty
|
||||||
|
find_repo_file() {
|
||||||
|
local repo="$1"
|
||||||
|
local branch="$2"
|
||||||
|
local filename="$3"
|
||||||
|
REPLY=""
|
||||||
|
|
||||||
|
# Try root first (fast)
|
||||||
|
local root_url="https://raw.githubusercontent.com/${repo}/${branch}/${filename}"
|
||||||
|
if curl -sfI "$root_url" >/dev/null 2>&1; then
|
||||||
|
REPLY="$root_url"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Search via GitHub API tree (recursive)
|
||||||
|
local tree_url="https://api.github.com/repos/${repo}/git/trees/${branch}?recursive=1"
|
||||||
|
local tree_json
|
||||||
|
tree_json=$(curl -sf -H "Authorization: token $GH_TOKEN" "$tree_url" 2>/dev/null || echo "")
|
||||||
|
if [[ -z "$tree_json" ]]; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Find first matching path (prefer shorter/root-level paths)
|
||||||
|
local match_path
|
||||||
|
match_path=$(echo "$tree_json" | jq -r --arg fn "$filename" \
|
||||||
|
'.tree[]? | select(.path | endswith("/" + $fn) or . == $fn) | .path' 2>/dev/null \
|
||||||
|
| sort | head -1 || echo "")
|
||||||
|
|
||||||
|
if [[ -n "$match_path" ]]; then
|
||||||
|
REPLY="https://raw.githubusercontent.com/${repo}/${branch}/${match_path}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Extract Node major from .nvmrc or .node-version
|
||||||
|
# Sets: NVMRC_NODE_MAJOR
|
||||||
|
extract_nvmrc_node() {
|
||||||
|
local content="$1"
|
||||||
|
NVMRC_NODE_MAJOR=""
|
||||||
|
# .nvmrc/.node-version typically has: "v22.9.0", "22", "lts/iron", etc.
|
||||||
|
local ver
|
||||||
|
ver=$(echo "$content" | tr -d '[:space:]' | grep -oP '^v?\K[0-9]+' | head -1 || echo "")
|
||||||
|
NVMRC_NODE_MAJOR="$ver"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Collect results
|
||||||
|
declare -a issue_scripts=()
|
||||||
|
declare -a report_lines=()
|
||||||
|
total=0
|
||||||
|
checked=0
|
||||||
|
drift_count=0
|
||||||
|
|
||||||
|
for script in install/*-install.sh; do
|
||||||
|
[[ ! -f "$script" ]] && continue
|
||||||
|
if ! grep -q 'setup_nodejs' "$script"; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
total=$((total + 1))
|
||||||
|
slug=$(basename "$script" | sed 's/-install\.sh$//')
|
||||||
|
|
||||||
|
# Extract Source URL (GitHub only) from the "# Source:" line
|
||||||
|
# Supports both:
|
||||||
|
# # Source: https://github.com/owner/repo
|
||||||
|
# # Source: https://example.com | Github: https://github.com/owner/repo
|
||||||
|
# NOTE: Must filter for "# Source:" line first to avoid matching the License URL
|
||||||
|
source_url=$(head -20 "$script" | grep -i '# Source:' | grep -oP 'https://github\.com/[^\s|]+' | head -1 || echo "")
|
||||||
|
if [[ -z "$source_url" ]]; then
|
||||||
|
report_lines+=("| \`$slug\` | — | — | — | — | ⏭️ No GitHub source |")
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
repo=$(echo "$source_url" | sed -E 's|https://github\.com/||; s|/$||; s|\.git$||')
|
||||||
|
if [[ -z "$repo" || "$repo" != */* ]]; then
|
||||||
|
report_lines+=("| \`$slug\` | — | — | — | — | ⏭️ Invalid repo |")
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
checked=$((checked + 1))
|
||||||
|
|
||||||
|
# Extract our NODE_VERSION
|
||||||
|
our_version=$(grep -oP 'NODE_VERSION="(\d+)"' "$script" | head -1 | grep -oP '\d+' || echo "")
|
||||||
|
if [[ -z "$our_version" ]]; then
|
||||||
|
if grep -q 'NODE_VERSION=\$(' "$script"; then
|
||||||
|
our_version="dynamic"
|
||||||
|
else
|
||||||
|
our_version="unset"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Determine default branch via GitHub API (fast, single call)
|
||||||
|
detected_branch=""
|
||||||
|
api_default=$(curl -sf -H "Authorization: token $GH_TOKEN" \
|
||||||
|
"https://api.github.com/repos/${repo}" 2>/dev/null \
|
||||||
|
| jq -r '.default_branch // empty' 2>/dev/null || echo "")
|
||||||
|
if [[ -n "$api_default" ]]; then
|
||||||
|
detected_branch="$api_default"
|
||||||
|
else
|
||||||
|
detected_branch="main"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Fetch upstream Dockerfile (root + subdirectories)
|
||||||
|
df_content=""
|
||||||
|
find_repo_file "$repo" "$detected_branch" "Dockerfile"
|
||||||
|
if [[ -n "$REPLY" ]]; then
|
||||||
|
df_content=$(curl -sf "$REPLY" 2>/dev/null || echo "")
|
||||||
|
fi
|
||||||
|
|
||||||
|
DF_NODE_MAJOR=""
|
||||||
|
DF_SOURCE=""
|
||||||
|
if [[ -n "$df_content" ]]; then
|
||||||
|
extract_dockerfile_node "$df_content"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Fetch upstream package.json (root + subdirectories)
|
||||||
|
pkg_content=""
|
||||||
|
find_repo_file "$repo" "$detected_branch" "package.json"
|
||||||
|
if [[ -n "$REPLY" ]]; then
|
||||||
|
pkg_content=$(curl -sf "$REPLY" 2>/dev/null || echo "")
|
||||||
|
fi
|
||||||
|
|
||||||
|
ENGINES_NODE_RAW=""
|
||||||
|
ENGINES_MIN_MAJOR=""
|
||||||
|
ENGINES_IS_MINIMUM="false"
|
||||||
|
if [[ -n "$pkg_content" ]]; then
|
||||||
|
extract_engines_node "$pkg_content"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Fallback: check .nvmrc or .node-version
|
||||||
|
NVMRC_NODE_MAJOR=""
|
||||||
|
if [[ -z "$DF_NODE_MAJOR" && -z "$ENGINES_MIN_MAJOR" ]]; then
|
||||||
|
for nvmfile in .nvmrc .node-version; do
|
||||||
|
find_repo_file "$repo" "$detected_branch" "$nvmfile"
|
||||||
|
if [[ -n "$REPLY" ]]; then
|
||||||
|
nvmrc_content=$(curl -sf "$REPLY" 2>/dev/null || echo "")
|
||||||
|
if [[ -n "$nvmrc_content" ]]; then
|
||||||
|
extract_nvmrc_node "$nvmrc_content"
|
||||||
|
[[ -n "$NVMRC_NODE_MAJOR" ]] && break
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Determine upstream recommended major version
|
||||||
|
upstream_major=""
|
||||||
|
upstream_hint=""
|
||||||
|
|
||||||
|
if [[ -n "$DF_NODE_MAJOR" ]]; then
|
||||||
|
upstream_major="$DF_NODE_MAJOR"
|
||||||
|
upstream_hint="$DF_SOURCE"
|
||||||
|
elif [[ -n "$ENGINES_MIN_MAJOR" ]]; then
|
||||||
|
upstream_major="$ENGINES_MIN_MAJOR"
|
||||||
|
upstream_hint="engines: $ENGINES_NODE_RAW"
|
||||||
|
elif [[ -n "$NVMRC_NODE_MAJOR" ]]; then
|
||||||
|
upstream_major="$NVMRC_NODE_MAJOR"
|
||||||
|
upstream_hint=".nvmrc/.node-version"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Build display values
|
||||||
|
engines_display="${ENGINES_NODE_RAW:-—}"
|
||||||
|
dockerfile_display="${DF_SOURCE:-—}"
|
||||||
|
|
||||||
|
# Compare
|
||||||
|
status="✅"
|
||||||
|
if [[ "$our_version" == "dynamic" ]]; then
|
||||||
|
status="🔄 Dynamic"
|
||||||
|
elif [[ "$our_version" == "unset" ]]; then
|
||||||
|
if [[ -n "$upstream_major" ]]; then
|
||||||
|
status="⚠️ NODE_VERSION not set (upstream=$upstream_major via $upstream_hint)"
|
||||||
|
else
|
||||||
|
status="⚠️ NODE_VERSION not set (no upstream info found)"
|
||||||
|
fi
|
||||||
|
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)"
|
||||||
|
else
|
||||||
|
status="🔸 Drift → upstream=$upstream_major ($upstream_hint)"
|
||||||
|
issue_scripts+=("$slug|$our_version|$upstream_major|$upstream_hint|$repo")
|
||||||
|
drift_count=$((drift_count + 1))
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
report_lines+=("| \`$slug\` | $our_version | $engines_display | $dockerfile_display | [$repo](https://github.com/$repo) | $status |")
|
||||||
|
|
||||||
|
# Rate-limit to avoid GitHub secondary rate limits
|
||||||
|
sleep 0.3
|
||||||
|
|
||||||
|
done
|
||||||
|
|
||||||
|
# Print summary
|
||||||
|
echo ""
|
||||||
|
echo "========================================="
|
||||||
|
echo " Total scripts with setup_nodejs: $total"
|
||||||
|
echo " Checked (with GitHub source): $checked"
|
||||||
|
echo " Version drift detected: $drift_count"
|
||||||
|
echo "========================================="
|
||||||
|
|
||||||
|
# Export
|
||||||
|
{
|
||||||
|
echo "drift_count=$drift_count"
|
||||||
|
echo "total=$total"
|
||||||
|
echo "checked=$checked"
|
||||||
|
} >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
# Save issue details for next step
|
||||||
|
printf '%s\n' "${issue_scripts[@]}" > /tmp/drift_scripts.txt 2>/dev/null || touch /tmp/drift_scripts.txt
|
||||||
|
|
||||||
|
# Save full report
|
||||||
|
{
|
||||||
|
echo "## Node.js Version Drift Report"
|
||||||
|
echo ""
|
||||||
|
echo "**Generated:** $(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||||
|
echo "**Scripts checked:** $total | **With GitHub source:** $checked | **Drift detected:** $drift_count"
|
||||||
|
echo ""
|
||||||
|
echo "| Script | Our Version | engines.node | Dockerfile | Upstream Repo | Status |"
|
||||||
|
echo "|--------|-------------|-------------|------------|---------------|--------|"
|
||||||
|
printf '%s\n' "${report_lines[@]}" | sort
|
||||||
|
} > /tmp/drift_report.md
|
||||||
|
|
||||||
|
cat /tmp/drift_report.md
|
||||||
|
|
||||||
|
- name: Create or update summary issue
|
||||||
|
if: steps.check.outputs.drift_count != '0'
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
TITLE="[Automated] Node.js Version Drift Report"
|
||||||
|
DATE=$(date -u +%Y-%m-%d)
|
||||||
|
DRIFT_COUNT="${{ steps.check.outputs.drift_count }}"
|
||||||
|
TOTAL="${{ steps.check.outputs.total }}"
|
||||||
|
CHECKED="${{ steps.check.outputs.checked }}"
|
||||||
|
|
||||||
|
# Build checklist from drift data
|
||||||
|
CHECKLIST=""
|
||||||
|
while IFS='|' read -r slug our_version upstream_major upstream_hint repo; do
|
||||||
|
[[ -z "$slug" ]] && continue
|
||||||
|
CHECKLIST+="- [ ] **\`${slug}\`** — ours: \`${our_version}\` → upstream: \`${upstream_major}\` (${upstream_hint}) — [repo](https://github.com/${repo})"$'\n'
|
||||||
|
done < /tmp/drift_scripts.txt
|
||||||
|
|
||||||
|
# Build full report table
|
||||||
|
REPORT=$(cat /tmp/drift_report.md)
|
||||||
|
|
||||||
|
BODY=$(cat <<ISSUE_EOF
|
||||||
|
## Node.js Version Drift Report — ${DATE}
|
||||||
|
|
||||||
|
**${DRIFT_COUNT}** script(s) with version drift detected (out of ${CHECKED} checked / ${TOTAL} total).
|
||||||
|
|
||||||
|
### Scripts requiring investigation
|
||||||
|
|
||||||
|
${CHECKLIST}
|
||||||
|
|
||||||
|
### How to resolve
|
||||||
|
|
||||||
|
1. Check upstream Dockerfile / package.json to confirm the required Node.js version
|
||||||
|
2. Test the script with the new Node version
|
||||||
|
3. Update \`NODE_VERSION\` in \`install/<slug>-install.sh\`
|
||||||
|
4. Update \`NODE_VERSION\` in \`ct/<slug>.sh\` (update section) if applicable
|
||||||
|
5. Check off the item above once done
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Full report</summary>
|
||||||
|
|
||||||
|
${REPORT}
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
---
|
||||||
|
*This issue is automatically created/updated weekly by the Node.js version drift check workflow.*
|
||||||
|
*Last updated: ${DATE}*
|
||||||
|
ISSUE_EOF
|
||||||
|
)
|
||||||
|
|
||||||
|
# Check if a matching open issue already exists
|
||||||
|
EXISTING=$(gh issue list --state open --label "automated,dependencies" --search "\"[Automated] Node.js Version Drift Report\"" --json number --jq '.[0].number // empty' 2>/dev/null || echo "")
|
||||||
|
|
||||||
|
if [[ -n "$EXISTING" ]]; then
|
||||||
|
gh issue edit "$EXISTING" --body "$BODY"
|
||||||
|
echo "Updated existing issue #$EXISTING"
|
||||||
|
else
|
||||||
|
gh issue create \
|
||||||
|
--title "$TITLE" \
|
||||||
|
--body "$BODY" \
|
||||||
|
--label "automated,dependencies"
|
||||||
|
echo "Created new summary issue"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Close issue if no drift
|
||||||
|
if: steps.check.outputs.drift_count == '0'
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
EXISTING=$(gh issue list --state open --label "automated,dependencies" --search "\"[Automated] Node.js Version Drift Report\"" --json number --jq '.[0].number // empty' 2>/dev/null || echo "")
|
||||||
|
if [[ -n "$EXISTING" ]]; then
|
||||||
|
gh issue close "$EXISTING" --comment "All Node.js versions are in sync with upstream. Closing automatically."
|
||||||
|
echo "Closed issue #$EXISTING"
|
||||||
|
fi
|
||||||
Generated
-164
@@ -1,164 +0,0 @@
|
|||||||
name: Close Discussion on PR Merge
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
discussions: write
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
close-discussion:
|
|
||||||
if: github.repository == 'community-scripts/ProxmoxVE'
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout Repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Set Up Node.js
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: "20"
|
|
||||||
|
|
||||||
- name: Install Dependencies
|
|
||||||
run: npm install zx @octokit/graphql
|
|
||||||
|
|
||||||
- name: Close Discussion
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
GITHUB_SHA: ${{ github.sha }}
|
|
||||||
GITHUB_REPOSITORY: ${{ github.repository }}
|
|
||||||
run: |
|
|
||||||
npx zx << 'EOF'
|
|
||||||
import { graphql } from "@octokit/graphql";
|
|
||||||
|
|
||||||
(async function () {
|
|
||||||
try {
|
|
||||||
const token = process.env.GITHUB_TOKEN;
|
|
||||||
const commitSha = process.env.GITHUB_SHA;
|
|
||||||
const [owner, repo] = process.env.GITHUB_REPOSITORY.split("/");
|
|
||||||
|
|
||||||
if (!token || !commitSha || !owner || !repo) {
|
|
||||||
console.log("Missing required environment variables.");
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
const graphqlWithAuth = graphql.defaults({
|
|
||||||
headers: { authorization: `Bearer ${token}` },
|
|
||||||
});
|
|
||||||
|
|
||||||
// Find PR from commit SHA
|
|
||||||
const searchQuery = `
|
|
||||||
query($owner: String!, $repo: String!, $sha: GitObjectID!) {
|
|
||||||
repository(owner: $owner, name: $repo) {
|
|
||||||
object(oid: $sha) {
|
|
||||||
... on Commit {
|
|
||||||
associatedPullRequests(first: 1) {
|
|
||||||
nodes {
|
|
||||||
number
|
|
||||||
body
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const prResult = await graphqlWithAuth(searchQuery, {
|
|
||||||
owner,
|
|
||||||
repo,
|
|
||||||
sha: commitSha,
|
|
||||||
});
|
|
||||||
|
|
||||||
const pr = prResult.repository.object.associatedPullRequests.nodes[0];
|
|
||||||
if (!pr) {
|
|
||||||
console.log("No PR found for this commit.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const prNumber = pr.number;
|
|
||||||
const prBody = pr.body;
|
|
||||||
|
|
||||||
const match = prBody.match(/#(\d+)/);
|
|
||||||
if (!match) {
|
|
||||||
console.log("No discussion ID found in PR body.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const discussionNumber = match[1];
|
|
||||||
console.log(`Extracted Discussion Number: ${discussionNumber}`);
|
|
||||||
|
|
||||||
// Fetch GraphQL discussion ID
|
|
||||||
const discussionQuery = `
|
|
||||||
query($owner: String!, $repo: String!, $number: Int!) {
|
|
||||||
repository(owner: $owner, name: $repo) {
|
|
||||||
discussion(number: $number) {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
let discussionQLId;
|
|
||||||
try {
|
|
||||||
const discussionResponse = await graphqlWithAuth(discussionQuery, {
|
|
||||||
owner,
|
|
||||||
repo,
|
|
||||||
number: parseInt(discussionNumber, 10),
|
|
||||||
});
|
|
||||||
|
|
||||||
discussionQLId = discussionResponse.repository.discussion.id;
|
|
||||||
if (!discussionQLId) {
|
|
||||||
console.log("Failed to fetch discussion GraphQL ID.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Discussion not found or error occurred while fetching discussion:", error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Post comment
|
|
||||||
const commentMutation = `
|
|
||||||
mutation($discussionId: ID!, $body: String!) {
|
|
||||||
addDiscussionComment(input: { discussionId: $discussionId, body: $body }) {
|
|
||||||
comment { id body }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const commentResponse = await graphqlWithAuth(commentMutation, {
|
|
||||||
discussionId: discussionQLId,
|
|
||||||
body: `Merged with PR #${prNumber}`,
|
|
||||||
});
|
|
||||||
|
|
||||||
const commentId = commentResponse.addDiscussionComment.comment.id;
|
|
||||||
if (!commentId) {
|
|
||||||
console.log("Failed to post the comment.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(`Comment Posted Successfully! Comment ID: ${commentId}`);
|
|
||||||
|
|
||||||
// Mark comment as answer
|
|
||||||
const markAnswerMutation = `
|
|
||||||
mutation($id: ID!) {
|
|
||||||
markDiscussionCommentAsAnswer(input: { id: $id }) {
|
|
||||||
discussion { id title }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
await graphqlWithAuth(markAnswerMutation, { id: commentId });
|
|
||||||
|
|
||||||
console.log("Comment marked as answer successfully!");
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error:", error);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
EOF
|
|
||||||
+119
@@ -0,0 +1,119 @@
|
|||||||
|
name: Close Unauthorized New Script PRs
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request_target:
|
||||||
|
branches: ["main"]
|
||||||
|
types: [opened, labeled]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
check-new-script:
|
||||||
|
if: github.repository == 'community-scripts/ProxmoxVE'
|
||||||
|
runs-on: self-hosted
|
||||||
|
permissions:
|
||||||
|
pull-requests: write
|
||||||
|
contents: read
|
||||||
|
steps:
|
||||||
|
- name: Close PR if unauthorized new script submission
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
const pr = context.payload.pull_request;
|
||||||
|
const prNumber = pr.number;
|
||||||
|
const author = pr.user.login;
|
||||||
|
const authorType = pr.user.type; // "User" or "Bot"
|
||||||
|
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",
|
||||||
|
];
|
||||||
|
|
||||||
|
if (allowedBots.includes(author)) {
|
||||||
|
core.info(`PR #${prNumber} by allowed bot "${author}" — skipping.`);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isMember) {
|
||||||
|
core.info(`PR #${prNumber} by contributor "${author}" — skipping.`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Unauthorized: close the PR with a comment ---
|
||||||
|
core.info(`Closing PR #${prNumber} by "${author}" — not a contributor or allowed bot.`);
|
||||||
|
|
||||||
|
const comment = [
|
||||||
|
`👋 Hi @${author},`,
|
||||||
|
``,
|
||||||
|
`Thank you for your interest in contributing a new script!`,
|
||||||
|
``,
|
||||||
|
`However, **new scripts must first be submitted to our development repository** for testing and review before they can be merged here.`,
|
||||||
|
``,
|
||||||
|
`> 🛑 New scripts must be submitted to [**ProxmoxVED**](https://github.com/community-scripts/ProxmoxVED) for testing.`,
|
||||||
|
`> PRs without prior testing will be closed.`,
|
||||||
|
``,
|
||||||
|
`Please open your PR at **https://github.com/community-scripts/ProxmoxVED** instead.`,
|
||||||
|
`Once your script has been tested and approved there, it will be pushed to this repository automatically.`,
|
||||||
|
``,
|
||||||
|
`This PR will now be closed. Thank you for understanding! 🙏`,
|
||||||
|
].join("\n");
|
||||||
|
|
||||||
|
await github.rest.issues.createComment({
|
||||||
|
owner,
|
||||||
|
repo,
|
||||||
|
issue_number: prNumber,
|
||||||
|
body: comment,
|
||||||
|
});
|
||||||
|
|
||||||
|
await github.rest.pulls.update({
|
||||||
|
owner,
|
||||||
|
repo,
|
||||||
|
pull_number: prNumber,
|
||||||
|
state: "closed",
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add a label to indicate why it was closed
|
||||||
|
await github.rest.issues.addLabels({
|
||||||
|
owner,
|
||||||
|
repo,
|
||||||
|
issue_number: prNumber,
|
||||||
|
labels: ["not a script issue"],
|
||||||
|
});
|
||||||
+1
-1
@@ -21,7 +21,7 @@ jobs:
|
|||||||
const message = `Hello, it looks like you are referencing the **old tteck repo**.
|
const message = `Hello, it looks like you are referencing the **old tteck repo**.
|
||||||
|
|
||||||
This repository is no longer used for active scripts.
|
This repository is no longer used for active scripts.
|
||||||
**Please update your bookmarks** and use: [https://helper-scripts.com](https://helper-scripts.com)
|
**Please update your bookmarks** and use: [https://community-scripts.com](https://community-scripts.com)
|
||||||
|
|
||||||
Also make sure your Bash command starts with:
|
Also make sure your Bash command starts with:
|
||||||
\`\`\`bash
|
\`\`\`bash
|
||||||
|
|||||||
+138
-4
@@ -6,14 +6,14 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
close_issue:
|
close_issue:
|
||||||
if: github.event.pull_request.merged == true && github.repository == 'community-scripts/ProxmoxVE'
|
if: github.event.pull_request.merged == true && github.repository == 'community-scripts/ProxmoxVE'
|
||||||
runs-on: ubuntu-latest
|
runs-on: self-hosted
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout target repo (main)
|
- name: Checkout target repo (merge commit)
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
repository: community-scripts/ProxmoxVE
|
repository: community-scripts/ProxmoxVE
|
||||||
ref: main
|
ref: ${{ github.event.pull_request.merge_commit_sha }}
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Extract and Process PR Title
|
- name: Extract and Process PR Title
|
||||||
@@ -23,6 +23,39 @@ jobs:
|
|||||||
echo "Processed Title: $title"
|
echo "Processed Title: $title"
|
||||||
echo "title=$title" >> $GITHUB_ENV
|
echo "title=$title" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Get slugs from merged PR
|
||||||
|
id: get_slugs
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
pr_files=$(gh pr view ${{ github.event.pull_request.number }} --repo community-scripts/ProxmoxVE --json files -q '.files[].path' 2>/dev/null || true)
|
||||||
|
slugs=""
|
||||||
|
for path in $pr_files; do
|
||||||
|
[[ -f "$path" ]] || continue
|
||||||
|
if [[ "$path" == frontend/public/json/*.json ]]; then
|
||||||
|
s=$(jq -r '.slug // empty' "$path" 2>/dev/null)
|
||||||
|
[[ -n "$s" ]] && slugs="$slugs $s"
|
||||||
|
elif [[ "$path" == ct/*.sh ]] || [[ "$path" == install/*.sh ]] || [[ "$path" == tools/*.sh ]] || [[ "$path" == turnkey/*.sh ]] || [[ "$path" == vm/*.sh ]]; then
|
||||||
|
base=$(basename "$path" .sh)
|
||||||
|
if [[ "$path" == install/* && "$base" == *-install ]]; then
|
||||||
|
s="${base%-install}"
|
||||||
|
else
|
||||||
|
s="$base"
|
||||||
|
fi
|
||||||
|
[[ -n "$s" ]] && slugs="$slugs $s"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
slugs=$(echo $slugs | xargs -n1 | sort -u | tr '\n' ' ')
|
||||||
|
if [[ -z "$slugs" && -n "$title" ]]; then
|
||||||
|
slugs="$title"
|
||||||
|
fi
|
||||||
|
if [[ -z "$slugs" ]]; then
|
||||||
|
echo "count=0" >> "$GITHUB_OUTPUT"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
echo "$slugs" > pocketbase_slugs.txt
|
||||||
|
echo "count=$(echo $slugs | wc -w)" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
- name: Search for Issues with Similar Titles
|
- name: Search for Issues with Similar Titles
|
||||||
id: find_issue
|
id: find_issue
|
||||||
env:
|
env:
|
||||||
@@ -63,3 +96,104 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
gh issue comment $issue_number --repo community-scripts/ProxmoxVED --body "Merged with #${{ github.event.pull_request.number }} in ProxmoxVE"
|
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
|
gh issue close $issue_number --repo community-scripts/ProxmoxVED
|
||||||
|
|
||||||
|
- name: Set is_dev to false in PocketBase
|
||||||
|
if: steps.get_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 }}
|
||||||
|
PR_URL: ${{ github.server_url }}/${{ github.repository }}/pull/${{ github.event.pull_request.number }}
|
||||||
|
run: |
|
||||||
|
node << 'ENDSCRIPT'
|
||||||
|
(async function() {
|
||||||
|
const fs = require('fs');
|
||||||
|
const https = require('https');
|
||||||
|
const http = require('http');
|
||||||
|
const url = require('url');
|
||||||
|
|
||||||
|
function request(fullUrl, opts) {
|
||||||
|
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) {
|
||||||
|
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 slugsText = fs.readFileSync('pocketbase_slugs.txt', 'utf8').trim();
|
||||||
|
const slugs = slugsText ? slugsText.split(/\s+/).filter(Boolean) : [];
|
||||||
|
if (slugs.length === 0) {
|
||||||
|
console.log('No slugs to update.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const authUrl = apiBase + '/collections/users/auth-with-password';
|
||||||
|
const authBody = JSON.stringify({
|
||||||
|
identity: process.env.POCKETBASE_ADMIN_EMAIL,
|
||||||
|
password: process.env.POCKETBASE_ADMIN_PASSWORD
|
||||||
|
});
|
||||||
|
const authRes = await request(authUrl, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: authBody
|
||||||
|
});
|
||||||
|
if (!authRes.ok) {
|
||||||
|
throw new Error('Auth failed: ' + authRes.body);
|
||||||
|
}
|
||||||
|
const token = JSON.parse(authRes.body).token;
|
||||||
|
const recordsUrl = apiBase + '/collections/' + encodeURIComponent(coll) + '/records';
|
||||||
|
const prUrl = process.env.PR_URL || '';
|
||||||
|
|
||||||
|
for (const slug of slugs) {
|
||||||
|
const filter = "(slug='" + slug.replace(/'/g, "''") + "')";
|
||||||
|
const listRes = await request(recordsUrl + '?filter=' + encodeURIComponent(filter) + '&perPage=1', {
|
||||||
|
headers: { 'Authorization': token }
|
||||||
|
});
|
||||||
|
const list = JSON.parse(listRes.body);
|
||||||
|
const record = list.items && list.items[0];
|
||||||
|
if (!record) {
|
||||||
|
console.log('Slug not in DB, skipping: ' + slug);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const patchRes = await request(recordsUrl + '/' + record.id, {
|
||||||
|
method: 'PATCH',
|
||||||
|
headers: { 'Authorization': token, 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({
|
||||||
|
name: record.name || record.slug,
|
||||||
|
last_update_commit: prUrl,
|
||||||
|
is_dev: false
|
||||||
|
})
|
||||||
|
});
|
||||||
|
if (!patchRes.ok) {
|
||||||
|
console.warn('PATCH failed for slug ' + slug + ': ' + patchRes.body);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
console.log('Set is_dev=false for slug: ' + slug);
|
||||||
|
}
|
||||||
|
console.log('Done.');
|
||||||
|
})().catch(e => { console.error(e); process.exit(1); });
|
||||||
|
ENDSCRIPT
|
||||||
|
shell: bash
|
||||||
|
|||||||
-38
@@ -1,38 +0,0 @@
|
|||||||
name: Build and Publish Docker Image
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
paths:
|
|
||||||
- '.github/runner/docker/**'
|
|
||||||
schedule:
|
|
||||||
- cron: '0 0 * * *'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
if: github.repository == 'community-scripts/ProxmoxVE'
|
|
||||||
runs-on: ubuntu-latest #To ensure it always builds we use the github runner with all the right tooling
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Log in to GHCR
|
|
||||||
uses: docker/login-action@v2
|
|
||||||
with:
|
|
||||||
registry: ghcr.io
|
|
||||||
username: ${{ github.actor }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Build Docker image
|
|
||||||
run: |
|
|
||||||
repo_name=${{ github.repository }} # Get repository name
|
|
||||||
repo_name_lower=$(echo $repo_name | tr '[:upper:]' '[:lower:]') # Convert to lowercase
|
|
||||||
docker build -t ghcr.io/$repo_name_lower/gh-runner-self:latest -f .github/runner/docker/gh-runner-self.dockerfile .
|
|
||||||
|
|
||||||
- name: Push Docker image to GHCR
|
|
||||||
run: |
|
|
||||||
repo_name=${{ github.repository }} # Get repository name
|
|
||||||
repo_name_lower=$(echo $repo_name | tr '[:upper:]' '[:lower:]') # Convert to lowercase
|
|
||||||
docker push ghcr.io/$repo_name_lower/gh-runner-self:latest
|
|
||||||
Generated
-29
@@ -1,29 +0,0 @@
|
|||||||
|
|
||||||
name: Delete JSON date PR Branch
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
types: [closed]
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
delete_branch:
|
|
||||||
if: github.repository == 'community-scripts/ProxmoxVE'
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout the code
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Delete PR Update Branch
|
|
||||||
if: github.event.pull_request.merged == true && startsWith(github.event.pull_request.head.ref, 'pr-update-json-')
|
|
||||||
run: |
|
|
||||||
PR_BRANCH="${{ github.event.pull_request.head.ref }}"
|
|
||||||
echo "Deleting branch $PR_BRANCH..."
|
|
||||||
|
|
||||||
# Avoid deleting the default branch (e.g., main)
|
|
||||||
if [[ "$PR_BRANCH" != "main" ]]; then
|
|
||||||
git push origin --delete "$PR_BRANCH"
|
|
||||||
else
|
|
||||||
echo "Skipping deletion of the main branch"
|
|
||||||
fi
|
|
||||||
@@ -0,0 +1,161 @@
|
|||||||
|
name: Set state to is_deleted in pocketbase
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
paths:
|
||||||
|
- "json/**"
|
||||||
|
- "vm/**"
|
||||||
|
- "tools/**"
|
||||||
|
- "turnkey/**"
|
||||||
|
- "ct/**"
|
||||||
|
- "install/**"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
delete-pocketbase-entry:
|
||||||
|
runs-on: self-hosted
|
||||||
|
steps:
|
||||||
|
- name: Checkout Repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Get slugs from deleted JSON and script files
|
||||||
|
id: slugs
|
||||||
|
run: |
|
||||||
|
BEFORE="${{ github.event.before }}"
|
||||||
|
AFTER="${{ github.event.after }}"
|
||||||
|
slugs=""
|
||||||
|
|
||||||
|
# Deleted JSON files: get slug from previous commit
|
||||||
|
deleted_json=$(git diff --name-only --diff-filter=D "$BEFORE" "$AFTER" -- json/ | grep '\.json$' || true)
|
||||||
|
for f in $deleted_json; do
|
||||||
|
[[ -z "$f" ]] && continue
|
||||||
|
s=$(git show "$BEFORE:$f" 2>/dev/null | jq -r '.slug // empty' 2>/dev/null || true)
|
||||||
|
[[ -n "$s" ]] && slugs="$slugs $s"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Deleted script files: derive slug from path
|
||||||
|
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
|
||||||
|
base="${f##*/}"
|
||||||
|
base="${base%.sh}"
|
||||||
|
if [[ "$f" == install/* && "$base" == *-install ]]; then
|
||||||
|
s="${base%-install}"
|
||||||
|
else
|
||||||
|
s="$base"
|
||||||
|
fi
|
||||||
|
[[ -n "$s" ]] && slugs="$slugs $s"
|
||||||
|
done
|
||||||
|
|
||||||
|
slugs=$(echo $slugs | xargs -n1 | 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 "count=$(echo $slugs | wc -w)" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "Slugs to mark as deleted: $slugs"
|
||||||
|
|
||||||
|
- name: Mark as deleted in PocketBase
|
||||||
|
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: |
|
||||||
|
node << 'ENDSCRIPT'
|
||||||
|
(async function() {
|
||||||
|
const fs = require('fs');
|
||||||
|
const https = require('https');
|
||||||
|
const http = require('http');
|
||||||
|
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 slugs = fs.readFileSync('slugs_to_delete.txt', 'utf8').trim().split(/\s+/).filter(Boolean);
|
||||||
|
|
||||||
|
const authUrl = apiBase + '/collections/users/auth-with-password';
|
||||||
|
const authBody = JSON.stringify({
|
||||||
|
identity: process.env.POCKETBASE_ADMIN_EMAIL,
|
||||||
|
password: process.env.POCKETBASE_ADMIN_PASSWORD
|
||||||
|
});
|
||||||
|
const authRes = await request(authUrl, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: authBody
|
||||||
|
});
|
||||||
|
if (!authRes.ok) {
|
||||||
|
throw new Error('Auth failed. Response: ' + authRes.body);
|
||||||
|
}
|
||||||
|
const token = JSON.parse(authRes.body).token;
|
||||||
|
const recordsUrl = apiBase + '/collections/' + encodeURIComponent(coll) + '/records';
|
||||||
|
|
||||||
|
const patchBody = JSON.stringify({ is_deleted: true });
|
||||||
|
|
||||||
|
for (const slug of slugs) {
|
||||||
|
const filter = "(slug='" + slug + "')";
|
||||||
|
const listRes = await request(recordsUrl + '?filter=' + encodeURIComponent(filter) + '&perPage=1', {
|
||||||
|
headers: { 'Authorization': token }
|
||||||
|
});
|
||||||
|
const list = JSON.parse(listRes.body);
|
||||||
|
const existingId = list.items && list.items[0] && list.items[0].id;
|
||||||
|
if (!existingId) {
|
||||||
|
console.log('No PocketBase record for slug "' + slug + '", skipping.');
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const patchRes = await request(recordsUrl + '/' + existingId, {
|
||||||
|
method: 'PATCH',
|
||||||
|
headers: { 'Authorization': token, 'Content-Type': 'application/json' },
|
||||||
|
body: patchBody
|
||||||
|
});
|
||||||
|
if (patchRes.ok) {
|
||||||
|
console.log('Set is_deleted=true for slug "' + slug + '" (id=' + existingId + ').');
|
||||||
|
} else {
|
||||||
|
console.warn('PATCH failed for slug "' + slug + '": ' + patchRes.statusCode + ' ' + patchRes.body);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log('Done.');
|
||||||
|
})().catch(e => { console.error(e); process.exit(1); });
|
||||||
|
ENDSCRIPT
|
||||||
|
shell: bash
|
||||||
Generated
-147
@@ -1,147 +0,0 @@
|
|||||||
# Based on https://github.com/actions/starter-workflows/blob/main/pages/nextjs.yml
|
|
||||||
|
|
||||||
name: Frontend CI/CD
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: ["main"]
|
|
||||||
paths:
|
|
||||||
- frontend/**
|
|
||||||
|
|
||||||
pull_request:
|
|
||||||
branches: ["main"]
|
|
||||||
types: [opened, synchronize, reopened, edited]
|
|
||||||
paths:
|
|
||||||
- frontend/**
|
|
||||||
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: pages-${{ github.ref }}
|
|
||||||
cancel-in-progress: false
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
test-json-files:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
working-directory: frontend
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Setup Python
|
|
||||||
uses: actions/setup-python@v4
|
|
||||||
with:
|
|
||||||
python-version: "3.x"
|
|
||||||
|
|
||||||
- name: Test JSON files
|
|
||||||
run: |
|
|
||||||
python3 << 'EOF'
|
|
||||||
import json
|
|
||||||
import glob
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
|
|
||||||
def test_json_files():
|
|
||||||
# Change to the correct directory
|
|
||||||
json_dir = "public/json"
|
|
||||||
if not os.path.exists(json_dir):
|
|
||||||
print(f"❌ Directory not found: {json_dir}")
|
|
||||||
return False
|
|
||||||
|
|
||||||
# Find all JSON files
|
|
||||||
pattern = os.path.join(json_dir, "*.json")
|
|
||||||
json_files = glob.glob(pattern)
|
|
||||||
|
|
||||||
if not json_files:
|
|
||||||
print(f"⚠️ No JSON files found in {json_dir}")
|
|
||||||
return True
|
|
||||||
|
|
||||||
print(f"Testing {len(json_files)} JSON files for valid syntax...")
|
|
||||||
|
|
||||||
invalid_files = []
|
|
||||||
|
|
||||||
for file_path in json_files:
|
|
||||||
try:
|
|
||||||
with open(file_path, 'r', encoding='utf-8') as f:
|
|
||||||
json.load(f)
|
|
||||||
print(f"✅ Valid JSON: {file_path}")
|
|
||||||
except json.JSONDecodeError as e:
|
|
||||||
print(f"❌ Invalid JSON syntax in: {file_path}")
|
|
||||||
print(f" Error: {e}")
|
|
||||||
invalid_files.append(file_path)
|
|
||||||
except Exception as e:
|
|
||||||
print(f"⚠️ Error reading: {file_path}")
|
|
||||||
print(f" Error: {e}")
|
|
||||||
invalid_files.append(file_path)
|
|
||||||
|
|
||||||
print("\n=== JSON Validation Summary ===")
|
|
||||||
print(f"Total files tested: {len(json_files)}")
|
|
||||||
print(f"Valid files: {len(json_files) - len(invalid_files)}")
|
|
||||||
print(f"Invalid files: {len(invalid_files)}")
|
|
||||||
|
|
||||||
if invalid_files:
|
|
||||||
print("\n❌ Found invalid JSON file(s):")
|
|
||||||
for file_path in invalid_files:
|
|
||||||
print(f" - {file_path}")
|
|
||||||
return False
|
|
||||||
else:
|
|
||||||
print("\n✅ All JSON files have valid syntax!")
|
|
||||||
return True
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
success = test_json_files()
|
|
||||||
sys.exit(0 if success else 1)
|
|
||||||
EOF
|
|
||||||
|
|
||||||
build:
|
|
||||||
if: github.repository == 'community-scripts/ProxmoxVE'
|
|
||||||
needs: test-json-files
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
working-directory: frontend
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Setup Bun
|
|
||||||
uses: oven-sh/setup-bun@v2
|
|
||||||
with:
|
|
||||||
bun-version: latest
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: bun install --frozen-lockfile
|
|
||||||
|
|
||||||
- name: Configure Next.js for pages
|
|
||||||
uses: actions/configure-pages@v5
|
|
||||||
with:
|
|
||||||
static_site_generator: next
|
|
||||||
|
|
||||||
- name: Build with Next.js
|
|
||||||
run: bun run build
|
|
||||||
|
|
||||||
- name: Upload artifact
|
|
||||||
if: github.ref == 'refs/heads/main'
|
|
||||||
uses: actions/upload-pages-artifact@v3
|
|
||||||
with:
|
|
||||||
path: frontend/out
|
|
||||||
|
|
||||||
deploy:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: build
|
|
||||||
if: github.ref == 'refs/heads/main' && github.repository == 'community-scripts/ProxmoxVE'
|
|
||||||
permissions:
|
|
||||||
pages: write
|
|
||||||
id-token: write
|
|
||||||
environment:
|
|
||||||
name: github-pages
|
|
||||||
url: ${{ steps.deployment.outputs.page_url }}
|
|
||||||
steps:
|
|
||||||
- name: Deploy to GitHub Pages
|
|
||||||
id: deployment
|
|
||||||
uses: actions/deploy-pages@v4
|
|
||||||
Generated
+801
@@ -0,0 +1,801 @@
|
|||||||
|
name: PocketBase Bot
|
||||||
|
|
||||||
|
on:
|
||||||
|
issue_comment:
|
||||||
|
types: [created]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
issues: write
|
||||||
|
pull-requests: write
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
pocketbase-bot:
|
||||||
|
runs-on: self-hosted
|
||||||
|
|
||||||
|
# Only act on /pocketbase commands
|
||||||
|
if: startsWith(github.event.comment.body, '/pocketbase')
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Execute PocketBase bot command
|
||||||
|
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 }}
|
||||||
|
COMMENT_BODY: ${{ github.event.comment.body }}
|
||||||
|
COMMENT_ID: ${{ github.event.comment.id }}
|
||||||
|
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 }}
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
FRONTEND_URL: ${{ secrets.FRONTEND_URL }}
|
||||||
|
REVALIDATE_SECRET: ${{ secrets.REVALIDATE_SECRET }}
|
||||||
|
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 API helpers ─────────────────────────────────────────────
|
||||||
|
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.GITHUB_TOKEN,
|
||||||
|
'Accept': 'application/vnd.github+json',
|
||||||
|
'X-GitHub-Api-Version': '2022-11-28',
|
||||||
|
'User-Agent': 'PocketBase-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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Permission check ───────────────────────────────────────────────
|
||||||
|
const association = process.env.ACTOR_ASSOCIATION;
|
||||||
|
if (association !== 'OWNER' && association !== 'MEMBER') {
|
||||||
|
await addReaction('-1');
|
||||||
|
await postComment(
|
||||||
|
'❌ **PocketBase Bot**: @' + actor + ' is not authorized to use this command.\n' +
|
||||||
|
'Only org members (Contributors team) can use `/pocketbase`.'
|
||||||
|
);
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Acknowledge ────────────────────────────────────────────────────
|
||||||
|
await addReaction('eyes');
|
||||||
|
|
||||||
|
// ── Parse command ──────────────────────────────────────────────────
|
||||||
|
const commentBody = process.env.COMMENT_BODY || '';
|
||||||
|
const lines = commentBody.trim().split('\n');
|
||||||
|
const firstLine = lines[0].trim();
|
||||||
|
const withoutCmd = firstLine.replace(/^\/pocketbase\s+/, '').trim();
|
||||||
|
|
||||||
|
function extractCodeBlock(body) {
|
||||||
|
const m = body.match(/```[^\n]*\n([\s\S]*?)```/);
|
||||||
|
return m ? m[1].trim() : null;
|
||||||
|
}
|
||||||
|
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' +
|
||||||
|
'/pocketbase <slug> set description\n' +
|
||||||
|
'```html\n' +
|
||||||
|
'<p>Your <b>HTML</b> or multi-line content here</p>\n' +
|
||||||
|
'```\n' +
|
||||||
|
'````\n\n' +
|
||||||
|
'**Note management:**\n' +
|
||||||
|
'```\n' +
|
||||||
|
'/pocketbase <slug> note list\n' +
|
||||||
|
'/pocketbase <slug> note add <type> "<text>"\n' +
|
||||||
|
'/pocketbase <slug> note edit <type> "<old text>" "<new text>"\n' +
|
||||||
|
'/pocketbase <slug> note remove <type> "<text>"\n' +
|
||||||
|
'```\n\n' +
|
||||||
|
'**Install method management:**\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 <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` ' +
|
||||||
|
'`is_disabled` `disable_message` `is_deleted` `deleted_message`';
|
||||||
|
|
||||||
|
if (!withoutCmd) {
|
||||||
|
await addReaction('-1');
|
||||||
|
await postComment('❌ **PocketBase Bot**: No slug or command specified.\n\n' + HELP_TEXT);
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
const spaceIdx = withoutCmd.indexOf(' ');
|
||||||
|
const slug = (spaceIdx === -1 ? withoutCmd : withoutCmd.substring(0, spaceIdx)).trim();
|
||||||
|
const rest = spaceIdx === -1 ? '' : withoutCmd.substring(spaceIdx + 1).trim();
|
||||||
|
|
||||||
|
if (!rest) {
|
||||||
|
await addReaction('-1');
|
||||||
|
await postComment('❌ **PocketBase Bot**: No command specified for slug `' + slug + '`.\n\n' + HELP_TEXT);
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── PocketBase: authenticate ───────────────────────────────────────
|
||||||
|
const raw = process.env.POCKETBASE_URL.replace(/\/$/, '');
|
||||||
|
const apiBase = /\/api$/i.test(raw) ? raw : raw + '/api';
|
||||||
|
const coll = process.env.POCKETBASE_COLLECTION;
|
||||||
|
|
||||||
|
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) {
|
||||||
|
await addReaction('-1');
|
||||||
|
await postComment('❌ **PocketBase Bot**: PocketBase authentication failed. CC @' + owner + '/maintainers');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
const token = JSON.parse(authRes.body).token;
|
||||||
|
|
||||||
|
// ── 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', {
|
||||||
|
headers: { 'Authorization': token }
|
||||||
|
});
|
||||||
|
const list = JSON.parse(listRes.body);
|
||||||
|
const record = list.items && list.items[0];
|
||||||
|
|
||||||
|
if (!record) {
|
||||||
|
await addReaction('-1');
|
||||||
|
await postComment(
|
||||||
|
'❌ **PocketBase Bot**: No record found for slug `' + slug + '`.\n\n' +
|
||||||
|
'Make sure the script was already pushed to PocketBase (JSON must exist and have been synced).'
|
||||||
|
);
|
||||||
|
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 (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);
|
||||||
|
|
||||||
|
async function patchNotes(arr) {
|
||||||
|
const res = await request(recordsUrl + '/' + record.id, {
|
||||||
|
method: 'PATCH',
|
||||||
|
headers: { 'Authorization': token, 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ notes: arr })
|
||||||
|
});
|
||||||
|
if (!res.ok) {
|
||||||
|
await addReaction('-1');
|
||||||
|
await postComment('❌ **PocketBase Bot**: Failed to update notes:\n```\n' + res.body + '\n```');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (noteAction === 'list') {
|
||||||
|
await addReaction('+1');
|
||||||
|
await postComment(
|
||||||
|
'ℹ️ **PocketBase Bot**: Notes for **`' + slug + '`** (' + notesArr.length + ' total)\n\n' +
|
||||||
|
formatNotesList(notesArr)
|
||||||
|
);
|
||||||
|
|
||||||
|
} else if (noteAction === 'add') {
|
||||||
|
const tokens = parseTokens(noteArgsStr);
|
||||||
|
if (tokens.length < 2) {
|
||||||
|
await addReaction('-1');
|
||||||
|
await postComment(
|
||||||
|
'❌ **PocketBase Bot**: `note add` requires `<type>` and `"<text>"`.\n\n' +
|
||||||
|
'**Usage:** `/pocketbase ' + slug + ' note add <type> "<text>"`'
|
||||||
|
);
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
const noteType = tokens[0].toLowerCase();
|
||||||
|
const noteText = tokens.slice(1).join(' ');
|
||||||
|
notesArr.push({ type: noteType, text: noteText });
|
||||||
|
await patchNotes(notesArr);
|
||||||
|
await revalidate(slug);
|
||||||
|
await addReaction('+1');
|
||||||
|
await postComment(
|
||||||
|
'✅ **PocketBase Bot**: Added note to **`' + slug + '`**\n\n' +
|
||||||
|
'- **Type:** `' + noteType + '`\n' +
|
||||||
|
'- **Text:** ' + noteText + '\n\n' +
|
||||||
|
'*Executed by @' + actor + '*'
|
||||||
|
);
|
||||||
|
|
||||||
|
} else if (noteAction === 'edit') {
|
||||||
|
const tokens = parseTokens(noteArgsStr);
|
||||||
|
if (tokens.length < 3) {
|
||||||
|
await addReaction('-1');
|
||||||
|
await postComment(
|
||||||
|
'❌ **PocketBase Bot**: `note edit` requires `<type>`, `"<old text>"`, and `"<new text>"`.\n\n' +
|
||||||
|
'**Usage:** `/pocketbase ' + slug + ' note edit <type> "<old text>" "<new text>"`\n\n' +
|
||||||
|
'Use `/pocketbase ' + slug + ' note list` to see current notes.'
|
||||||
|
);
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
const noteType = tokens[0].toLowerCase();
|
||||||
|
const oldText = tokens[1];
|
||||||
|
const newText = tokens[2];
|
||||||
|
const idx = notesArr.findIndex(function (n) {
|
||||||
|
return n.type.toLowerCase() === noteType && n.text === oldText;
|
||||||
|
});
|
||||||
|
if (idx === -1) {
|
||||||
|
await addReaction('-1');
|
||||||
|
await postComment(
|
||||||
|
'❌ **PocketBase Bot**: No `' + noteType + '` note found with that exact text.\n\n' +
|
||||||
|
'**Current notes for `' + slug + '`:**\n' + formatNotesList(notesArr)
|
||||||
|
);
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
notesArr[idx].text = newText;
|
||||||
|
await patchNotes(notesArr);
|
||||||
|
await revalidate(slug);
|
||||||
|
await addReaction('+1');
|
||||||
|
await postComment(
|
||||||
|
'✅ **PocketBase Bot**: Edited note in **`' + slug + '`**\n\n' +
|
||||||
|
'- **Type:** `' + noteType + '`\n' +
|
||||||
|
'- **Old:** ' + oldText + '\n' +
|
||||||
|
'- **New:** ' + newText + '\n\n' +
|
||||||
|
'*Executed by @' + actor + '*'
|
||||||
|
);
|
||||||
|
|
||||||
|
} else if (noteAction === 'remove') {
|
||||||
|
const tokens = parseTokens(noteArgsStr);
|
||||||
|
if (tokens.length < 2) {
|
||||||
|
await addReaction('-1');
|
||||||
|
await postComment(
|
||||||
|
'❌ **PocketBase Bot**: `note remove` requires `<type>` and `"<text>"`.\n\n' +
|
||||||
|
'**Usage:** `/pocketbase ' + slug + ' note remove <type> "<text>"`\n\n' +
|
||||||
|
'Use `/pocketbase ' + slug + ' note list` to see current notes.'
|
||||||
|
);
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
const noteType = tokens[0].toLowerCase();
|
||||||
|
const noteText = tokens[1];
|
||||||
|
const before = notesArr.length;
|
||||||
|
notesArr = notesArr.filter(function (n) {
|
||||||
|
return !(n.type.toLowerCase() === noteType && n.text === noteText);
|
||||||
|
});
|
||||||
|
if (notesArr.length === before) {
|
||||||
|
await addReaction('-1');
|
||||||
|
await postComment(
|
||||||
|
'❌ **PocketBase Bot**: No `' + noteType + '` note found with that exact text.\n\n' +
|
||||||
|
'**Current notes for `' + slug + '`:**\n' + formatNotesList(notesArr)
|
||||||
|
);
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
await patchNotes(notesArr);
|
||||||
|
await revalidate(slug);
|
||||||
|
await addReaction('+1');
|
||||||
|
await postComment(
|
||||||
|
'✅ **PocketBase Bot**: Removed note from **`' + slug + '`**\n\n' +
|
||||||
|
'- **Type:** `' + noteType + '`\n' +
|
||||||
|
'- **Text:** ' + noteText + '\n\n' +
|
||||||
|
'*Executed by @' + actor + '*'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (methodMatch) {
|
||||||
|
// ── METHOD SUBCOMMAND ────────────────────────────────────────────
|
||||||
|
const methodArgs = rest.replace(/^method\s*/i, '').trim();
|
||||||
|
const methodListMode = !methodArgs || methodArgs.toLowerCase() === 'list';
|
||||||
|
let methodsArr = readJsonBlob(record.install_methods);
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
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 patchMethods(arr) {
|
||||||
|
const res = await request(recordsUrl + '/' + record.id, {
|
||||||
|
method: 'PATCH',
|
||||||
|
headers: { 'Authorization': token, 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ install_methods: arr })
|
||||||
|
});
|
||||||
|
if (!res.ok) {
|
||||||
|
await addReaction('-1');
|
||||||
|
await postComment('❌ **PocketBase Bot**: Failed to update install methods:\n```\n' + res.body + '\n```');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (methodListMode) {
|
||||||
|
await addReaction('+1');
|
||||||
|
await postComment(
|
||||||
|
'ℹ️ **PocketBase Bot**: Install methods for **`' + slug + '`** (' + methodsArr.length + ' total)\n\n' +
|
||||||
|
formatMethodsList(methodsArr)
|
||||||
|
);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// 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];
|
||||||
|
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 parsed = parseKVPairs(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);
|
||||||
|
await addReaction('+1');
|
||||||
|
await postComment(
|
||||||
|
'✅ **PocketBase Bot**: Added install method **`' + newType + '`** to **`' + slug + '`**\n\n' +
|
||||||
|
formatMethodsList([newMethod]) + '\n\n' +
|
||||||
|
'*Executed by @' + actor + '*'
|
||||||
|
);
|
||||||
|
|
||||||
|
} 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**: 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 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' +
|
||||||
|
'*Executed by @' + actor + '*'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (setMatch) {
|
||||||
|
// ── SET SUBCOMMAND (value from code block) ───────────────────────
|
||||||
|
const fieldName = setMatch[1].toLowerCase();
|
||||||
|
const SET_ALLOWED = {
|
||||||
|
name: 'string', description: 'string', logo: 'string',
|
||||||
|
documentation: 'string', website: 'string', project_url: 'string', github: 'string',
|
||||||
|
config_path: 'string', disable_message: 'string', deleted_message: 'string'
|
||||||
|
};
|
||||||
|
if (!SET_ALLOWED[fieldName]) {
|
||||||
|
await addReaction('-1');
|
||||||
|
await postComment(
|
||||||
|
'❌ **PocketBase Bot**: `set` only supports text fields.\n\n' +
|
||||||
|
'**Allowed:** `' + Object.keys(SET_ALLOWED).join('`, `') + '`\n\n' +
|
||||||
|
'For boolean/number fields use `field=value` syntax instead.'
|
||||||
|
);
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
if (!codeBlockValue) {
|
||||||
|
await addReaction('-1');
|
||||||
|
await postComment(
|
||||||
|
'❌ **PocketBase Bot**: `set` requires a code block with the value.\n\n' +
|
||||||
|
'**Usage:**\n````\n/pocketbase ' + slug + ' set ' + fieldName + '\n```\nYour content here (HTML, multiline, special chars all fine)\n```\n````'
|
||||||
|
);
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
const setPayload = {};
|
||||||
|
setPayload[fieldName] = codeBlockValue;
|
||||||
|
const setPatchRes = await request(recordsUrl + '/' + record.id, {
|
||||||
|
method: 'PATCH',
|
||||||
|
headers: { 'Authorization': token, 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify(setPayload)
|
||||||
|
});
|
||||||
|
if (!setPatchRes.ok) {
|
||||||
|
await addReaction('-1');
|
||||||
|
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(
|
||||||
|
'✅ **PocketBase Bot**: Set `' + fieldName + '` for **`' + slug + '`**\n\n' +
|
||||||
|
'**Value set:**\n```\n' + preview + '\n```\n\n' +
|
||||||
|
'*Executed by @' + actor + '*'
|
||||||
|
);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// ── FIELD=VALUE PATH ─────────────────────────────────────────────
|
||||||
|
const ALLOWED_FIELDS = {
|
||||||
|
name: 'string',
|
||||||
|
description: 'string',
|
||||||
|
logo: 'string',
|
||||||
|
documentation: 'string',
|
||||||
|
website: 'string',
|
||||||
|
project_url: 'string',
|
||||||
|
github: 'string',
|
||||||
|
config_path: 'string',
|
||||||
|
port: 'number',
|
||||||
|
default_user: 'nullable_string',
|
||||||
|
default_passwd: 'nullable_string',
|
||||||
|
updateable: 'boolean',
|
||||||
|
privileged: 'boolean',
|
||||||
|
has_arm: 'boolean',
|
||||||
|
is_dev: 'boolean',
|
||||||
|
is_disabled: 'boolean',
|
||||||
|
disable_message: 'string',
|
||||||
|
is_deleted: 'boolean',
|
||||||
|
deleted_message: 'string',
|
||||||
|
};
|
||||||
|
|
||||||
|
const parsedFields = parseKVPairs(rest);
|
||||||
|
|
||||||
|
const unknownFields = Object.keys(parsedFields).filter(function (f) { return !ALLOWED_FIELDS[f]; });
|
||||||
|
if (unknownFields.length > 0) {
|
||||||
|
await addReaction('-1');
|
||||||
|
await postComment(
|
||||||
|
'❌ **PocketBase Bot**: Unknown field(s): `' + unknownFields.join('`, `') + '`\n\n' +
|
||||||
|
'**Allowed fields:** `' + Object.keys(ALLOWED_FIELDS).join('`, `') + '`'
|
||||||
|
);
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Object.keys(parsedFields).length === 0) {
|
||||||
|
await addReaction('-1');
|
||||||
|
await postComment('❌ **PocketBase Bot**: Could not parse any valid `field=value` pairs.\n\n' + HELP_TEXT);
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cast values to correct types
|
||||||
|
const payload = {};
|
||||||
|
for (const [key, rawVal] of Object.entries(parsedFields)) {
|
||||||
|
const type = ALLOWED_FIELDS[key];
|
||||||
|
if (type === 'boolean') {
|
||||||
|
if (rawVal === 'true') payload[key] = true;
|
||||||
|
else if (rawVal === 'false') payload[key] = false;
|
||||||
|
else {
|
||||||
|
await addReaction('-1');
|
||||||
|
await postComment('❌ **PocketBase Bot**: `' + key + '` must be `true` or `false`, got: `' + rawVal + '`');
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
} else if (type === 'number') {
|
||||||
|
const n = parseInt(rawVal, 10);
|
||||||
|
if (isNaN(n)) {
|
||||||
|
await addReaction('-1');
|
||||||
|
await postComment('❌ **PocketBase Bot**: `' + key + '` must be a number, got: `' + rawVal + '`');
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
payload[key] = n;
|
||||||
|
} else if (type === 'nullable_string') {
|
||||||
|
payload[key] = rawVal === '' ? null : rawVal;
|
||||||
|
} else {
|
||||||
|
payload[key] = rawVal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const patchRes = await request(recordsUrl + '/' + record.id, {
|
||||||
|
method: 'PATCH',
|
||||||
|
headers: { 'Authorization': token, 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify(payload)
|
||||||
|
});
|
||||||
|
if (!patchRes.ok) {
|
||||||
|
await addReaction('-1');
|
||||||
|
await postComment('❌ **PocketBase Bot**: PATCH failed for `' + slug + '`:\n```\n' + patchRes.body + '\n```');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
await revalidate(slug);
|
||||||
|
await addReaction('+1');
|
||||||
|
const changesLines = Object.entries(payload)
|
||||||
|
.map(function ([k, v]) { return '- `' + k + '` → `' + JSON.stringify(v) + '`'; })
|
||||||
|
.join('\n');
|
||||||
|
await postComment(
|
||||||
|
'✅ **PocketBase Bot**: Updated **`' + slug + '`** successfully!\n\n' +
|
||||||
|
'**Changes applied:**\n' + changesLines + '\n\n' +
|
||||||
|
'*Executed by @' + actor + '*'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Done.');
|
||||||
|
})().catch(function (e) {
|
||||||
|
console.error('Fatal error:', e.message || e);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
|
ENDSCRIPT
|
||||||
|
shell: bash
|
||||||
+262
@@ -0,0 +1,262 @@
|
|||||||
|
name: Push JSON changes to PocketBase
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
paths:
|
||||||
|
- "json/**"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
push-json:
|
||||||
|
runs-on: self-hosted
|
||||||
|
steps:
|
||||||
|
- name: Checkout Repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Get changed JSON files with slug
|
||||||
|
id: changed
|
||||||
|
run: |
|
||||||
|
changed=$(git diff --name-only "${{ github.event.before }}" "${{ github.event.after }}" -- json/ | grep '\.json$' || true)
|
||||||
|
with_slug=""
|
||||||
|
for f in $changed; do
|
||||||
|
[[ -f "$f" ]] || continue
|
||||||
|
jq -e '.slug' "$f" >/dev/null 2>&1 && with_slug="$with_slug $f"
|
||||||
|
done
|
||||||
|
with_slug=$(echo $with_slug | xargs -n1)
|
||||||
|
if [[ -z "$with_slug" ]]; then
|
||||||
|
echo "No app JSON files changed (or no files with slug)."
|
||||||
|
echo "count=0" >> "$GITHUB_OUTPUT"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
echo "$with_slug" > changed_app_jsons.txt
|
||||||
|
echo "count=$(echo "$with_slug" | wc -w)" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
- name: Push to PocketBase
|
||||||
|
if: steps.changed.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: |
|
||||||
|
node << 'ENDSCRIPT'
|
||||||
|
(async function() {
|
||||||
|
const fs = require('fs');
|
||||||
|
const https = require('https');
|
||||||
|
const http = require('http');
|
||||||
|
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 files = fs.readFileSync('changed_app_jsons.txt', 'utf8').trim().split(/\s+/).filter(Boolean);
|
||||||
|
const authUrl = apiBase + '/collections/users/auth-with-password';
|
||||||
|
console.log('Auth URL: ' + authUrl);
|
||||||
|
const authBody = JSON.stringify({
|
||||||
|
identity: process.env.POCKETBASE_ADMIN_EMAIL,
|
||||||
|
password: process.env.POCKETBASE_ADMIN_PASSWORD
|
||||||
|
});
|
||||||
|
const authRes = await request(authUrl, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: authBody
|
||||||
|
});
|
||||||
|
if (!authRes.ok) {
|
||||||
|
throw new Error('Auth failed. Tried: ' + authUrl + ' - Verify POST to that URL with body {"identity":"...","password":"..."} works. Response: ' + authRes.body);
|
||||||
|
}
|
||||||
|
const token = JSON.parse(authRes.body).token;
|
||||||
|
const recordsUrl = apiBase + '/collections/' + encodeURIComponent(coll) + '/records';
|
||||||
|
let categoryIdToName = {};
|
||||||
|
try {
|
||||||
|
const metadata = JSON.parse(fs.readFileSync('json/metadata.json', 'utf8'));
|
||||||
|
(metadata.categories || []).forEach(function(cat) { categoryIdToName[cat.id] = cat.name; });
|
||||||
|
} catch (e) { console.warn('Could not load metadata.json:', e.message); }
|
||||||
|
let typeValueToId = {};
|
||||||
|
let categoryNameToPbId = {};
|
||||||
|
try {
|
||||||
|
const typesRes = await request(apiBase + '/collections/z_ref_script_types/records?perPage=500', { headers: { 'Authorization': token } });
|
||||||
|
if (typesRes.ok) {
|
||||||
|
const typesData = JSON.parse(typesRes.body);
|
||||||
|
(typesData.items || []).forEach(function(item) {
|
||||||
|
if (item.type != null) typeValueToId[item.type] = item.id;
|
||||||
|
if (item.name != null) typeValueToId[item.name] = item.id;
|
||||||
|
if (item.value != null) typeValueToId[item.value] = item.id;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (e) { console.warn('Could not fetch z_ref_script_types:', e.message); }
|
||||||
|
try {
|
||||||
|
const catRes = await request(apiBase + '/collections/script_categories/records?perPage=500', { headers: { 'Authorization': token } });
|
||||||
|
if (catRes.ok) {
|
||||||
|
const catData = JSON.parse(catRes.body);
|
||||||
|
(catData.items || []).forEach(function(item) { if (item.name) categoryNameToPbId[item.name] = item.id; });
|
||||||
|
}
|
||||||
|
} catch (e) { console.warn('Could not fetch script_categories:', e.message); }
|
||||||
|
var noteTypeToId = {};
|
||||||
|
var installMethodTypeToId = {};
|
||||||
|
var osToId = {};
|
||||||
|
var osVersionToId = {};
|
||||||
|
try {
|
||||||
|
const res = await request(apiBase + '/collections/z_ref_note_types/records?perPage=500', { headers: { 'Authorization': token } });
|
||||||
|
if (res.ok) JSON.parse(res.body).items?.forEach(function(item) { if (item.type != null) { noteTypeToId[item.type] = item.id; noteTypeToId[item.type.toLowerCase()] = item.id; } });
|
||||||
|
} catch (e) { console.warn('z_ref_note_types:', e.message); }
|
||||||
|
try {
|
||||||
|
const res = await request(apiBase + '/collections/z_ref_install_method_types/records?perPage=500', { headers: { 'Authorization': token } });
|
||||||
|
if (res.ok) JSON.parse(res.body).items?.forEach(function(item) { if (item.type != null) { installMethodTypeToId[item.type] = item.id; installMethodTypeToId[item.type.toLowerCase()] = item.id; } });
|
||||||
|
} catch (e) { console.warn('z_ref_install_method_types:', e.message); }
|
||||||
|
try {
|
||||||
|
const res = await request(apiBase + '/collections/z_ref_os/records?perPage=500', { headers: { 'Authorization': token } });
|
||||||
|
if (res.ok) JSON.parse(res.body).items?.forEach(function(item) { if (item.os != null) { osToId[item.os] = item.id; osToId[item.os.toLowerCase()] = item.id; } });
|
||||||
|
} catch (e) { console.warn('z_ref_os:', e.message); }
|
||||||
|
try {
|
||||||
|
const res = await request(apiBase + '/collections/z_ref_os_version/records?perPage=500&expand=os', { headers: { 'Authorization': token } });
|
||||||
|
if (res.ok) {
|
||||||
|
(JSON.parse(res.body).items || []).forEach(function(item) {
|
||||||
|
var osName = item.expand && item.expand.os && item.expand.os.os != null ? item.expand.os.os : null;
|
||||||
|
if (osName != null && item.version != null) osVersionToId[osName + '|' + item.version] = item.id;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (e) { console.warn('z_ref_os_version:', e.message); }
|
||||||
|
var notesCollUrl = apiBase + '/collections/script_notes/records';
|
||||||
|
var installMethodsCollUrl = apiBase + '/collections/script_install_methods/records';
|
||||||
|
for (const file of files) {
|
||||||
|
if (!fs.existsSync(file)) continue;
|
||||||
|
const data = JSON.parse(fs.readFileSync(file, 'utf8'));
|
||||||
|
if (!data.slug) { console.log('Skipping', file, '(no slug)'); continue; }
|
||||||
|
var payload = {
|
||||||
|
name: data.name,
|
||||||
|
slug: data.slug,
|
||||||
|
script_created: data.date_created || data.script_created,
|
||||||
|
script_updated: new Date().toISOString().split('T')[0],
|
||||||
|
updateable: data.updateable,
|
||||||
|
privileged: data.privileged,
|
||||||
|
port: data.interface_port != null ? data.interface_port : data.port,
|
||||||
|
documentation: data.documentation,
|
||||||
|
website: data.website,
|
||||||
|
logo: data.logo,
|
||||||
|
description: data.description,
|
||||||
|
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
|
||||||
|
};
|
||||||
|
var resolvedType = typeValueToId[data.type];
|
||||||
|
if (resolvedType == null && data.type === 'ct') resolvedType = typeValueToId['lxc'];
|
||||||
|
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.version !== undefined) payload.version = data.version;
|
||||||
|
if (data.changelog !== undefined) payload.changelog = data.changelog;
|
||||||
|
if (data.screenshots !== undefined) payload.screenshots = data.screenshots;
|
||||||
|
const filter = "(slug='" + data.slug + "')";
|
||||||
|
const listRes = await request(recordsUrl + '?filter=' + encodeURIComponent(filter) + '&perPage=1', {
|
||||||
|
headers: { 'Authorization': token }
|
||||||
|
});
|
||||||
|
const list = JSON.parse(listRes.body);
|
||||||
|
const existingId = list.items && list.items[0] && list.items[0].id;
|
||||||
|
async function resolveNotesAndInstallMethods(scriptId) {
|
||||||
|
var noteIds = [];
|
||||||
|
for (var i = 0; i < (data.notes || []).length; i++) {
|
||||||
|
var note = data.notes[i];
|
||||||
|
var typeId = noteTypeToId[note.type];
|
||||||
|
if (typeId == null) continue;
|
||||||
|
var postRes = await request(notesCollUrl, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Authorization': token, 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ text: note.text || '', type: typeId, script: scriptId })
|
||||||
|
});
|
||||||
|
if (postRes.ok) noteIds.push(JSON.parse(postRes.body).id);
|
||||||
|
}
|
||||||
|
var installMethodIds = [];
|
||||||
|
for (var j = 0; j < (data.install_methods || []).length; j++) {
|
||||||
|
var im = data.install_methods[j];
|
||||||
|
var typeId = installMethodTypeToId[im.type];
|
||||||
|
var res = im.resources || {};
|
||||||
|
var osId = osToId[res.os];
|
||||||
|
var osVersionKey = (res.os != null && res.version != null) ? res.os + '|' + res.version : null;
|
||||||
|
var osVersionId = osVersionKey ? osVersionToId[osVersionKey] : null;
|
||||||
|
var imBody = {
|
||||||
|
script: scriptId,
|
||||||
|
resources_cpu: res.cpu != null ? res.cpu : 0,
|
||||||
|
resources_ram: res.ram != null ? res.ram : 0,
|
||||||
|
resources_hdd: res.hdd != null ? res.hdd : 0
|
||||||
|
};
|
||||||
|
if (typeId) imBody.type = typeId;
|
||||||
|
if (osId) imBody.os = osId;
|
||||||
|
if (osVersionId) imBody.os_version = osVersionId;
|
||||||
|
var imPostRes = await request(installMethodsCollUrl, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Authorization': token, 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify(imBody)
|
||||||
|
});
|
||||||
|
if (imPostRes.ok) installMethodIds.push(JSON.parse(imPostRes.body).id);
|
||||||
|
}
|
||||||
|
return { noteIds: noteIds, installMethodIds: installMethodIds };
|
||||||
|
}
|
||||||
|
if (existingId) {
|
||||||
|
var resolved = await resolveNotesAndInstallMethods(existingId);
|
||||||
|
payload.notes = resolved.noteIds;
|
||||||
|
payload.install_methods = resolved.installMethodIds;
|
||||||
|
console.log('Updating', file, '(slug=' + data.slug + ')');
|
||||||
|
const r = await request(recordsUrl + '/' + existingId, {
|
||||||
|
method: 'PATCH',
|
||||||
|
headers: { 'Authorization': token, 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify(payload)
|
||||||
|
});
|
||||||
|
if (!r.ok) throw new Error('PATCH failed: ' + r.body);
|
||||||
|
} else {
|
||||||
|
console.log('Creating', file, '(slug=' + data.slug + ')');
|
||||||
|
const r = await request(recordsUrl, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Authorization': token, 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify(payload)
|
||||||
|
});
|
||||||
|
if (!r.ok) throw new Error('POST failed: ' + r.body);
|
||||||
|
var scriptId = JSON.parse(r.body).id;
|
||||||
|
var resolved = await resolveNotesAndInstallMethods(scriptId);
|
||||||
|
var patchRes = await request(recordsUrl + '/' + scriptId, {
|
||||||
|
method: 'PATCH',
|
||||||
|
headers: { 'Authorization': token, 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ install_methods: resolved.installMethodIds, notes: resolved.noteIds })
|
||||||
|
});
|
||||||
|
if (!patchRes.ok) throw new Error('PATCH relations failed: ' + patchRes.body);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log('Done.');
|
||||||
|
})().catch(e => { console.error(e); process.exit(1); });
|
||||||
|
ENDSCRIPT
|
||||||
|
shell: bash
|
||||||
Generated
-48
@@ -1,48 +0,0 @@
|
|||||||
name: Sync to Gitea
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
sync:
|
|
||||||
if: github.repository == 'community-scripts/ProxmoxVE'
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout source repo
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Change all links to git.community-scripts.org
|
|
||||||
run: |
|
|
||||||
echo "Searching for files containing raw.githubusercontent.com URLs..."
|
|
||||||
|
|
||||||
# Find all files containing GitHub raw URLs, excluding certain directories
|
|
||||||
files_with_github_urls=$(grep -r "https://raw.githubusercontent.com/community-scripts/ProxmoxVE" . --exclude-dir=.git --exclude-dir=node_modules --exclude-dir=.github/workflows --files-with-matches || true)
|
|
||||||
|
|
||||||
if [ -n "$files_with_github_urls" ]; then
|
|
||||||
echo "$files_with_github_urls" | while read file; do
|
|
||||||
if [ -f "$file" ]; then
|
|
||||||
sed -i 's|https://raw\.githubusercontent\.com/community-scripts/ProxmoxVE/|https://git.community-scripts.org/community-scripts/ProxmoxVE/raw/branch/|g' "$file"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
else
|
|
||||||
echo "No files found containing GitHub raw URLs"
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
- name: Push to Gitea
|
|
||||||
run: |
|
|
||||||
git config --global user.name "Push From Github"
|
|
||||||
git config --global user.email "actions@github.com"
|
|
||||||
git remote add gitea https://$GITEA_USER:$GITEA_TOKEN@git.community-scripts.org/community-scripts/ProxmoxVE.git
|
|
||||||
git add .
|
|
||||||
git commit -m "Sync to Gitea"
|
|
||||||
git push gitea --all --force
|
|
||||||
env:
|
|
||||||
GITEA_USER: ${{ secrets.GITEA_USERNAME }}
|
|
||||||
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
|
||||||
@@ -1,85 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
# Copyright (c) 2021-2026 community-scripts ORG
|
|
||||||
# Author: Michel Roegl-Brunner (michelroegl-brunner)
|
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
|
||||||
|
|
||||||
color() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
catch_errors() {
|
|
||||||
set -Eeuo pipefail
|
|
||||||
trap 'error_handler $LINENO "$BASH_COMMAND"' ERR
|
|
||||||
}
|
|
||||||
|
|
||||||
# This function handles errors
|
|
||||||
error_handler() {
|
|
||||||
local line_number="$1"
|
|
||||||
local command="$2"
|
|
||||||
SCRIPT_NAME=$(basename "$0")
|
|
||||||
local error_message="$SCRIPT_NAME: Failure in line $line_number while executing command $command"
|
|
||||||
echo -e "\n$error_message"
|
|
||||||
exit 0
|
|
||||||
}
|
|
||||||
verb_ip6() {
|
|
||||||
STD=""
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
msg_info() {
|
|
||||||
local msg="$1"
|
|
||||||
echo -ne "${msg}\n"
|
|
||||||
}
|
|
||||||
|
|
||||||
msg_ok() {
|
|
||||||
local msg="$1"
|
|
||||||
echo -e "${msg}\n"
|
|
||||||
}
|
|
||||||
|
|
||||||
msg_error() {
|
|
||||||
|
|
||||||
local msg="$1"
|
|
||||||
echo -e "${msg}\n"
|
|
||||||
}
|
|
||||||
|
|
||||||
RETRY_NUM=10
|
|
||||||
RETRY_EVERY=3
|
|
||||||
i=$RETRY_NUM
|
|
||||||
|
|
||||||
setting_up_container() {
|
|
||||||
while [ $i -gt 0 ]; do
|
|
||||||
if [ "$(ip addr show | grep 'inet ' | grep -v '127.0.0.1' | awk '{print $2}' | cut -d'/' -f1)" != "" ]; then
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
echo 1>&2 -en "No Network! "
|
|
||||||
sleep $RETRY_EVERY
|
|
||||||
i=$((i - 1))
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ "$(ip addr show | grep 'inet ' | grep -v '127.0.0.1' | awk '{print $2}' | cut -d'/' -f1)" = "" ]; then
|
|
||||||
echo 1>&2 -e "\n No Network After $RETRY_NUM Tries"
|
|
||||||
echo -e "Check Network Settings"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
msg_ok "Set up Container OS"
|
|
||||||
msg_ok "Network Connected: $(hostname -i)"
|
|
||||||
}
|
|
||||||
|
|
||||||
network_check() {
|
|
||||||
RESOLVEDIP=$(getent hosts github.com | awk '{ print $1 }')
|
|
||||||
if [[ -z "$RESOLVEDIP" ]]; then msg_error "DNS Lookup Failure"; else msg_ok "DNS Resolved github.com to $RESOLVEDIP"; fi
|
|
||||||
set -e
|
|
||||||
}
|
|
||||||
|
|
||||||
update_os() {
|
|
||||||
msg_info "Updating Container OS"
|
|
||||||
$STD apk -U upgrade
|
|
||||||
msg_ok "Updated Container OS"
|
|
||||||
}
|
|
||||||
|
|
||||||
motd_ssh() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
customize() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
-260
@@ -1,260 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
# Copyright (c) 2021-2026 community-scripts ORG
|
|
||||||
# Author: Michel Roegl-Brunner (michelroegl-brunner)
|
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
|
||||||
|
|
||||||
variables() {
|
|
||||||
NSAPP=$(echo ${APP,,} | tr -d ' ') # This function sets the NSAPP variable by converting the value of the APP variable to lowercase and removing any spaces.
|
|
||||||
var_install="${NSAPP}-install" # sets the var_install variable by appending "-install" to the value of NSAPP.
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
NEXTID=$(pvesh get /cluster/nextid)
|
|
||||||
timezone=$(cat /etc/timezone)
|
|
||||||
header_info() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
base_settings() {
|
|
||||||
# Default Settings
|
|
||||||
CT_TYPE="1"
|
|
||||||
DISK_SIZE="4"
|
|
||||||
CORE_COUNT="1"
|
|
||||||
RAM_SIZE="1024"
|
|
||||||
VERBOSE="no"
|
|
||||||
PW=""
|
|
||||||
CT_ID=$NEXTID
|
|
||||||
HN=$NSAPP
|
|
||||||
BRG="vmbr0"
|
|
||||||
NET="dhcp"
|
|
||||||
GATE=""
|
|
||||||
APT_CACHER=""
|
|
||||||
APT_CACHER_IP=""
|
|
||||||
DISABLEIP6="no"
|
|
||||||
MTU=""
|
|
||||||
SD=""
|
|
||||||
NS=""
|
|
||||||
MAC=""
|
|
||||||
VLAN=""
|
|
||||||
SSH="no"
|
|
||||||
SSH_AUTHORIZED_KEY=""
|
|
||||||
TAGS="community-script;"
|
|
||||||
|
|
||||||
# Override default settings with variables from ct script
|
|
||||||
CT_TYPE=${var_unprivileged:-$CT_TYPE}
|
|
||||||
DISK_SIZE=${var_disk:-$DISK_SIZE}
|
|
||||||
CORE_COUNT=${var_cpu:-$CORE_COUNT}
|
|
||||||
RAM_SIZE=${var_ram:-$RAM_SIZE}
|
|
||||||
VERB=${var_verbose:-$VERBOSE}
|
|
||||||
TAGS="${TAGS}${var_tags:-}"
|
|
||||||
|
|
||||||
# Since these 2 are only defined outside of default_settings function, we add a temporary fallback. TODO: To align everything, we should add these as constant variables (e.g. OSTYPE and OSVERSION), but that would currently require updating the default_settings function for all existing scripts
|
|
||||||
if [ -z "$var_os" ]; then
|
|
||||||
var_os="debian"
|
|
||||||
fi
|
|
||||||
if [ -z "$var_version" ]; then
|
|
||||||
var_version="12"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
color() {
|
|
||||||
# Colors
|
|
||||||
YW=$(echo "\033[33m")
|
|
||||||
YWB=$(echo "\033[93m")
|
|
||||||
BL=$(echo "\033[36m")
|
|
||||||
RD=$(echo "\033[01;31m")
|
|
||||||
BGN=$(echo "\033[4;92m")
|
|
||||||
GN=$(echo "\033[1;92m")
|
|
||||||
DGN=$(echo "\033[32m")
|
|
||||||
|
|
||||||
# Formatting
|
|
||||||
CL=$(echo "\033[m")
|
|
||||||
UL=$(echo "\033[4m")
|
|
||||||
BOLD=$(echo "\033[1m")
|
|
||||||
BFR="\\r\\033[K"
|
|
||||||
HOLD=" "
|
|
||||||
TAB=" "
|
|
||||||
|
|
||||||
# Icons
|
|
||||||
CM="${TAB}✔️${TAB}${CL}"
|
|
||||||
CROSS="${TAB}✖️${TAB}${CL}"
|
|
||||||
INFO="${TAB}💡${TAB}${CL}"
|
|
||||||
OS="${TAB}🖥️${TAB}${CL}"
|
|
||||||
OSVERSION="${TAB}🌟${TAB}${CL}"
|
|
||||||
CONTAINERTYPE="${TAB}📦${TAB}${CL}"
|
|
||||||
DISKSIZE="${TAB}💾${TAB}${CL}"
|
|
||||||
CPUCORE="${TAB}🧠${TAB}${CL}"
|
|
||||||
RAMSIZE="${TAB}🛠️${TAB}${CL}"
|
|
||||||
SEARCH="${TAB}🔍${TAB}${CL}"
|
|
||||||
VERIFYPW="${TAB}🔐${TAB}${CL}"
|
|
||||||
CONTAINERID="${TAB}🆔${TAB}${CL}"
|
|
||||||
HOSTNAME="${TAB}🏠${TAB}${CL}"
|
|
||||||
BRIDGE="${TAB}🌉${TAB}${CL}"
|
|
||||||
NETWORK="${TAB}📡${TAB}${CL}"
|
|
||||||
GATEWAY="${TAB}🌐${TAB}${CL}"
|
|
||||||
DISABLEIPV6="${TAB}🚫${TAB}${CL}"
|
|
||||||
DEFAULT="${TAB}⚙️${TAB}${CL}"
|
|
||||||
MACADDRESS="${TAB}🔗${TAB}${CL}"
|
|
||||||
VLANTAG="${TAB}🏷️${TAB}${CL}"
|
|
||||||
ROOTSSH="${TAB}🔑${TAB}${CL}"
|
|
||||||
CREATING="${TAB}🚀${TAB}${CL}"
|
|
||||||
ADVANCED="${TAB}🧩${TAB}${CL}"
|
|
||||||
}
|
|
||||||
|
|
||||||
catch_errors() {
|
|
||||||
set -Eeuo pipefail
|
|
||||||
trap 'error_handler $LINENO "$BASH_COMMAND"' ERR
|
|
||||||
}
|
|
||||||
|
|
||||||
# This function handles errors
|
|
||||||
error_handler() {
|
|
||||||
local line_number="$1"
|
|
||||||
local command="$2"
|
|
||||||
SCRIPT_NAME=$(basename "$0")
|
|
||||||
local error_message="$SCRIPT_NAME: Failure in line $line_number while executing command $command"
|
|
||||||
echo -e "\n$error_message"
|
|
||||||
exit 100
|
|
||||||
}
|
|
||||||
|
|
||||||
msg_info() {
|
|
||||||
local msg="$1"
|
|
||||||
echo -ne "${msg}\n"
|
|
||||||
}
|
|
||||||
|
|
||||||
msg_ok() {
|
|
||||||
local msg="$1"
|
|
||||||
echo -e "${msg}\n"
|
|
||||||
}
|
|
||||||
|
|
||||||
msg_error() {
|
|
||||||
|
|
||||||
local msg="$1"
|
|
||||||
echo -e "${msg}\n"
|
|
||||||
}
|
|
||||||
start() {
|
|
||||||
base_settings
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
build_container() {
|
|
||||||
# if [ "$VERB" == "yes" ]; then set -x; fi
|
|
||||||
|
|
||||||
if [ "$CT_TYPE" == "1" ]; then
|
|
||||||
FEATURES="keyctl=1,nesting=1"
|
|
||||||
else
|
|
||||||
FEATURES="nesting=1"
|
|
||||||
fi
|
|
||||||
TEMP_DIR=$(mktemp -d)
|
|
||||||
pushd $TEMP_DIR >/dev/null
|
|
||||||
if [ "$var_os" == "alpine" ]; then
|
|
||||||
export FUNCTIONS_FILE_PATH="$(curl -s https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/.github/workflows/scripts/app-test/pr-alpine-install.func)"
|
|
||||||
else
|
|
||||||
export FUNCTIONS_FILE_PATH="$(curl -s https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/.github/workflows/scripts/app-test/pr-install.func)"
|
|
||||||
fi
|
|
||||||
|
|
||||||
export CACHER="$APT_CACHER"
|
|
||||||
export CACHER_IP="$APT_CACHER_IP"
|
|
||||||
export tz=""
|
|
||||||
export DISABLEIPV6="$DISABLEIP6"
|
|
||||||
export APPLICATION="$APP"
|
|
||||||
export app="$NSAPP"
|
|
||||||
export PASSWORD="$PW"
|
|
||||||
export VERBOSE="$VERB"
|
|
||||||
export SSH_ROOT="${SSH}"
|
|
||||||
export SSH_AUTHORIZED_KEY
|
|
||||||
export CTID="$CT_ID"
|
|
||||||
export CTTYPE="$CT_TYPE"
|
|
||||||
export PCT_OSTYPE="$var_os"
|
|
||||||
export PCT_OSVERSION="$var_version"
|
|
||||||
export PCT_DISK_SIZE="$DISK_SIZE"
|
|
||||||
export tz="$timezone"
|
|
||||||
export PCT_OPTIONS="
|
|
||||||
-features $FEATURES
|
|
||||||
-hostname $HN
|
|
||||||
-tags $TAGS
|
|
||||||
$SD
|
|
||||||
$NS
|
|
||||||
-net0 name=eth0,bridge=$BRG$MAC,ip=$NET$GATE$VLAN$MTU
|
|
||||||
-onboot 1
|
|
||||||
-cores $CORE_COUNT
|
|
||||||
-memory $RAM_SIZE
|
|
||||||
-unprivileged $CT_TYPE
|
|
||||||
$PW
|
|
||||||
"
|
|
||||||
echo "Container ID: $CTID"
|
|
||||||
|
|
||||||
# This executes create_lxc.sh and creates the container and .conf file
|
|
||||||
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/.github/workflows/scripts/app-test/pr-create-lxc.sh)"
|
|
||||||
|
|
||||||
LXC_CONFIG=/etc/pve/lxc/${CTID}.conf
|
|
||||||
if [ "$CT_TYPE" == "0" ]; then
|
|
||||||
cat <<EOF >>$LXC_CONFIG
|
|
||||||
# USB passthrough
|
|
||||||
lxc.cgroup2.devices.allow: a
|
|
||||||
lxc.cap.drop:
|
|
||||||
lxc.cgroup2.devices.allow: c 188:* rwm
|
|
||||||
lxc.cgroup2.devices.allow: c 189:* rwm
|
|
||||||
lxc.mount.entry: /dev/serial/by-id dev/serial/by-id none bind,optional,create=dir
|
|
||||||
lxc.mount.entry: /dev/ttyUSB0 dev/ttyUSB0 none bind,optional,create=file
|
|
||||||
lxc.mount.entry: /dev/ttyUSB1 dev/ttyUSB1 none bind,optional,create=file
|
|
||||||
lxc.mount.entry: /dev/ttyACM0 dev/ttyACM0 none bind,optional,create=file
|
|
||||||
lxc.mount.entry: /dev/ttyACM1 dev/ttyACM1 none bind,optional,create=file
|
|
||||||
EOF
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$CT_TYPE" == "0" ]; then
|
|
||||||
if [[ "$APP" == "Channels" || "$APP" == "Emby" || "$APP" == "ErsatzTV" || "$APP" == "Frigate" || "$APP" == "Jellyfin" || "$APP" == "Plex" || "$APP" == "Scrypted" || "$APP" == "Tdarr" || "$APP" == "Unmanic" || "$APP" == "Ollama" ]]; then
|
|
||||||
cat <<EOF >>$LXC_CONFIG
|
|
||||||
# VAAPI hardware transcoding
|
|
||||||
lxc.cgroup2.devices.allow: c 226:0 rwm
|
|
||||||
lxc.cgroup2.devices.allow: c 226:128 rwm
|
|
||||||
lxc.cgroup2.devices.allow: c 29:0 rwm
|
|
||||||
lxc.mount.entry: /dev/fb0 dev/fb0 none bind,optional,create=file
|
|
||||||
lxc.mount.entry: /dev/dri dev/dri none bind,optional,create=dir
|
|
||||||
lxc.mount.entry: /dev/dri/renderD128 dev/dri/renderD128 none bind,optional,create=file
|
|
||||||
EOF
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
if [[ "$APP" == "Channels" || "$APP" == "Emby" || "$APP" == "ErsatzTV" || "$APP" == "Frigate" || "$APP" == "Jellyfin" || "$APP" == "Plex" || "$APP" == "Scrypted" || "$APP" == "Tdarr" || "$APP" == "Unmanic" || "$APP" == "Ollama" ]]; then
|
|
||||||
if [[ -e "/dev/dri/renderD128" ]]; then
|
|
||||||
if [[ -e "/dev/dri/card0" ]]; then
|
|
||||||
cat <<EOF >>$LXC_CONFIG
|
|
||||||
# VAAPI hardware transcoding
|
|
||||||
dev0: /dev/dri/card0,gid=44
|
|
||||||
dev1: /dev/dri/renderD128,gid=104
|
|
||||||
EOF
|
|
||||||
else
|
|
||||||
cat <<EOF >>$LXC_CONFIG
|
|
||||||
# VAAPI hardware transcoding
|
|
||||||
dev0: /dev/dri/card1,gid=44
|
|
||||||
dev1: /dev/dri/renderD128,gid=104
|
|
||||||
EOF
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# This starts the container and executes <app>-install.sh
|
|
||||||
msg_info "Starting LXC Container"
|
|
||||||
pct start "$CTID"
|
|
||||||
msg_ok "Started LXC Container"
|
|
||||||
|
|
||||||
if [[ ! -f "/root/actions-runner/_work/ProxmoxVE/ProxmoxVE/install/$var_install.sh" ]]; then
|
|
||||||
msg_error "No install script found for $APP"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
if [ "$var_os" == "alpine" ]; then
|
|
||||||
sleep 3
|
|
||||||
pct exec "$CTID" -- /bin/sh -c 'cat <<EOF >/etc/apk/repositories
|
|
||||||
http://dl-cdn.alpinelinux.org/alpine/latest-stable/main
|
|
||||||
http://dl-cdn.alpinelinux.org/alpine/latest-stable/community
|
|
||||||
EOF'
|
|
||||||
pct exec "$CTID" -- ash -c "apk add bash >/dev/null"
|
|
||||||
fi
|
|
||||||
lxc-attach -n "$CTID" -- bash -c "$(cat /root/actions-runner/_work/ProxmoxVE/ProxmoxVE/install/$var_install.sh)"
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
description() {
|
|
||||||
IP=$(pct exec "$CTID" ip a s dev eth0 | awk '/inet / {print $2}' | cut -d/ -f1)
|
|
||||||
}
|
|
||||||
-163
@@ -1,163 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
# Copyright (c) 2021-2026 community-scripts ORG
|
|
||||||
# Author: Michel Roegl-Brunner (michelroegl-brunner)
|
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
|
||||||
|
|
||||||
color() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
catch_errors() {
|
|
||||||
set -Eeuo pipefail
|
|
||||||
trap 'error_handler $LINENO "$BASH_COMMAND"' ERR
|
|
||||||
}
|
|
||||||
|
|
||||||
# This function handles errors
|
|
||||||
error_handler() {
|
|
||||||
local exit_code="$?"
|
|
||||||
local line_number="$1"
|
|
||||||
local command="$2"
|
|
||||||
local error_message="Failure in line $line_number: exit code $exit_code: while executing command $command"
|
|
||||||
echo -e "\n$error_message"
|
|
||||||
exit 100
|
|
||||||
}
|
|
||||||
verb_ip6() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
msg_info() {
|
|
||||||
local msg="$1"
|
|
||||||
echo -ne "${msg}\n"
|
|
||||||
}
|
|
||||||
|
|
||||||
msg_ok() {
|
|
||||||
local msg="$1"
|
|
||||||
echo -e "${msg}\n"
|
|
||||||
}
|
|
||||||
|
|
||||||
msg_error() {
|
|
||||||
|
|
||||||
local msg="$1"
|
|
||||||
echo -e "${msg}\n"
|
|
||||||
}
|
|
||||||
|
|
||||||
VALIDCT=$(pvesm status -content rootdir | awk 'NR>1')
|
|
||||||
if [ -z "$VALIDCT" ]; then
|
|
||||||
msg_error "Unable to detect a valid Container Storage location."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
VALIDTMP=$(pvesm status -content vztmpl | awk 'NR>1')
|
|
||||||
if [ -z "$VALIDTMP" ]; then
|
|
||||||
msg_error "Unable to detect a valid Template Storage location."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
function select_storage() {
|
|
||||||
local CLASS=$1
|
|
||||||
local CONTENT
|
|
||||||
local CONTENT_LABEL
|
|
||||||
case $CLASS in
|
|
||||||
container)
|
|
||||||
CONTENT='rootdir'
|
|
||||||
CONTENT_LABEL='Container'
|
|
||||||
;;
|
|
||||||
template)
|
|
||||||
CONTENT='vztmpl'
|
|
||||||
CONTENT_LABEL='Container template'
|
|
||||||
;;
|
|
||||||
*) false || {
|
|
||||||
msg_error "Invalid storage class."
|
|
||||||
exit 201
|
|
||||||
} ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# This Queries all storage locations
|
|
||||||
local -a MENU
|
|
||||||
while read -r line; do
|
|
||||||
local TAG=$(echo $line | awk '{print $1}')
|
|
||||||
local TYPE=$(echo $line | awk '{printf "%-10s", $2}')
|
|
||||||
local FREE=$(echo $line | numfmt --field 4-6 --from-unit=K --to=iec --format %.2f | awk '{printf( "%9sB", $6)}')
|
|
||||||
local ITEM="Type: $TYPE Free: $FREE "
|
|
||||||
local OFFSET=2
|
|
||||||
if [[ $((${#ITEM} + $OFFSET)) -gt ${MSG_MAX_LENGTH:-} ]]; then
|
|
||||||
local MSG_MAX_LENGTH=$((${#ITEM} + $OFFSET))
|
|
||||||
fi
|
|
||||||
MENU+=("$TAG" "$ITEM" "OFF")
|
|
||||||
done < <(pvesm status -content $CONTENT | awk 'NR>1')
|
|
||||||
|
|
||||||
# Select storage location
|
|
||||||
if [ $((${#MENU[@]} / 3)) -eq 1 ]; then
|
|
||||||
printf ${MENU[0]}
|
|
||||||
else
|
|
||||||
msg_error "STORAGE ISSUES!"
|
|
||||||
exit 202
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
[[ "${CTID:-}" ]] || {
|
|
||||||
msg_error "You need to set 'CTID' variable."
|
|
||||||
exit 203
|
|
||||||
}
|
|
||||||
[[ "${PCT_OSTYPE:-}" ]] || {
|
|
||||||
msg_error "You need to set 'PCT_OSTYPE' variable."
|
|
||||||
exit 204
|
|
||||||
}
|
|
||||||
|
|
||||||
# Test if ID is valid
|
|
||||||
[ "$CTID" -ge "100" ] || {
|
|
||||||
msg_error "ID cannot be less than 100."
|
|
||||||
exit 205
|
|
||||||
}
|
|
||||||
|
|
||||||
# Test if ID is in use
|
|
||||||
if pct status $CTID &>/dev/null; then
|
|
||||||
echo -e "ID '$CTID' is already in use."
|
|
||||||
unset CTID
|
|
||||||
msg_error "Cannot use ID that is already in use."
|
|
||||||
exit 206
|
|
||||||
fi
|
|
||||||
|
|
||||||
TEMPLATE_STORAGE=$(select_storage template) || exit
|
|
||||||
|
|
||||||
CONTAINER_STORAGE=$(select_storage container) || exit
|
|
||||||
|
|
||||||
pveam update >/dev/null
|
|
||||||
|
|
||||||
TEMPLATE_SEARCH=${PCT_OSTYPE}-${PCT_OSVERSION:-}
|
|
||||||
mapfile -t TEMPLATES < <(pveam available -section system | sed -n "s/.*\($TEMPLATE_SEARCH.*\)/\1/p" | sort -t - -k 2 -V)
|
|
||||||
[ ${#TEMPLATES[@]} -gt 0 ] || {
|
|
||||||
msg_error "Unable to find a template when searching for '$TEMPLATE_SEARCH'."
|
|
||||||
exit 207
|
|
||||||
}
|
|
||||||
TEMPLATE="${TEMPLATES[-1]}"
|
|
||||||
|
|
||||||
TEMPLATE_PATH="/var/lib/vz/template/cache/$TEMPLATE"
|
|
||||||
|
|
||||||
if ! pveam list "$TEMPLATE_STORAGE" | grep -q "$TEMPLATE"; then
|
|
||||||
[[ -f "$TEMPLATE_PATH" ]] && rm -f "$TEMPLATE_PATH"
|
|
||||||
pveam download "$TEMPLATE_STORAGE" "$TEMPLATE" >/dev/null ||
|
|
||||||
{
|
|
||||||
msg_error "A problem occurred while downloading the LXC template."
|
|
||||||
exit 208
|
|
||||||
}
|
|
||||||
fi
|
|
||||||
|
|
||||||
grep -q "root:100000:65536" /etc/subuid || echo "root:100000:65536" >>/etc/subuid
|
|
||||||
grep -q "root:100000:65536" /etc/subgid || echo "root:100000:65536" >>/etc/subgid
|
|
||||||
|
|
||||||
PCT_OPTIONS=(${PCT_OPTIONS[@]:-${DEFAULT_PCT_OPTIONS[@]}})
|
|
||||||
[[ " ${PCT_OPTIONS[@]} " =~ " -rootfs " ]] || PCT_OPTIONS+=(-rootfs "$CONTAINER_STORAGE:${PCT_DISK_SIZE:-8}")
|
|
||||||
|
|
||||||
if ! pct create "$CTID" "${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE}" "${PCT_OPTIONS[@]}" &>/dev/null; then
|
|
||||||
[[ -f "$TEMPLATE_PATH" ]] && rm -f "$TEMPLATE_PATH"
|
|
||||||
|
|
||||||
pveam download "$TEMPLATE_STORAGE" "$TEMPLATE" >/dev/null ||
|
|
||||||
{
|
|
||||||
msg_error "A problem occurred while re-downloading the LXC template."
|
|
||||||
exit 208
|
|
||||||
}
|
|
||||||
|
|
||||||
if ! pct create "$CTID" "${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE}" "${PCT_OPTIONS[@]}" &>/dev/null; then
|
|
||||||
msg_error "A problem occurred while trying to create container after re-downloading template."
|
|
||||||
exit 200
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
-93
@@ -1,93 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
# Copyright (c) 2021-2026 community-scripts ORG
|
|
||||||
# Author: Michel Roegl-Brunner (michelroegl-brunner)
|
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
|
||||||
|
|
||||||
color() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
catch_errors() {
|
|
||||||
set -Euo pipefail
|
|
||||||
trap 'error_handler $LINENO "$BASH_COMMAND"' ERR
|
|
||||||
}
|
|
||||||
|
|
||||||
error_handler() {
|
|
||||||
local line_number="$1"
|
|
||||||
local command="$2"
|
|
||||||
local error_message="Failure in line $line_number while executing command '$command'"
|
|
||||||
echo -e "\n$error_message\n" >&2
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
verb_ip6() {
|
|
||||||
STD="silent"
|
|
||||||
silent() {
|
|
||||||
"$@" >/dev/null 2>&1 || error_handler "${BASH_LINENO[0]}" "$*"
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
msg_info() {
|
|
||||||
local msg="$1"
|
|
||||||
echo -ne "${msg}\n"
|
|
||||||
}
|
|
||||||
|
|
||||||
msg_ok() {
|
|
||||||
local msg="$1"
|
|
||||||
echo -e "${msg}\n"
|
|
||||||
}
|
|
||||||
|
|
||||||
msg_error() {
|
|
||||||
|
|
||||||
local msg="$1"
|
|
||||||
echo -e "${msg}\n"
|
|
||||||
}
|
|
||||||
|
|
||||||
RETRY_NUM=10
|
|
||||||
RETRY_EVERY=3
|
|
||||||
setting_up_container() {
|
|
||||||
|
|
||||||
sed -i "/$LANG/ s/\(^# \)//" /etc/locale.gen
|
|
||||||
locale_line=$(grep -v '^#' /etc/locale.gen | grep -E '^[a-zA-Z]' | awk '{print $1}' | head -n 1)
|
|
||||||
echo "LANG=${locale_line}" >/etc/default/locale
|
|
||||||
locale-gen >/dev/null
|
|
||||||
export LANG=${locale_line}
|
|
||||||
echo $tz >/etc/timezone
|
|
||||||
ln -sf /usr/share/zoneinfo/$tz /etc/localtime
|
|
||||||
|
|
||||||
for ((i = RETRY_NUM; i > 0; i--)); do
|
|
||||||
if [ "$(hostname -I)" != "" ]; then
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
sleep $RETRY_EVERY
|
|
||||||
done
|
|
||||||
if [ "$(hostname -I)" = "" ]; then
|
|
||||||
echo 1>&2 -e "\nNo Network After $RETRY_NUM Tries"
|
|
||||||
echo -e "Check Network Settings"
|
|
||||||
exit 101
|
|
||||||
fi
|
|
||||||
rm -rf /usr/lib/python3.*/EXTERNALLY-MANAGED
|
|
||||||
systemctl disable -q --now systemd-networkd-wait-online.service
|
|
||||||
}
|
|
||||||
|
|
||||||
network_check() {
|
|
||||||
RESOLVEDIP=$(getent hosts github.com | awk '{ print $1 }')
|
|
||||||
if [[ -z "$RESOLVEDIP" ]]; then msg_error "DNS Lookup Failure"; else msg_ok "DNS Resolved github.com to $RESOLVEDIP"; fi
|
|
||||||
set -e
|
|
||||||
}
|
|
||||||
|
|
||||||
update_os() {
|
|
||||||
export DEBIAN_FRONTEND=noninteractive
|
|
||||||
apt-get update >/dev/null 2>&1
|
|
||||||
apt-get -o Dpkg::Options::="--force-confold" -y dist-upgrade >/dev/null
|
|
||||||
rm -rf /usr/lib/python3.*/EXTERNALLY-MANAGED
|
|
||||||
}
|
|
||||||
|
|
||||||
motd_ssh() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
customize() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
Generated
-20
@@ -1,20 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
FILE=$1
|
|
||||||
TODAY=$(date -u +"%Y-%m-%d")
|
|
||||||
|
|
||||||
if [[ -z "$FILE" ]]; then
|
|
||||||
echo "No file specified. Exiting."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ! -f "$FILE" ]]; then
|
|
||||||
echo "File $FILE not found. Exiting."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
DATE_IN_JSON=$(jq -r '.date_created' "$FILE" 2>/dev/null || echo "")
|
|
||||||
|
|
||||||
if [[ "$DATE_IN_JSON" != "$TODAY" ]]; then
|
|
||||||
jq --arg date "$TODAY" '.date_created = $date' "$FILE" >tmp.json && mv tmp.json "$FILE"
|
|
||||||
fi
|
|
||||||
-23
@@ -1,23 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
# Verzeichnis, das die JSON-Dateien enthält
|
|
||||||
json_dir="./json/*.json"
|
|
||||||
|
|
||||||
current_date=$(date +"%Y-%m-%d")
|
|
||||||
|
|
||||||
for json_file in $json_dir; do
|
|
||||||
if [[ -f "$json_file" ]]; then
|
|
||||||
current_json_date=$(jq -r '.date_created' "$json_file")
|
|
||||||
|
|
||||||
if [[ "$current_json_date" != "$current_date" ]]; then
|
|
||||||
echo "Updating $json_file with date $current_date"
|
|
||||||
jq --arg date "$current_date" '.date_created = $date' "$json_file" >temp.json && mv temp.json "$json_file"
|
|
||||||
|
|
||||||
git add "$json_file"
|
|
||||||
git commit -m "Update date_created to $current_date in $json_file"
|
|
||||||
else
|
|
||||||
echo "Date in $json_file is already up to date."
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
git push origin HEAD
|
|
||||||
Generated
+111
@@ -0,0 +1,111 @@
|
|||||||
|
name: Stale PR Management
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: "0 0 * * *"
|
||||||
|
workflow_dispatch:
|
||||||
|
pull_request_target:
|
||||||
|
types:
|
||||||
|
- labeled
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
stale-prs:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
pull-requests: write
|
||||||
|
issues: write
|
||||||
|
contents: read
|
||||||
|
steps:
|
||||||
|
- name: Handle stale PRs
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
const now = new Date();
|
||||||
|
const owner = context.repo.owner;
|
||||||
|
const repo = context.repo.repo;
|
||||||
|
|
||||||
|
// --- When stale label is added, comment immediately ---
|
||||||
|
if (context.eventName === "pull_request_target" && context.payload.action === "labeled") {
|
||||||
|
const label = context.payload.label?.name;
|
||||||
|
if (label === "stale") {
|
||||||
|
const author = context.payload.pull_request.user.login;
|
||||||
|
await github.rest.issues.createComment({
|
||||||
|
owner,
|
||||||
|
repo,
|
||||||
|
issue_number: context.payload.pull_request.number,
|
||||||
|
body: `@${author} This PR has been marked as stale. It will be closed if no new commits are added in 7 days.`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Scheduled run: check all stale PRs ---
|
||||||
|
const { data: prs } = await github.rest.pulls.list({
|
||||||
|
owner,
|
||||||
|
repo,
|
||||||
|
state: "open",
|
||||||
|
per_page: 100
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const pr of prs) {
|
||||||
|
const hasStale = pr.labels.some(l => l.name === "stale");
|
||||||
|
if (!hasStale) continue;
|
||||||
|
|
||||||
|
// Get timeline events to find when stale label was added
|
||||||
|
const { data: events } = await github.rest.issues.listEvents({
|
||||||
|
owner,
|
||||||
|
repo,
|
||||||
|
issue_number: pr.number,
|
||||||
|
per_page: 100
|
||||||
|
});
|
||||||
|
|
||||||
|
// Find the most recent time the stale label was added
|
||||||
|
const staleLabelEvents = events
|
||||||
|
.filter(e => e.event === "labeled" && e.label?.name === "stale")
|
||||||
|
.sort((a, b) => new Date(b.created_at) - new Date(a.created_at));
|
||||||
|
|
||||||
|
if (staleLabelEvents.length === 0) continue;
|
||||||
|
|
||||||
|
const staleLabelDate = new Date(staleLabelEvents[0].created_at);
|
||||||
|
const daysSinceStale = (now - staleLabelDate) / (1000 * 60 * 60 * 24);
|
||||||
|
|
||||||
|
// Check for new commits since stale label was added
|
||||||
|
const { data: commits } = await github.rest.pulls.listCommits({
|
||||||
|
owner,
|
||||||
|
repo,
|
||||||
|
pull_number: pr.number
|
||||||
|
});
|
||||||
|
|
||||||
|
const lastCommitDate = new Date(commits[commits.length - 1].commit.author.date);
|
||||||
|
const author = pr.user.login;
|
||||||
|
|
||||||
|
// If there are new commits after the stale label, remove it
|
||||||
|
if (lastCommitDate > staleLabelDate) {
|
||||||
|
await github.rest.issues.removeLabel({
|
||||||
|
owner,
|
||||||
|
repo,
|
||||||
|
issue_number: pr.number,
|
||||||
|
name: "stale"
|
||||||
|
});
|
||||||
|
await github.rest.issues.createComment({
|
||||||
|
owner,
|
||||||
|
repo,
|
||||||
|
issue_number: pr.number,
|
||||||
|
body: `@${author} Recent activity detected. Removing stale label.`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// If 7 days have passed since stale label, close the PR
|
||||||
|
else if (daysSinceStale > 7) {
|
||||||
|
await github.rest.pulls.update({
|
||||||
|
owner,
|
||||||
|
repo,
|
||||||
|
pull_number: pr.number,
|
||||||
|
state: "closed"
|
||||||
|
});
|
||||||
|
await github.rest.issues.createComment({
|
||||||
|
owner,
|
||||||
|
repo,
|
||||||
|
issue_number: pr.number,
|
||||||
|
body: `@${author} Closing stale PR due to inactivity (no commits for 7 days after stale label).`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
+41
@@ -0,0 +1,41 @@
|
|||||||
|
name: Pages Redirect
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
pages: write
|
||||||
|
id-token: write
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Create redirect page
|
||||||
|
run: |
|
||||||
|
mkdir site
|
||||||
|
cat <<EOF > site/index.html
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="refresh" content="0; url=https://community-scripts.org/">
|
||||||
|
<link rel="canonical" href="https://community-scripts.org/">
|
||||||
|
<title>Redirecting...</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
Redirecting...
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
EOF
|
||||||
|
|
||||||
|
- uses: actions/upload-pages-artifact@v3
|
||||||
|
with:
|
||||||
|
path: site
|
||||||
|
|
||||||
|
- name: Deploy
|
||||||
|
uses: actions/deploy-pages@v4
|
||||||
Generated
-152
@@ -1,152 +0,0 @@
|
|||||||
name: Update JSON Date
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
paths:
|
|
||||||
- "frontend/public/json/**.json"
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
update-app-files:
|
|
||||||
if: github.repository == 'community-scripts/ProxmoxVE'
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
pull-requests: write
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Generate a token
|
|
||||||
id: generate-token
|
|
||||||
uses: actions/create-github-app-token@v1
|
|
||||||
with:
|
|
||||||
app-id: ${{ vars.APP_ID }}
|
|
||||||
private-key: ${{ secrets.APP_PRIVATE_KEY }}
|
|
||||||
|
|
||||||
- name: Generate a token for PR approval and merge
|
|
||||||
id: generate-token-merge
|
|
||||||
uses: actions/create-github-app-token@v1
|
|
||||||
with:
|
|
||||||
app-id: ${{ secrets.APP_ID_APPROVE_AND_MERGE }}
|
|
||||||
private-key: ${{ secrets.APP_KEY_APPROVE_AND_MERGE }}
|
|
||||||
|
|
||||||
- name: Generate dynamic branch name
|
|
||||||
id: timestamp
|
|
||||||
run: echo "BRANCH_NAME=pr-update-json-$(date +'%Y%m%d%H%M%S')" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Set up GH_TOKEN
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
run: |
|
|
||||||
echo "GH_TOKEN=${GH_TOKEN}" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Checkout Repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 2 # Ensure we have the last two commits
|
|
||||||
|
|
||||||
- name: Get Previous Commit
|
|
||||||
id: prev_commit
|
|
||||||
run: |
|
|
||||||
PREV_COMMIT=$(git rev-parse HEAD^)
|
|
||||||
echo "Previous commit: $PREV_COMMIT"
|
|
||||||
echo "prev_commit=$PREV_COMMIT" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Get Newly Added JSON Files
|
|
||||||
id: new_json_files
|
|
||||||
run: |
|
|
||||||
git diff --name-only --diff-filter=A ${{ env.prev_commit }} HEAD | grep '^frontend/public/json/.*\.json$' > new_files.txt || true
|
|
||||||
echo "New files detected:"
|
|
||||||
cat new_files.txt || echo "No new files."
|
|
||||||
|
|
||||||
- name: Disable file mode changes
|
|
||||||
run: git config core.fileMode false
|
|
||||||
|
|
||||||
- name: Set up Git
|
|
||||||
run: |
|
|
||||||
git config --global user.name "GitHub Actions"
|
|
||||||
git config --global user.email "github-actions[bot]@users.noreply.github.com"
|
|
||||||
|
|
||||||
- name: Change JSON Date
|
|
||||||
id: change-json-date
|
|
||||||
run: |
|
|
||||||
current_date=$(date +"%Y-%m-%d")
|
|
||||||
while IFS= read -r file; do
|
|
||||||
# Skip empty lines
|
|
||||||
[[ -z "$file" ]] && continue
|
|
||||||
|
|
||||||
if [[ -f "$file" ]]; then
|
|
||||||
echo "Processing $file..."
|
|
||||||
current_json_date=$(jq -r '.date_created // empty' "$file")
|
|
||||||
if [[ -z "$current_json_date" || "$current_json_date" != "$current_date" ]]; then
|
|
||||||
echo "Updating $file with date $current_date"
|
|
||||||
jq --arg date "$current_date" '.date_created = $date' "$file" > temp.json && mv temp.json "$file"
|
|
||||||
else
|
|
||||||
echo "Date in $file is already up to date."
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "Warning: File $file not found!"
|
|
||||||
fi
|
|
||||||
done < new_files.txt
|
|
||||||
rm new_files.txt
|
|
||||||
|
|
||||||
- name: Check if there are any changes
|
|
||||||
run: |
|
|
||||||
echo "Checking for changes..."
|
|
||||||
git add -A
|
|
||||||
git status
|
|
||||||
if git diff --cached --quiet; then
|
|
||||||
echo "No changes detected."
|
|
||||||
echo "changed=false" >> "$GITHUB_ENV"
|
|
||||||
else
|
|
||||||
echo "Changes detected:"
|
|
||||||
git diff --stat --cached
|
|
||||||
echo "changed=true" >> "$GITHUB_ENV"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Step 7: Commit and create PR if changes exist
|
|
||||||
- name: Commit and create PR if changes exist
|
|
||||||
if: env.changed == 'true'
|
|
||||||
run: |
|
|
||||||
|
|
||||||
|
|
||||||
git commit -m "Update date in json"
|
|
||||||
git checkout -b ${{ env.BRANCH_NAME }}
|
|
||||||
git push origin ${{ env.BRANCH_NAME }}
|
|
||||||
|
|
||||||
gh pr create --title "[core] update date in json" \
|
|
||||||
--body "This PR is auto-generated by a GitHub Action to update the date in json." \
|
|
||||||
--head ${{ env.BRANCH_NAME }} \
|
|
||||||
--base main \
|
|
||||||
--label "automated pr"
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
|
|
||||||
|
|
||||||
- name: Approve pull request
|
|
||||||
if: env.changed == 'true'
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
run: |
|
|
||||||
PR_NUMBER=$(gh pr list --head "${{ env.BRANCH_NAME }}" --json number --jq '.[].number')
|
|
||||||
if [ -n "$PR_NUMBER" ]; then
|
|
||||||
gh pr review $PR_NUMBER --approve
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Approve pull request and merge
|
|
||||||
if: env.changed == 'true'
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ steps.generate-token-merge.outputs.token }}
|
|
||||||
run: |
|
|
||||||
git config --global user.name "github-actions-automege[bot]"
|
|
||||||
git config --global user.email "github-actions-automege[bot]@users.noreply.github.com"
|
|
||||||
PR_NUMBER=$(gh pr list --head "${BRANCH_NAME}" --json number --jq '.[].number')
|
|
||||||
if [ -n "$PR_NUMBER" ]; then
|
|
||||||
gh pr review $PR_NUMBER --approve
|
|
||||||
gh pr merge $PR_NUMBER --squash --admin
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: No changes detected
|
|
||||||
if: env.changed == 'false'
|
|
||||||
run: echo "No changes to commit. Workflow completed successfully."
|
|
||||||
@@ -0,0 +1,183 @@
|
|||||||
|
name: Update script timestamp on .sh changes
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
paths:
|
||||||
|
- "ct/**/*.sh"
|
||||||
|
- "install/**/*.sh"
|
||||||
|
- "tools/**/*.sh"
|
||||||
|
- "turnkey/**/*.sh"
|
||||||
|
- "vm/**/*.sh"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
update-script-timestamp:
|
||||||
|
runs-on: self-hosted
|
||||||
|
steps:
|
||||||
|
- name: Checkout Repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Get changed .sh files and derive slugs
|
||||||
|
id: slugs
|
||||||
|
run: |
|
||||||
|
changed=$(git diff --name-only "${{ github.event.before }}" "${{ github.event.after }}" -- ct/ install/ tools/ turnkey/ vm/ | grep '\.sh$' || true)
|
||||||
|
if [[ -z "$changed" ]]; then
|
||||||
|
echo "No .sh files changed in ct/, install/, tools/, turnkey/, or vm/."
|
||||||
|
echo "count=0" >> "$GITHUB_OUTPUT"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
declare -A seen
|
||||||
|
slugs=""
|
||||||
|
for f in $changed; do
|
||||||
|
[[ -f "$f" ]] || continue
|
||||||
|
base="${f##*/}"
|
||||||
|
base="${base%.sh}"
|
||||||
|
if [[ "$f" == install/* && "$base" == *-install ]]; then
|
||||||
|
slug="${base%-install}"
|
||||||
|
else
|
||||||
|
slug="$base"
|
||||||
|
fi
|
||||||
|
if [[ -z "${seen[$slug]:-}" ]]; then
|
||||||
|
seen[$slug]=1
|
||||||
|
slugs="$slugs $slug"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
slugs=$(echo $slugs | xargs -n1 | sort -u)
|
||||||
|
if [[ -z "$slugs" ]]; then
|
||||||
|
echo "No slugs to update."
|
||||||
|
echo "count=0" >> "$GITHUB_OUTPUT"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
echo "$slugs" > changed_slugs.txt
|
||||||
|
echo "count=$(echo "$slugs" | wc -w)" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
- name: Parse PR number from merge commit
|
||||||
|
id: pr
|
||||||
|
run: |
|
||||||
|
re='#([0-9]+)'
|
||||||
|
if [[ "$COMMIT_MSG" =~ $re ]]; then
|
||||||
|
echo "number=${BASH_REMATCH[1]}" >> "$GITHUB_OUTPUT"
|
||||||
|
else
|
||||||
|
echo "number=" >> "$GITHUB_OUTPUT"
|
||||||
|
fi
|
||||||
|
env:
|
||||||
|
COMMIT_MSG: ${{ github.event.head_commit.message }}
|
||||||
|
|
||||||
|
- name: Update script timestamps in PocketBase
|
||||||
|
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 }}
|
||||||
|
COMMIT_URL: ${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }}
|
||||||
|
PR_URL: ${{ steps.pr.outputs.number != '' && format('{0}/{1}/pull/{2}', github.server_url, github.repository, steps.pr.outputs.number) || '' }}
|
||||||
|
run: |
|
||||||
|
node << 'ENDSCRIPT'
|
||||||
|
(async function() {
|
||||||
|
const fs = require('fs');
|
||||||
|
const https = require('https');
|
||||||
|
const http = require('http');
|
||||||
|
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 slugsText = fs.readFileSync('changed_slugs.txt', 'utf8').trim();
|
||||||
|
const slugs = slugsText ? slugsText.split(/\s+/).filter(Boolean) : [];
|
||||||
|
if (slugs.length === 0) {
|
||||||
|
console.log('No slugs to update.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const authUrl = apiBase + '/collections/users/auth-with-password';
|
||||||
|
const authBody = JSON.stringify({
|
||||||
|
identity: process.env.POCKETBASE_ADMIN_EMAIL,
|
||||||
|
password: process.env.POCKETBASE_ADMIN_PASSWORD
|
||||||
|
});
|
||||||
|
const authRes = await request(authUrl, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: authBody
|
||||||
|
});
|
||||||
|
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 slugs) {
|
||||||
|
const filter = "(slug='" + slug.replace(/'/g, "''") + "')";
|
||||||
|
const listRes = await request(recordsUrl + '?filter=' + encodeURIComponent(filter) + '&perPage=1', {
|
||||||
|
headers: { 'Authorization': token }
|
||||||
|
});
|
||||||
|
const list = JSON.parse(listRes.body);
|
||||||
|
const record = list.items && list.items[0];
|
||||||
|
if (!record) {
|
||||||
|
console.log('Slug not in DB, skipping: ' + slug);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const today = new Date().toISOString().split('T')[0];
|
||||||
|
const patchBody = {
|
||||||
|
script_updated: today,
|
||||||
|
last_update_commit: process.env.PR_URL || process.env.COMMIT_URL || ''
|
||||||
|
};
|
||||||
|
// When a dev script is merged into main, promote it to production
|
||||||
|
if (record.is_dev === true) {
|
||||||
|
patchBody.is_dev = false;
|
||||||
|
patchBody.script_created = today;
|
||||||
|
console.log('Promoting dev script to production: ' + slug);
|
||||||
|
}
|
||||||
|
const patchRes = await request(recordsUrl + '/' + record.id, {
|
||||||
|
method: 'PATCH',
|
||||||
|
headers: { 'Authorization': token, 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify(patchBody)
|
||||||
|
});
|
||||||
|
if (!patchRes.ok) {
|
||||||
|
console.warn('PATCH failed for slug ' + slug + ': ' + patchRes.body);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
console.log('Updated timestamp for slug: ' + slug);
|
||||||
|
}
|
||||||
|
console.log('Done.');
|
||||||
|
})().catch(e => { console.error(e); process.exit(1); });
|
||||||
|
ENDSCRIPT
|
||||||
|
shell: bash
|
||||||
-236
@@ -1,236 +0,0 @@
|
|||||||
name: Update GitHub Versions (New)
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
schedule:
|
|
||||||
# Runs 4x daily: 00:00, 06:00, 12:00, 18:00 UTC
|
|
||||||
- cron: "0 0,6,12,18 * * *"
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
pull-requests: write
|
|
||||||
|
|
||||||
env:
|
|
||||||
VERSIONS_FILE: frontend/public/json/github-versions.json
|
|
||||||
BRANCH_NAME: automated/update-github-versions
|
|
||||||
AUTOMATED_PR_LABEL: "automated pr"
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
update-github-versions:
|
|
||||||
if: github.repository == 'community-scripts/ProxmoxVE'
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Generate a token
|
|
||||||
id: generate-token
|
|
||||||
uses: actions/create-github-app-token@v1
|
|
||||||
with:
|
|
||||||
app-id: ${{ vars.APP_ID }}
|
|
||||||
private-key: ${{ secrets.APP_PRIVATE_KEY }}
|
|
||||||
|
|
||||||
- name: Generate a token for PR approval and merge
|
|
||||||
id: generate-token-merge
|
|
||||||
uses: actions/create-github-app-token@v1
|
|
||||||
with:
|
|
||||||
app-id: ${{ secrets.APP_ID_APPROVE_AND_MERGE }}
|
|
||||||
private-key: ${{ secrets.APP_KEY_APPROVE_AND_MERGE }}
|
|
||||||
|
|
||||||
- name: Checkout Repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
ref: main
|
|
||||||
|
|
||||||
- name: Extract GitHub versions from install scripts
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
run: |
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
echo "========================================="
|
|
||||||
echo " Extracting GitHub versions from scripts"
|
|
||||||
echo "========================================="
|
|
||||||
|
|
||||||
# Initialize versions array
|
|
||||||
versions_json="[]"
|
|
||||||
|
|
||||||
# Function to add a version entry
|
|
||||||
add_version() {
|
|
||||||
local slug="$1"
|
|
||||||
local repo="$2"
|
|
||||||
local version="$3"
|
|
||||||
local pinned="$4"
|
|
||||||
local date="$5"
|
|
||||||
|
|
||||||
versions_json=$(echo "$versions_json" | jq \
|
|
||||||
--arg slug "$slug" \
|
|
||||||
--arg repo "$repo" \
|
|
||||||
--arg version "$version" \
|
|
||||||
--argjson pinned "$pinned" \
|
|
||||||
--arg date "$date" \
|
|
||||||
'. += [{"slug": $slug, "repo": $repo, "version": $version, "pinned": $pinned, "date": $date}]')
|
|
||||||
}
|
|
||||||
|
|
||||||
# Get list of slugs from JSON files
|
|
||||||
echo ""
|
|
||||||
echo "=== Scanning JSON files for slugs ==="
|
|
||||||
|
|
||||||
for json_file in frontend/public/json/*.json; do
|
|
||||||
[[ ! -f "$json_file" ]] && continue
|
|
||||||
|
|
||||||
# Skip non-app JSON files
|
|
||||||
basename_file=$(basename "$json_file")
|
|
||||||
case "$basename_file" in
|
|
||||||
metadata.json|versions.json|github-versions.json|dependency-check.json|update-apps.json)
|
|
||||||
continue
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# Extract slug from JSON
|
|
||||||
slug=$(jq -r '.slug // empty' "$json_file" 2>/dev/null)
|
|
||||||
[[ -z "$slug" ]] && continue
|
|
||||||
|
|
||||||
# Find corresponding script (install script or addon script)
|
|
||||||
install_script=""
|
|
||||||
if [[ -f "install/${slug}-install.sh" ]]; then
|
|
||||||
install_script="install/${slug}-install.sh"
|
|
||||||
elif [[ -f "tools/addon/${slug}.sh" ]]; then
|
|
||||||
install_script="tools/addon/${slug}.sh"
|
|
||||||
else
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Look for fetch_and_deploy_gh_release calls
|
|
||||||
# Pattern: fetch_and_deploy_gh_release "app" "owner/repo" ["mode"] ["version"]
|
|
||||||
while IFS= read -r line; do
|
|
||||||
# Skip commented lines
|
|
||||||
[[ "$line" =~ ^[[:space:]]*# ]] && continue
|
|
||||||
|
|
||||||
# Extract repo and version from fetch_and_deploy_gh_release
|
|
||||||
if [[ "$line" =~ fetch_and_deploy_gh_release[[:space:]]+\"[^\"]*\"[[:space:]]+\"([^\"]+)\"([[:space:]]+\"([^\"]+)\")?([[:space:]]+\"([^\"]+)\")? ]]; then
|
|
||||||
repo="${BASH_REMATCH[1]}"
|
|
||||||
mode="${BASH_REMATCH[3]:-tarball}"
|
|
||||||
pinned_version="${BASH_REMATCH[5]:-latest}"
|
|
||||||
|
|
||||||
# Check if version is pinned (not "latest" and not empty)
|
|
||||||
is_pinned=false
|
|
||||||
target_version=""
|
|
||||||
|
|
||||||
if [[ -n "$pinned_version" && "$pinned_version" != "latest" ]]; then
|
|
||||||
is_pinned=true
|
|
||||||
target_version="$pinned_version"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Fetch version from GitHub
|
|
||||||
if [[ "$is_pinned" == "true" ]]; then
|
|
||||||
# For pinned versions, verify it exists and get date
|
|
||||||
response=$(gh api "repos/${repo}/releases/tags/${target_version}" 2>/dev/null || echo '{}')
|
|
||||||
if echo "$response" | jq -e '.tag_name' > /dev/null 2>&1; then
|
|
||||||
version=$(echo "$response" | jq -r '.tag_name')
|
|
||||||
date=$(echo "$response" | jq -r '.published_at // empty')
|
|
||||||
add_version "$slug" "$repo" "$version" "true" "$date"
|
|
||||||
echo "[$slug] ✓ $version (pinned)"
|
|
||||||
else
|
|
||||||
echo "[$slug] ⚠ pinned version $target_version not found"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
# Fetch latest release
|
|
||||||
response=$(gh api "repos/${repo}/releases/latest" 2>/dev/null || echo '{}')
|
|
||||||
if echo "$response" | jq -e '.tag_name' > /dev/null 2>&1; then
|
|
||||||
version=$(echo "$response" | jq -r '.tag_name')
|
|
||||||
date=$(echo "$response" | jq -r '.published_at // empty')
|
|
||||||
add_version "$slug" "$repo" "$version" "false" "$date"
|
|
||||||
echo "[$slug] ✓ $version"
|
|
||||||
else
|
|
||||||
# Try tags as fallback
|
|
||||||
version=$(gh api "repos/${repo}/tags" --jq '.[0].name // empty' 2>/dev/null || echo "")
|
|
||||||
if [[ -n "$version" ]]; then
|
|
||||||
add_version "$slug" "$repo" "$version" "false" ""
|
|
||||||
echo "[$slug] ✓ $version (from tags)"
|
|
||||||
else
|
|
||||||
echo "[$slug] ⚠ no version found"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
break # Only first match per script
|
|
||||||
fi
|
|
||||||
done < <(grep 'fetch_and_deploy_gh_release' "$install_script" 2>/dev/null || true)
|
|
||||||
|
|
||||||
done
|
|
||||||
|
|
||||||
# Save versions file
|
|
||||||
echo "$versions_json" | jq --arg date "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
|
|
||||||
'{generated: $date, versions: (. | sort_by(.slug))}' > "$VERSIONS_FILE"
|
|
||||||
|
|
||||||
total=$(echo "$versions_json" | jq 'length')
|
|
||||||
echo ""
|
|
||||||
echo "========================================="
|
|
||||||
echo " Total versions extracted: $total"
|
|
||||||
echo "========================================="
|
|
||||||
|
|
||||||
- name: Check for changes
|
|
||||||
id: check-changes
|
|
||||||
run: |
|
|
||||||
# Check if file is new (untracked) or has changes
|
|
||||||
if [[ ! -f "$VERSIONS_FILE" ]]; then
|
|
||||||
echo "changed=false" >> "$GITHUB_OUTPUT"
|
|
||||||
echo "Versions file was not created"
|
|
||||||
elif ! git ls-files --error-unmatch "$VERSIONS_FILE" &>/dev/null; then
|
|
||||||
# File exists but is not tracked - it's new
|
|
||||||
echo "changed=true" >> "$GITHUB_OUTPUT"
|
|
||||||
echo "New file created: $VERSIONS_FILE"
|
|
||||||
elif git diff --quiet "$VERSIONS_FILE" 2>/dev/null; then
|
|
||||||
echo "changed=false" >> "$GITHUB_OUTPUT"
|
|
||||||
echo "No changes detected"
|
|
||||||
else
|
|
||||||
echo "changed=true" >> "$GITHUB_OUTPUT"
|
|
||||||
echo "Changes detected:"
|
|
||||||
git diff --stat "$VERSIONS_FILE" 2>/dev/null || true
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Commit and push changes
|
|
||||||
if: steps.check-changes.outputs.changed == 'true'
|
|
||||||
run: |
|
|
||||||
git config --global user.name "github-actions[bot]"
|
|
||||||
git config --global user.email "github-actions[bot]@users.noreply.github.com"
|
|
||||||
git add "$VERSIONS_FILE"
|
|
||||||
git commit -m "chore: update github-versions.json"
|
|
||||||
git checkout -b $BRANCH_NAME || git checkout $BRANCH_NAME
|
|
||||||
git push origin $BRANCH_NAME --force
|
|
||||||
|
|
||||||
- name: Create pull request if not exists
|
|
||||||
if: steps.check-changes.outputs.changed == 'true'
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
|
|
||||||
run: |
|
|
||||||
PR_EXISTS=$(gh pr list --head "${BRANCH_NAME}" --json number --jq '.[].number')
|
|
||||||
if [ -z "$PR_EXISTS" ]; then
|
|
||||||
gh pr create --title "[Github Action] Update github-versions.json" \
|
|
||||||
--body "This PR is auto-generated by a Github Action to update the github-versions.json file." \
|
|
||||||
--head $BRANCH_NAME \
|
|
||||||
--base main \
|
|
||||||
--label "$AUTOMATED_PR_LABEL"
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Approve pull request
|
|
||||||
if: steps.check-changes.outputs.changed == 'true'
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
run: |
|
|
||||||
PR_NUMBER=$(gh pr list --head "${BRANCH_NAME}" --json number --jq '.[].number')
|
|
||||||
if [ -n "$PR_NUMBER" ]; then
|
|
||||||
gh pr review $PR_NUMBER --approve
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Approve pull request and merge
|
|
||||||
if: steps.check-changes.outputs.changed == 'true'
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ steps.generate-token-merge.outputs.token }}
|
|
||||||
run: |
|
|
||||||
git config --global user.name "github-actions-automege[bot]"
|
|
||||||
git config --global user.email "github-actions-automege[bot]@users.noreply.github.com"
|
|
||||||
PR_NUMBER=$(gh pr list --head "${BRANCH_NAME}" --json number --jq '.[].number')
|
|
||||||
if [ -n "$PR_NUMBER" ]; then
|
|
||||||
gh pr review $PR_NUMBER --approve
|
|
||||||
gh pr merge $PR_NUMBER --squash --admin
|
|
||||||
fi
|
|
||||||
+5
-45
@@ -2,39 +2,14 @@
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
Thumbs.db
|
Thumbs.db
|
||||||
|
|
||||||
# Editor & IDE files (keeping .vscode settings but ignoring unnecessary metadata)
|
# Editor & IDE files
|
||||||
!.vscode/
|
!.vscode/
|
||||||
.vscode/*.workspace
|
.vscode/*.workspace
|
||||||
.vscode/*.tmp
|
.vscode/*.tmp
|
||||||
|
|
||||||
# Log and Cache files
|
# Log files
|
||||||
logs/
|
logs/
|
||||||
*.log
|
*.log
|
||||||
npm-debug.log*
|
|
||||||
yarn-debug.log*
|
|
||||||
yarn-error.log*
|
|
||||||
|
|
||||||
# Python-specific exclusions
|
|
||||||
__pycache__/
|
|
||||||
*.pyc
|
|
||||||
*.pyo
|
|
||||||
*.pyd
|
|
||||||
*.venv/
|
|
||||||
venv/
|
|
||||||
env/
|
|
||||||
*.env
|
|
||||||
|
|
||||||
# Node.js dependencies (frontend folder was excluded, but keeping this rule for reference)
|
|
||||||
frontend/node_modules/
|
|
||||||
frontend/.svelte-kit/
|
|
||||||
frontend/.turbo/
|
|
||||||
frontend/.vite/
|
|
||||||
frontend/build/
|
|
||||||
|
|
||||||
# API and Backend specific exclusions
|
|
||||||
api/.env
|
|
||||||
api/__pycache__/
|
|
||||||
api/*.sqlite3
|
|
||||||
|
|
||||||
# Install scripts and temporary files
|
# Install scripts and temporary files
|
||||||
install/tmp/
|
install/tmp/
|
||||||
@@ -48,7 +23,7 @@ vm/*.vmdk
|
|||||||
vm/*.iso
|
vm/*.iso
|
||||||
vm/*.bak
|
vm/*.bak
|
||||||
|
|
||||||
# Miscellaneous temporary or unnecessary files
|
# Miscellaneous temporary files
|
||||||
*.bak
|
*.bak
|
||||||
*.swp
|
*.swp
|
||||||
*.swo
|
*.swo
|
||||||
@@ -56,22 +31,7 @@ vm/*.bak
|
|||||||
*.tmp
|
*.tmp
|
||||||
*.backup
|
*.backup
|
||||||
|
|
||||||
# JSON configuration backups
|
# JSON temporary files
|
||||||
|
json/
|
||||||
json/*.bak
|
json/*.bak
|
||||||
json/*.tmp
|
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
|
|
||||||
+553
-856
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">
|
<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>
|
<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>
|
<p>
|
||||||
<a href="https://helper-scripts.com">
|
<a href="https://community-scripts.org"><img src="https://img.shields.io/badge/Website-community--scripts.org-4c9b3f?style=flat-square" /></a>
|
||||||
<img src="https://img.shields.io/badge/🌐_Website-Visit-4c9b3f?style=for-the-badge&labelColor=2d3748" alt="Website" />
|
<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>
|
<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://discord.gg/3AnUqsXnmK">
|
<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>
|
||||||
<img src="https://img.shields.io/badge/💬_Discord-Join-7289da?style=for-the-badge&labelColor=2d3748" alt="Discord" />
|
<a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue?style=flat-square" /></a>
|
||||||
</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>
|
|
||||||
</p>
|
</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>
|
</div>
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🎯 Key Features
|
## What is this?
|
||||||
|
|
||||||
<div align="center">
|
**Simplify your Proxmox VE setup with community-driven automation scripts.**
|
||||||
|
|
||||||
<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.
|
||||||
<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>
|
|
||||||
|
|
||||||
</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">
|
| Component | Details |
|
||||||
|
| -------------- | ------------------------------------------------ |
|
||||||
<table>
|
| **Proxmox VE** | Version 8.4, 9.0, or 9.1 |
|
||||||
<tr>
|
| **Host OS** | Proxmox VE (Debian-based) |
|
||||||
<td align="center" width="33%">
|
| **Access** | Root shell access on the Proxmox host |
|
||||||
<h3>🖥️ Proxmox VE</h3>
|
| **Network** | Internet connection required during installation |
|
||||||
<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>
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 📥 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:
|
Each script page documents what the container includes, default resource allocation, and post-install notes.
|
||||||
|
|
||||||
1. Visit **[helper-scripts.com](https://helper-scripts.com/)** 🌐
|
|
||||||
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)
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 💬 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>
|
<tr>
|
||||||
<td align="center" width="33%">
|
<td align="center">
|
||||||
<h3>💬 Discord</h3>
|
<a href="https://github.com/MickLesk">
|
||||||
<p>Real-time chat, support, and discussions</p>
|
<img src="https://github.com/MickLesk.png" width="80" height="80" style="border-radius:50%" alt="MickLesk" /><br/>
|
||||||
<a href="https://discord.gg/3AnUqsXnmK">
|
<sub><b>MickLesk</b></sub>
|
||||||
<img src="https://img.shields.io/badge/Join-7289da?style=for-the-badge&logo=discord&logoColor=white" alt="Discord" />
|
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td align="center" width="33%">
|
<td align="center">
|
||||||
<h3>💭 Discussions</h3>
|
<a href="https://github.com/michelroegl-brunner">
|
||||||
<p>Feature requests, Q&A, and ideas</p>
|
<img src="https://github.com/michelroegl-brunner.png" width="80" height="80" style="border-radius:50%" alt="michelroegl-brunner" /><br/>
|
||||||
<a href="https://github.com/community-scripts/ProxmoxVE/discussions">
|
<sub><b>michelroegl-brunner</b></sub>
|
||||||
<img src="https://img.shields.io/badge/Discuss-238636?style=for-the-badge&logo=github&logoColor=white" alt="Discussions" />
|
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td align="center" width="33%">
|
<td align="center">
|
||||||
<h3>🐛 Issues</h3>
|
<a href="https://github.com/BramSuurdje">
|
||||||
<p>Bug reports and issue tracking</p>
|
<img src="https://github.com/BramSuurdje.png" width="80" height="80" style="border-radius:50%" alt="BramSuurdje" /><br/>
|
||||||
<a href="https://github.com/community-scripts/ProxmoxVE/issues">
|
<sub><b>BramSuurdje</b></sub>
|
||||||
<img src="https://img.shields.io/badge/Report-d73a4a?style=for-the-badge&logo=github&logoColor=white" alt="Issues" />
|
</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>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</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">
|
<p align="center">
|
||||||
<img
|
<img
|
||||||
src="https://repobeats.axiom.co/api/embed/57edde03e00f88d739bdb5b844ff7d07dd079375.svg"
|
src="https://repobeats.axiom.co/api/embed/57edde03e00f88d739bdb5b844ff7d07dd079375.svg"
|
||||||
alt="Repobeats analytics"
|
alt="Repository activity"
|
||||||
width="650"
|
width="700"
|
||||||
/>
|
/>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://star-history.com/#community-scripts/ProxmoxVE&Date">
|
<a href="https://star-history.com/#community-scripts/ProxmoxVE&Date">
|
||||||
<picture>
|
<picture>
|
||||||
<source
|
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=community-scripts/ProxmoxVE&type=Date&theme=dark" />
|
||||||
media="(prefers-color-scheme: dark)"
|
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=community-scripts/ProxmoxVE&type=Date" />
|
||||||
srcset="https://api.star-history.com/svg?repos=community-scripts/ProxmoxVE&type=Date&theme=dark"
|
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=community-scripts/ProxmoxVE&type=Date" width="700" />
|
||||||
/>
|
|
||||||
<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"
|
|
||||||
/>
|
|
||||||
</picture>
|
</picture>
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</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">
|
<div align="center">
|
||||||
<sub>Made with ❤️ by the Proxmox community in memory of tteck</sub>
|
<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/>
|
||||||
<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>
|
<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>
|
</div>
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@ source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxV
|
|||||||
# Copyright (c) 2021-2026 community-scripts ORG
|
# Copyright (c) 2021-2026 community-scripts ORG
|
||||||
# Author: jkrgr0
|
# Author: jkrgr0
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
# Source: https://docs.2fauth.app/
|
# Source: https://docs.2fauth.app/ | Github: https://github.com/Bubka/2FAuth
|
||||||
|
|
||||||
APP="2FAuth"
|
APP="2FAuth"
|
||||||
var_tags="${var_tags:-2fa;authenticator}"
|
var_tags="${var_tags:-2fa;authenticator}"
|
||||||
|
|||||||
+4
-4
@@ -3,7 +3,7 @@ source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxV
|
|||||||
# Copyright (c) 2021-2026 community-scripts ORG
|
# Copyright (c) 2021-2026 community-scripts ORG
|
||||||
# Author: MickLesk (CanbiZ)
|
# Author: MickLesk (CanbiZ)
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
# Source: https://actualbudget.org/
|
# Source: https://actualbudget.org/ | Github: https://github.com/actualbudget/actual
|
||||||
|
|
||||||
APP="Actual Budget"
|
APP="Actual Budget"
|
||||||
var_tags="${var_tags:-finance}"
|
var_tags="${var_tags:-finance}"
|
||||||
@@ -48,9 +48,9 @@ function update_script() {
|
|||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
msg_info "Old Installation Found, you need to migrate your data and recreate to a new container"
|
msg_warn "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_warn "Please follow the instructions on the Actual Budget website to migrate your data"
|
||||||
msg_info "https://actualbudget.org/docs/backup-restore/backup"
|
msg_warn "https://actualbudget.org/docs/backup-restore/backup"
|
||||||
exit
|
exit
|
||||||
fi
|
fi
|
||||||
exit
|
exit
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@ source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxV
|
|||||||
# Copyright (c) 2021-2026 tteck
|
# Copyright (c) 2021-2026 tteck
|
||||||
# Author: tteck (tteckster)
|
# Author: tteck (tteckster)
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
# Source: https://adguard.com/
|
# Source: https://adguard.com/ | Github: https://github.com/AdguardTeam/AdGuardHome
|
||||||
|
|
||||||
APP="Adguard"
|
APP="Adguard"
|
||||||
var_tags="${var_tags:-adblock}"
|
var_tags="${var_tags:-adblock}"
|
||||||
|
|||||||
+2
-1
@@ -3,7 +3,7 @@ source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxV
|
|||||||
# Copyright (c) 2021-2026 tteck
|
# Copyright (c) 2021-2026 tteck
|
||||||
# Author: MickLesk (Canbiz)
|
# Author: MickLesk (Canbiz)
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
# Source: https://adventurelog.app/
|
# Source: https://github.com/seanmorley15/AdventureLog
|
||||||
|
|
||||||
APP="AdventureLog"
|
APP="AdventureLog"
|
||||||
var_tags="${var_tags:-traveling}"
|
var_tags="${var_tags:-traveling}"
|
||||||
@@ -56,6 +56,7 @@ function update_script() {
|
|||||||
fi
|
fi
|
||||||
$STD .venv/bin/python -m pip install --upgrade pip
|
$STD .venv/bin/python -m pip install --upgrade pip
|
||||||
$STD .venv/bin/python -m pip install -r requirements.txt
|
$STD .venv/bin/python -m pip install -r requirements.txt
|
||||||
|
$STD .venv/bin/python -m pip install 'djangorestframework<3.15'
|
||||||
$STD .venv/bin/python -m manage collectstatic --noinput
|
$STD .venv/bin/python -m manage collectstatic --noinput
|
||||||
$STD .venv/bin/python -m manage migrate
|
$STD .venv/bin/python -m manage migrate
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,107 @@
|
|||||||
|
#!/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: Sander Koenders (sanderkoenders)
|
||||||
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
|
# Source: https://www.borgbackup.org/
|
||||||
|
|
||||||
|
APP="Alpine-BorgBackup-Server"
|
||||||
|
var_tags="${var_tags:-alpine;backup}"
|
||||||
|
var_cpu="${var_cpu:-2}"
|
||||||
|
var_ram="${var_ram:-1024}"
|
||||||
|
var_disk="${var_disk:-20}"
|
||||||
|
var_os="${var_os:-alpine}"
|
||||||
|
var_version="${var_version:-3.23}"
|
||||||
|
var_unprivileged="${var_unprivileged:-1}"
|
||||||
|
|
||||||
|
header_info "$APP"
|
||||||
|
variables
|
||||||
|
color
|
||||||
|
catch_errors
|
||||||
|
|
||||||
|
function update_script() {
|
||||||
|
header_info
|
||||||
|
|
||||||
|
if [[ ! -f /usr/bin/borg ]]; then
|
||||||
|
msg_error "No ${APP} Installation Found!"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
CHOICE=$(msg_menu "BorgBackup Server Update Options" \
|
||||||
|
"1" "Update BorgBackup Server" \
|
||||||
|
"2" "Reset SSH Access" \
|
||||||
|
"3" "Enable password authentication for backup user (not recommended, use SSH key instead)" \
|
||||||
|
"4" "Disable password authentication for backup user (recommended for security, use SSH key)")
|
||||||
|
|
||||||
|
case $CHOICE in
|
||||||
|
1)
|
||||||
|
msg_info "Updating $APP LXC"
|
||||||
|
$STD apk -U upgrade
|
||||||
|
msg_ok "Updated $APP LXC successfully!"
|
||||||
|
;;
|
||||||
|
2)
|
||||||
|
if [[ "${PHS_SILENT:-0}" == "1" ]]; then
|
||||||
|
msg_warn "Reset SSH Public key requires interactive mode, skipping."
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
msg_info "Setting up SSH Public Key for backup user"
|
||||||
|
|
||||||
|
msg_info "Please paste your SSH public key (e.g., ssh-rsa AAAAB3... user@host): \n"
|
||||||
|
read -p "Key: " SSH_PUBLIC_KEY
|
||||||
|
echo
|
||||||
|
|
||||||
|
if [[ -z "$SSH_PUBLIC_KEY" ]]; then
|
||||||
|
msg_error "No SSH public key provided!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! "$SSH_PUBLIC_KEY" =~ ^(ssh-rsa|ssh-dss|ssh-ed25519|ecdsa-sha2-) ]]; then
|
||||||
|
msg_error "Invalid SSH public key format!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
msg_info "Setting up SSH access"
|
||||||
|
mkdir -p /home/backup/.ssh
|
||||||
|
echo "$SSH_PUBLIC_KEY" >/home/backup/.ssh/authorized_keys
|
||||||
|
|
||||||
|
chown -R backup:backup /home/backup/.ssh
|
||||||
|
chmod 700 /home/backup/.ssh
|
||||||
|
chmod 600 /home/backup/.ssh/authorized_keys
|
||||||
|
|
||||||
|
msg_ok "SSH access configured for backup user"
|
||||||
|
;;
|
||||||
|
3)
|
||||||
|
if [[ "${PHS_SILENT:-0}" == "1" ]]; then
|
||||||
|
msg_warn "Enabling password authentication requires interactive mode, skipping."
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
msg_info "Enabling password authentication for backup user"
|
||||||
|
msg_warn "Password authentication is less secure than using SSH keys. Consider using SSH keys instead."
|
||||||
|
passwd backup
|
||||||
|
sed -i 's/^#*\s*PasswordAuthentication\s\+\(yes\|no\)/PasswordAuthentication yes/' /etc/ssh/sshd_config
|
||||||
|
rc-service sshd restart
|
||||||
|
msg_ok "Password authentication enabled for backup user"
|
||||||
|
;;
|
||||||
|
4)
|
||||||
|
msg_info "Disabling password authentication for backup user"
|
||||||
|
sed -i 's/^#*\s*PasswordAuthentication\s\+\(yes\|no\)/PasswordAuthentication no/' /etc/ssh/sshd_config
|
||||||
|
rc-service sshd restart
|
||||||
|
msg_ok "Password authentication disabled for backup user"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
start
|
||||||
|
build_container
|
||||||
|
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 "${TAB}${VERIFYPW}${YW}To set SSH key, run this script with the 'update' option and select option 2${CL}"
|
||||||
+1
-1
@@ -3,7 +3,7 @@ source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxV
|
|||||||
# Copyright (c) 2021-2026 community-scripts ORG
|
# Copyright (c) 2021-2026 community-scripts ORG
|
||||||
# Author: MickLesk (CanbiZ)
|
# Author: MickLesk (CanbiZ)
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
# Source: https://gitea.io
|
# Source: https://gitea.io/
|
||||||
|
|
||||||
APP="Alpine-Gitea"
|
APP="Alpine-Gitea"
|
||||||
var_tags="${var_tags:-alpine;git}"
|
var_tags="${var_tags:-alpine;git}"
|
||||||
|
|||||||
@@ -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: MickLesk (CanbiZ)
|
||||||
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
|
# Source: https://github.com/nearai/ironclaw
|
||||||
|
|
||||||
|
APP="Alpine-IronClaw"
|
||||||
|
var_tags="${var_tags:-ai;agent;alpine}"
|
||||||
|
var_cpu="${var_cpu:-1}"
|
||||||
|
var_ram="${var_ram:-1024}"
|
||||||
|
var_disk="${var_disk:-8}"
|
||||||
|
var_os="${var_os:-alpine}"
|
||||||
|
var_version="${var_version:-3.23}"
|
||||||
|
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 /usr/local/bin/ironclaw ]]; then
|
||||||
|
msg_error "No ${APP} Installation Found!"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
if check_for_gh_release "ironclaw-bin" "nearai/ironclaw"; then
|
||||||
|
msg_info "Stopping Service"
|
||||||
|
rc-service ironclaw stop 2>/dev/null || true
|
||||||
|
msg_ok "Stopped Service"
|
||||||
|
|
||||||
|
msg_info "Backing up Configuration"
|
||||||
|
cp /root/.ironclaw/.env /root/ironclaw.env.bak
|
||||||
|
msg_ok "Backed up Configuration"
|
||||||
|
|
||||||
|
fetch_and_deploy_gh_release "ironclaw-bin" "nearai/ironclaw" "prebuild" "latest" "/usr/local/bin" \
|
||||||
|
"ironclaw-$(uname -m)-unknown-linux-musl.tar.gz"
|
||||||
|
chmod +x /usr/local/bin/ironclaw
|
||||||
|
|
||||||
|
msg_info "Restoring Configuration"
|
||||||
|
cp /root/ironclaw.env.bak /root/.ironclaw/.env
|
||||||
|
rm -f /root/ironclaw.env.bak
|
||||||
|
msg_ok "Restored Configuration"
|
||||||
|
|
||||||
|
msg_info "Starting Service"
|
||||||
|
rc-service ironclaw start
|
||||||
|
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} 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}"
|
||||||
+37
-31
@@ -3,7 +3,7 @@ source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxV
|
|||||||
# Copyright (c) 2021-2026 community-scripts ORG
|
# Copyright (c) 2021-2026 community-scripts ORG
|
||||||
# Author: MickLesk (CanbiZ)
|
# Author: MickLesk (CanbiZ)
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
# Source: https://komo.do
|
# Source: https://komo.do/
|
||||||
|
|
||||||
APP="Alpine-Komodo"
|
APP="Alpine-Komodo"
|
||||||
var_tags="${var_tags:-docker;alpine}"
|
var_tags="${var_tags:-docker;alpine}"
|
||||||
@@ -19,44 +19,50 @@ variables
|
|||||||
color
|
color
|
||||||
catch_errors
|
catch_errors
|
||||||
|
|
||||||
|
ADDON_SCRIPT="https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/addon/komodo.sh"
|
||||||
|
|
||||||
function update_script() {
|
function update_script() {
|
||||||
[[ -d /opt/komodo ]] || {
|
if [[ ! -d /opt/komodo ]]; then
|
||||||
msg_error "No ${APP} Installation Found!"
|
msg_error "No ${APP} Installation Found!"
|
||||||
exit
|
exit
|
||||||
}
|
|
||||||
|
|
||||||
msg_info "Updating ${APP}"
|
|
||||||
COMPOSE_FILE=$(find /opt/komodo -maxdepth 1 -type f -name '*.compose.yaml' ! -name 'compose.env' | head -n1)
|
|
||||||
if [[ -z "$COMPOSE_FILE" ]]; then
|
|
||||||
msg_error "No valid compose file found in /opt/komodo!"
|
|
||||||
exit
|
|
||||||
fi
|
fi
|
||||||
COMPOSE_BASENAME=$(basename "$COMPOSE_FILE")
|
|
||||||
|
|
||||||
if [[ "$COMPOSE_BASENAME" == "sqlite.compose.yaml" || "$COMPOSE_BASENAME" == "postgres.compose.yaml" ]]; then
|
msg_warn "⚠️ ${APP} has been migrated to an addon script."
|
||||||
msg_error "❌ Detected outdated Komodo setup using SQLite or PostgreSQL (FerretDB v1)."
|
echo ""
|
||||||
echo -e "${YW}This configuration is no longer supported since Komodo v1.18.0.${CL}"
|
msg_info "This is a one-time migration. After this, you can update ${APP} anytime with:"
|
||||||
echo -e "${YW}Please follow the migration guide:${CL}"
|
echo -e "${TAB}${TAB}${GN}update_komodo${CL} or ${GN}bash <(curl -fsSL ${ADDON_SCRIPT})${CL}"
|
||||||
echo -e "${BGN}https://github.com/community-scripts/ProxmoxVE/discussions/5689${CL}\n"
|
echo ""
|
||||||
|
read -r -p "${TAB}Migrate update function now? [y/N]: " CONFIRM
|
||||||
|
if [[ ! "${CONFIRM,,}" =~ ^(y|yes)$ ]]; then
|
||||||
|
msg_warn "Migration skipped. The old update will continue to work for now."
|
||||||
|
msg_warn "⚠️ Komodo v2 uses :2 image tags. The :latest tag is deprecated and will not receive v2 updates."
|
||||||
|
msg_warn "Please migrate to the addon script to receive Komodo v2."
|
||||||
|
msg_info "Updating ${APP} (legacy)"
|
||||||
|
COMPOSE_FILE=$(find /opt/komodo -maxdepth 1 -type f -name '*.compose.yaml' ! -name 'compose.env' | head -n1)
|
||||||
|
if [[ -z "$COMPOSE_FILE" ]]; then
|
||||||
|
msg_error "No valid compose file found in /opt/komodo!"
|
||||||
|
exit 252
|
||||||
|
fi
|
||||||
|
$STD docker compose -p komodo -f "$COMPOSE_FILE" --env-file /opt/komodo/compose.env pull
|
||||||
|
$STD docker compose -p komodo -f "$COMPOSE_FILE" --env-file /opt/komodo/compose.env up -d
|
||||||
|
msg_ok "Updated ${APP}"
|
||||||
exit
|
exit
|
||||||
fi
|
fi
|
||||||
|
|
||||||
BACKUP_FILE="/opt/komodo/${COMPOSE_BASENAME}.bak_$(date +%Y%m%d_%H%M%S)"
|
msg_info "Migrating update function"
|
||||||
cp "$COMPOSE_FILE" "$BACKUP_FILE" || {
|
TMP_UPDATE=$(mktemp)
|
||||||
msg_error "Failed to create backup of ${COMPOSE_BASENAME}!"
|
cat <<'MIGRATION_EOF' >"$TMP_UPDATE"
|
||||||
exit
|
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/addon/komodo.sh)"
|
||||||
}
|
MIGRATION_EOF
|
||||||
GITHUB_URL="https://raw.githubusercontent.com/moghtech/komodo/main/compose/${COMPOSE_BASENAME}"
|
mv "$TMP_UPDATE" /usr/bin/update
|
||||||
if ! curl -fsSL "$GITHUB_URL" -o "$COMPOSE_FILE"; then
|
chmod +x /usr/bin/update
|
||||||
msg_error "Failed to download ${COMPOSE_BASENAME} from GitHub!"
|
|
||||||
mv "$BACKUP_FILE" "$COMPOSE_FILE"
|
ln -sf /usr/bin/update /usr/bin/update_komodo 2>/dev/null || true
|
||||||
exit
|
msg_ok "Migration complete"
|
||||||
fi
|
|
||||||
$STD docker compose -p komodo -f "$COMPOSE_FILE" --env-file /opt/komodo/compose.env pull
|
msg_info "Running addon update"
|
||||||
$STD docker compose -p komodo -f "$COMPOSE_FILE" --env-file /opt/komodo/compose.env up -d
|
type=update bash <(curl -fsSL "${ADDON_SCRIPT}")
|
||||||
msg_ok "Updated Alpine-Komodo"
|
exit
|
||||||
msg_ok "Updated successfully!"
|
|
||||||
exit 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
start
|
start
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxV
|
|||||||
# Copyright (c) 2021-2026 community-scripts ORG
|
# Copyright (c) 2021-2026 community-scripts ORG
|
||||||
# Author: MickLesk (CanbiZ)
|
# Author: MickLesk (CanbiZ)
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
# Source: https://mariadb.org
|
# Source: https://mariadb.org/
|
||||||
|
|
||||||
APP="Alpine-MariaDB"
|
APP="Alpine-MariaDB"
|
||||||
var_tags="${var_tags:-alpine;database}"
|
var_tags="${var_tags:-alpine;database}"
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxV
|
|||||||
# Copyright (c) 2021-2026 community-scripts ORG
|
# Copyright (c) 2021-2026 community-scripts ORG
|
||||||
# Author: MickLesk (CanbiZ)
|
# Author: MickLesk (CanbiZ)
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
# Source: https://nodered.org
|
# Source: https://nodered.org/
|
||||||
|
|
||||||
APP="Alpine-Node-RED"
|
APP="Alpine-Node-RED"
|
||||||
var_tags="${var_tags:-alpine;automation}"
|
var_tags="${var_tags:-alpine;automation}"
|
||||||
@@ -31,6 +31,10 @@ function update_script() {
|
|||||||
msg_info "Updating Node-RED"
|
msg_info "Updating Node-RED"
|
||||||
$STD npm install -g --unsafe-perm node-red
|
$STD npm install -g --unsafe-perm node-red
|
||||||
msg_ok "Updated Node-RED"
|
msg_ok "Updated Node-RED"
|
||||||
|
|
||||||
|
msg_info "Restarting Node-RED"
|
||||||
|
$STD rc-service nodered restart
|
||||||
|
msg_ok "Restarted Node-RED"
|
||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
exit 0
|
exit 0
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
#!/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: cobalt (cobaltgit)
|
||||||
|
# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE
|
||||||
|
# Source: https://ntfy.sh/
|
||||||
|
|
||||||
|
APP="Alpine-ntfy"
|
||||||
|
var_tags="${var_tags:-notification}"
|
||||||
|
var_cpu="${var_cpu:-1}"
|
||||||
|
var_ram="${var_ram:-256}"
|
||||||
|
var_disk="${var_disk:-2}"
|
||||||
|
var_os="${var_os:-alpine}"
|
||||||
|
var_version="${var_version:-3.23}"
|
||||||
|
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 /etc/ntfy ]]; then
|
||||||
|
msg_error "No ${APP} Installation Found!"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
msg_info "Updating ntfy LXC"
|
||||||
|
$STD apk -U upgrade
|
||||||
|
setcap 'cap_net_bind_service=+ep' /usr/bin/ntfy
|
||||||
|
msg_ok "Updated ntfy LXC"
|
||||||
|
|
||||||
|
msg_info "Restarting ntfy"
|
||||||
|
rc-service ntfy restart
|
||||||
|
msg_ok "Restarted ntfy"
|
||||||
|
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}"
|
||||||
|
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||||
|
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}${CL}"
|
||||||
@@ -3,7 +3,7 @@ source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxV
|
|||||||
# Copyright (c) 2021-2026 community-scripts ORG
|
# Copyright (c) 2021-2026 community-scripts ORG
|
||||||
# Author: MickLesk (CanbiZ)
|
# Author: MickLesk (CanbiZ)
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
# Source: https://postgresql.org/
|
# Source: https://www.postgresql.org/
|
||||||
|
|
||||||
APP="Alpine-PostgreSQL"
|
APP="Alpine-PostgreSQL"
|
||||||
var_tags="${var_tags:-alpine;database}"
|
var_tags="${var_tags:-alpine;database}"
|
||||||
|
|||||||
@@ -27,21 +27,21 @@ function update_script() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
APIRELEASE=$(curl -s https://api.github.com/repos/lejianwen/rustdesk-api/releases/latest | grep "tag_name" | awk '{print substr($2, 3, length($2)-4) }')
|
APIRELEASE=$(curl -s https://api.github.com/repos/lejianwen/rustdesk-api/releases/latest | grep "tag_name" | awk '{print substr($2, 3, length($2)-4) }')
|
||||||
RELEASE=$(curl -s https://api.github.com/repos/rustdesk/rustdesk-server/releases/latest | grep "tag_name" | awk '{print substr($2, 2, length($2)-3) }')
|
RELEASE=$(curl -s https://api.github.com/repos/lejianwen/rustdesk-server/releases/latest | grep "tag_name" | awk '{print substr($2, 2, length($2)-3) }')
|
||||||
if [ "${RELEASE}" != "$(cat ~/.rustdesk-server 2>/dev/null)" ] || [ ! -f ~/.rustdesk-server ]; then
|
if [ "${RELEASE}" != "$(cat ~/.rustdesk-server 2>/dev/null)" ] || [ ! -f ~/.rustdesk-server ]; then
|
||||||
msg_info "Updating RustDesk Server to v${RELEASE}"
|
msg_info "Updating RustDesk Server to v${RELEASE}"
|
||||||
$STD apk -U upgrade
|
$STD apk -U upgrade
|
||||||
$STD service rustdesk-server-hbbs stop
|
$STD service rustdesk-server-hbbs stop
|
||||||
$STD service rustdesk-server-hbbr stop
|
$STD service rustdesk-server-hbbr stop
|
||||||
temp_file1=$(mktemp)
|
temp_file1=$(mktemp)
|
||||||
curl -fsSL "https://github.com/rustdesk/rustdesk-server/releases/download/${RELEASE}/rustdesk-server-linux-amd64.zip" -o "$temp_file1"
|
curl -fsSL "https://github.com/lejianwen/rustdesk-server/releases/download/${RELEASE}/rustdesk-server-linux-amd64.zip" -o "$temp_file1"
|
||||||
$STD unzip "$temp_file1"
|
$STD unzip "$temp_file1"
|
||||||
cp -r amd64/* /opt/rustdesk-server/
|
cp -r amd64/* /opt/rustdesk-server/
|
||||||
echo "${RELEASE}" >~/.rustdesk-server
|
echo "${RELEASE}" >~/.rustdesk-server
|
||||||
$STD service rustdesk-server-hbbs start
|
$STD service rustdesk-server-hbbs start
|
||||||
$STD service rustdesk-server-hbbr start
|
$STD service rustdesk-server-hbbr start
|
||||||
rm -rf amd64
|
rm -rf amd64
|
||||||
rm -f $temp_file1
|
rm -f "$temp_file1"
|
||||||
msg_ok "Updated RustDesk Server"
|
msg_ok "Updated RustDesk Server"
|
||||||
else
|
else
|
||||||
msg_ok "No update required. ${APP} is already at v${RELEASE}"
|
msg_ok "No update required. ${APP} is already at v${RELEASE}"
|
||||||
@@ -56,7 +56,7 @@ function update_script() {
|
|||||||
echo "${APIRELEASE}" >~/.rustdesk-api
|
echo "${APIRELEASE}" >~/.rustdesk-api
|
||||||
$STD service rustdesk-api start
|
$STD service rustdesk-api start
|
||||||
rm -rf release
|
rm -rf release
|
||||||
rm -f $temp_file2
|
rm -f "$temp_file2"
|
||||||
msg_ok "Updated RustDesk API"
|
msg_ok "Updated RustDesk API"
|
||||||
else
|
else
|
||||||
msg_ok "No update required. RustDesk API is already at v${APIRELEASE}"
|
msg_ok "No update required. RustDesk API is already at v${APIRELEASE}"
|
||||||
|
|||||||
@@ -35,6 +35,20 @@ function update_script() {
|
|||||||
$STD service tinyauth stop
|
$STD service tinyauth stop
|
||||||
msg_ok "Service Stopped"
|
msg_ok "Service Stopped"
|
||||||
|
|
||||||
|
if [[ -f /opt/tinyauth/.env ]] && ! grep -q "^TINYAUTH_" /opt/tinyauth/.env; then
|
||||||
|
msg_info "Migrating .env to v5 format"
|
||||||
|
sed -i \
|
||||||
|
-e 's/^DATABASE_PATH=/TINYAUTH_DATABASE_PATH=/' \
|
||||||
|
-e 's/^USERS=/TINYAUTH_AUTH_USERS=/' \
|
||||||
|
-e "s/^USERS='/TINYAUTH_AUTH_USERS='/" \
|
||||||
|
-e 's/^APP_URL=/TINYAUTH_APPURL=/' \
|
||||||
|
-e 's/^SECRET=/TINYAUTH_AUTH_SECRET=/' \
|
||||||
|
-e 's/^PORT=/TINYAUTH_SERVER_PORT=/' \
|
||||||
|
-e 's/^ADDRESS=/TINYAUTH_SERVER_ADDRESS=/' \
|
||||||
|
/opt/tinyauth/.env
|
||||||
|
msg_ok "Migrated .env to v5 format"
|
||||||
|
fi
|
||||||
|
|
||||||
msg_info "Updating Tinyauth"
|
msg_info "Updating Tinyauth"
|
||||||
rm -f /opt/tinyauth/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/steveiliop56/tinyauth/releases/download/v${RELEASE}/tinyauth-amd64" -o /opt/tinyauth/tinyauth
|
||||||
|
|||||||
@@ -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: Slaviša Arežina (tremor021)
|
||||||
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
|
# Source: https://wakapi.dev/ | https://github.com/muety/wakapi
|
||||||
|
|
||||||
|
APP="Alpine-Wakapi"
|
||||||
|
var_tags="${var_tags:-code;time-tracking}"
|
||||||
|
var_cpu="${var_cpu:-1}"
|
||||||
|
var_ram="${var_ram:-512}"
|
||||||
|
var_disk="${var_disk:-4}"
|
||||||
|
var_os="${var_os:-alpine}"
|
||||||
|
var_version="${var_version:-3.23}"
|
||||||
|
var_unprivileged="${var_unprivileged:-1}"
|
||||||
|
|
||||||
|
header_info "$APP"
|
||||||
|
variables
|
||||||
|
color
|
||||||
|
catch_errors
|
||||||
|
|
||||||
|
function update_script() {
|
||||||
|
header_info
|
||||||
|
if [[ ! -d /opt/wakapi ]]; then
|
||||||
|
msg_error "No ${APP} Installation Found!"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
RELEASE=$(curl -s https://api.github.com/repos/muety/wakapi/releases/latest | grep "tag_name" | awk '{print substr($2, 2, length($2)-3) }')
|
||||||
|
if [ "${RELEASE}" != "$(cat ~/.wakapi 2>/dev/null)" ] || [ ! -f ~/.wakapi ]; then
|
||||||
|
msg_info "Stopping Wakapi Service"
|
||||||
|
$STD rc-service wakapi stop
|
||||||
|
msg_ok "Stopped Wakapi Service"
|
||||||
|
|
||||||
|
msg_info "Updating Wakapi LXC"
|
||||||
|
$STD apk -U upgrade
|
||||||
|
msg_ok "Updated Wakapi LXC"
|
||||||
|
|
||||||
|
msg_info "Creating backup"
|
||||||
|
mkdir -p /opt/wakapi-backup
|
||||||
|
cp /opt/wakapi/config.yml /opt/wakapi/wakapi_db.db /opt/wakapi-backup/
|
||||||
|
msg_ok "Created backup"
|
||||||
|
|
||||||
|
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "wakapi" "muety/wakapi" "prebuild" "latest" "/opt/wakapi" "wakapi_linux_amd64.zip"
|
||||||
|
|
||||||
|
msg_info "Configuring Wakapi"
|
||||||
|
cd /opt/wakapi
|
||||||
|
cp /opt/wakapi-backup/config.yml /opt/wakapi/
|
||||||
|
cp /opt/wakapi-backup/wakapi_db.db /opt/wakapi/
|
||||||
|
rm -rf /opt/wakapi-backup
|
||||||
|
msg_ok "Configured Wakapi"
|
||||||
|
|
||||||
|
msg_info "Starting Service"
|
||||||
|
$STD rc-service wakapi start
|
||||||
|
msg_ok "Started Service"
|
||||||
|
msg_ok "Updated successfully"
|
||||||
|
else
|
||||||
|
msg_ok "No update required. ${APP} is already at ${RELEASE}"
|
||||||
|
fi
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
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}"
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
#!/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_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"
|
||||||
|
|
||||||
|
msg_info "Backing up Configuration"
|
||||||
|
cp /opt/anchor/.env /opt/anchor.env.bak
|
||||||
|
msg_ok "Backed up Configuration"
|
||||||
|
|
||||||
|
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"
|
||||||
|
|
||||||
|
cp /opt/anchor.env.bak /opt/anchor/.env
|
||||||
|
rm -f /opt/anchor.env.bak
|
||||||
|
|
||||||
|
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 "${TAB}${GATEWAY}${BGN}http://${IP}:3000${CL}"
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
#!/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://anytype.io
|
||||||
|
|
||||||
|
APP="Anytype-Server"
|
||||||
|
var_tags="${var_tags:-notes;productivity;sync}"
|
||||||
|
var_cpu="${var_cpu:-2}"
|
||||||
|
var_ram="${var_ram:-4096}"
|
||||||
|
var_disk="${var_disk:-16}"
|
||||||
|
var_os="${var_os:-ubuntu}"
|
||||||
|
var_version="${var_version:-24.04}"
|
||||||
|
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/anytype/any-sync-bundle ]]; then
|
||||||
|
msg_error "No ${APP} Installation Found!"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
if check_for_gh_release "anytype" "grishy/any-sync-bundle"; then
|
||||||
|
msg_info "Stopping Service"
|
||||||
|
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"
|
||||||
|
|
||||||
|
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"
|
||||||
|
|
||||||
|
msg_info "Starting Service"
|
||||||
|
systemctl start anytype
|
||||||
|
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 "${TAB}${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}"
|
||||||
+1
-1
@@ -3,7 +3,7 @@ source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxV
|
|||||||
# Copyright (c) 2021-2026 tteck
|
# Copyright (c) 2021-2026 tteck
|
||||||
# Author: tteck
|
# Author: tteck
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
# Source: https://archivebox.io/
|
# Source: https://archivebox.io/ | Github: https://github.com/ArchiveBox/ArchiveBox
|
||||||
|
|
||||||
APP="ArchiveBox"
|
APP="ArchiveBox"
|
||||||
var_tags="${var_tags:-archive;bookmark}"
|
var_tags="${var_tags:-archive;bookmark}"
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@ source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxV
|
|||||||
# Copyright (c) 2021-2026 community-scripts ORG
|
# Copyright (c) 2021-2026 community-scripts ORG
|
||||||
# Author: MickLesk (CanbiZ)
|
# Author: MickLesk (CanbiZ)
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
# Source: https://release-argus.io/
|
# Source: https://release-argus.io/ | Github: https://github.com/release-argus/Argus
|
||||||
|
|
||||||
APP="Argus"
|
APP="Argus"
|
||||||
var_tags="${var_tags:-watcher}"
|
var_tags="${var_tags:-watcher}"
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@ source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxV
|
|||||||
# Copyright (c) 2021-2026 tteck
|
# Copyright (c) 2021-2026 tteck
|
||||||
# Author: tteck (tteckster)
|
# Author: tteck (tteckster)
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
# Source: https://aria2.github.io/
|
# Source: https://aria2.github.io/ | Github: https://github.com/aria2/aria2
|
||||||
|
|
||||||
APP="Aria2"
|
APP="Aria2"
|
||||||
var_tags="${var_tags:-download-utility}"
|
var_tags="${var_tags:-download-utility}"
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@ source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxV
|
|||||||
# Copyright (c) 2021-2026 community-scripts ORG
|
# Copyright (c) 2021-2026 community-scripts ORG
|
||||||
# Author: michelroegl-brunner
|
# Author: michelroegl-brunner
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
# Source: https://asterisk.org/
|
# Source: https://asterisk.org
|
||||||
|
|
||||||
APP="Asterisk"
|
APP="Asterisk"
|
||||||
var_tags="${var_tags:-telephone;pbx}"
|
var_tags="${var_tags:-telephone;pbx}"
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@ source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxV
|
|||||||
# Copyright (c) 2021-2026 community-scripts ORG
|
# Copyright (c) 2021-2026 community-scripts ORG
|
||||||
# Author: thost96 (thost96)
|
# Author: thost96 (thost96)
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
# Source: https://www.authelia.com/
|
# Source: https://www.authelia.com/ | Github: https://github.com/authelia/authelia
|
||||||
|
|
||||||
APP="Authelia"
|
APP="Authelia"
|
||||||
var_tags="${var_tags:-authenticator}"
|
var_tags="${var_tags:-authenticator}"
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@ source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxV
|
|||||||
# Copyright (c) 2021-2026 tteck
|
# Copyright (c) 2021-2026 tteck
|
||||||
# Author: tteck (tteckster)
|
# Author: tteck (tteckster)
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
# Source: https://autobrr.com/
|
# Source: https://autobrr.com/ | Github: https://github.com/autobrr/autobrr
|
||||||
|
|
||||||
APP="Autobrr"
|
APP="Autobrr"
|
||||||
var_tags="${var_tags:-arr;}"
|
var_tags="${var_tags:-arr;}"
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ function update_script() {
|
|||||||
mv /tmp/production.py.bak /opt/babybuddy/babybuddy/settings/production.py
|
mv /tmp/production.py.bak /opt/babybuddy/babybuddy/settings/production.py
|
||||||
source .venv/bin/activate
|
source .venv/bin/activate
|
||||||
$STD uv pip install -r requirements.txt
|
$STD uv pip install -r requirements.txt
|
||||||
|
export DJANGO_SETTINGS_MODULE=babybuddy.settings.production
|
||||||
$STD python manage.py migrate
|
$STD python manage.py migrate
|
||||||
msg_ok "Updated ${APP}"
|
msg_ok "Updated ${APP}"
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@ source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxV
|
|||||||
# Copyright (c) 2021-2026 community-scripts ORG
|
# Copyright (c) 2021-2026 community-scripts ORG
|
||||||
# Author: ksad (enirys31)
|
# Author: ksad (enirys31)
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
# Source: https://garethgeorge.github.io/backrest/
|
# Source: https://garethgeorge.github.io/backrest/ | Github: https://github.com/garethgeorge/backrest
|
||||||
|
|
||||||
APP="Backrest"
|
APP="Backrest"
|
||||||
var_tags="${var_tags:-backup}"
|
var_tags="${var_tags:-backup}"
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@ source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxV
|
|||||||
# Copyright (c) 2021-2026 community-scripts ORG
|
# Copyright (c) 2021-2026 community-scripts ORG
|
||||||
# Author: bvdberg01
|
# Author: bvdberg01
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
# Source: https://sabre.io/baikal/
|
# Source: https://sabre.io/baikal/ | Github: https://github.com/sabre-io/Baikal
|
||||||
|
|
||||||
APP="Baikal"
|
APP="Baikal"
|
||||||
var_tags="${var_tags:-Dav}"
|
var_tags="${var_tags:-Dav}"
|
||||||
|
|||||||
@@ -0,0 +1,90 @@
|
|||||||
|
#!/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: Adrian-RDA
|
||||||
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
|
# Source: https://github.com/maziggy/bambuddy
|
||||||
|
|
||||||
|
APP="Bambuddy"
|
||||||
|
var_tags="${var_tags:-media;3d-printing}"
|
||||||
|
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_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/bambuddy ]]; then
|
||||||
|
msg_error "No ${APP} Installation Found!"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
ensure_dependencies ffmpeg
|
||||||
|
|
||||||
|
if check_for_gh_release "bambuddy" "maziggy/bambuddy"; then
|
||||||
|
msg_info "Stopping Service"
|
||||||
|
systemctl stop bambuddy
|
||||||
|
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
|
||||||
|
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 --clear
|
||||||
|
$STD uv pip install -r requirements.txt
|
||||||
|
msg_ok "Updated Python Dependencies"
|
||||||
|
|
||||||
|
msg_info "Rebuilding Frontend"
|
||||||
|
cd /opt/bambuddy/frontend
|
||||||
|
$STD npm install
|
||||||
|
$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"
|
||||||
|
|
||||||
|
msg_info "Starting Service"
|
||||||
|
systemctl start bambuddy
|
||||||
|
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 "${TAB}${GATEWAY}${BGN}http://${IP}:8000${CL}"
|
||||||
+1
-1
@@ -3,7 +3,7 @@ source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxV
|
|||||||
# Copyright (c) 2021-2026 tteck
|
# Copyright (c) 2021-2026 tteck
|
||||||
# Author: tteck (tteckster)
|
# Author: tteck (tteckster)
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
# Source: https://www.bazarr.media/
|
# Source: https://www.bazarr.media/ | Github: https://github.com/morpheus65535/bazarr
|
||||||
|
|
||||||
APP="Bazarr"
|
APP="Bazarr"
|
||||||
var_tags="${var_tags:-arr}"
|
var_tags="${var_tags:-arr}"
|
||||||
|
|||||||
+100
-3
@@ -7,7 +7,7 @@ source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxV
|
|||||||
|
|
||||||
APP="BentoPDF"
|
APP="BentoPDF"
|
||||||
var_tags="${var_tags:-pdf-editor}"
|
var_tags="${var_tags:-pdf-editor}"
|
||||||
var_cpu="${var_cpu:-1}"
|
var_cpu="${var_cpu:-2}"
|
||||||
var_ram="${var_ram:-4096}"
|
var_ram="${var_ram:-4096}"
|
||||||
var_disk="${var_disk:-4}"
|
var_disk="${var_disk:-4}"
|
||||||
var_os="${var_os:-debian}"
|
var_os="${var_os:-debian}"
|
||||||
@@ -35,16 +35,113 @@ function update_script() {
|
|||||||
systemctl stop bentopdf
|
systemctl stop bentopdf
|
||||||
msg_ok "Stopped Service"
|
msg_ok "Stopped Service"
|
||||||
|
|
||||||
|
[[ -f /opt/bentopdf/.env.production ]] && cp /opt/bentopdf/.env.production /opt/production.env
|
||||||
|
|
||||||
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "bentopdf" "alam00000/bentopdf" "tarball" "latest" "/opt/bentopdf"
|
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "bentopdf" "alam00000/bentopdf" "tarball" "latest" "/opt/bentopdf"
|
||||||
|
|
||||||
msg_info "Updating BentoPDF"
|
msg_info "Updating BentoPDF"
|
||||||
cd /opt/bentopdf
|
cd /opt/bentopdf
|
||||||
$STD npm ci --no-audit --no-fund
|
$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 SIMPLE_MODE=true
|
||||||
$STD npm run build -- --mode production
|
export VITE_USE_CDN=true
|
||||||
|
$STD npm run build:all
|
||||||
|
if [[ ! -f /opt/bentopdf/dist/config.json ]]; then
|
||||||
|
cat <<'EOF' >/opt/bentopdf/dist/config.json
|
||||||
|
{}
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
msg_ok "Updated BentoPDF"
|
msg_ok "Updated BentoPDF"
|
||||||
|
|
||||||
msg_info "Starting Service"
|
msg_info "Starting Service"
|
||||||
|
ensure_dependencies nginx openssl
|
||||||
|
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}"
|
||||||
|
fi
|
||||||
|
cat <<'EOF' >/etc/nginx/sites-available/bentopdf
|
||||||
|
server {
|
||||||
|
listen 8080;
|
||||||
|
server_name _;
|
||||||
|
return 301 https://$host:8443$request_uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 8443 ssl;
|
||||||
|
server_name _;
|
||||||
|
ssl_certificate /etc/ssl/certs/bentopdf-selfsigned.crt;
|
||||||
|
ssl_certificate_key /etc/ssl/private/bentopdf-selfsigned.key;
|
||||||
|
root /opt/bentopdf/dist;
|
||||||
|
index index.html;
|
||||||
|
|
||||||
|
# Required for LibreOffice WASM (Word/Excel/PowerPoint to PDF via SharedArrayBuffer)
|
||||||
|
add_header Cross-Origin-Opener-Policy "same-origin" always;
|
||||||
|
add_header Cross-Origin-Embedder-Policy "require-corp" always;
|
||||||
|
add_header Cross-Origin-Resource-Policy "cross-origin" always;
|
||||||
|
add_header X-Content-Type-Options "nosniff" always;
|
||||||
|
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||||
|
|
||||||
|
gzip_static on;
|
||||||
|
|
||||||
|
location ~* /libreoffice-wasm/soffice\.wasm\.gz$ {
|
||||||
|
gzip off;
|
||||||
|
types {} default_type application/wasm;
|
||||||
|
add_header Content-Encoding gzip;
|
||||||
|
add_header Vary "Accept-Encoding";
|
||||||
|
add_header Cache-Control "public, immutable";
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~* /libreoffice-wasm/soffice\.data\.gz$ {
|
||||||
|
gzip off;
|
||||||
|
types {} default_type application/octet-stream;
|
||||||
|
add_header Content-Encoding gzip;
|
||||||
|
add_header Vary "Accept-Encoding";
|
||||||
|
add_header Cache-Control "public, immutable";
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~* \.wasm$ {
|
||||||
|
types {} default_type application/wasm;
|
||||||
|
expires 1y;
|
||||||
|
add_header Cache-Control "public, immutable";
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~* \.(wasm\.gz|data\.gz|data)$ {
|
||||||
|
expires 1y;
|
||||||
|
add_header Cache-Control "public, immutable";
|
||||||
|
}
|
||||||
|
|
||||||
|
location / {
|
||||||
|
try_files $uri $uri/ $uri.html =404;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_page 404 /404.html;
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
rm -f /etc/nginx/sites-enabled/default
|
||||||
|
ln -sf /etc/nginx/sites-available/bentopdf /etc/nginx/sites-enabled/bentopdf
|
||||||
|
cat <<'EOF' >/etc/systemd/system/bentopdf.service
|
||||||
|
[Unit]
|
||||||
|
Description=BentoPDF Service
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
ExecStart=/usr/sbin/nginx -g "daemon off;"
|
||||||
|
ExecReload=/bin/kill -HUP $MAINPID
|
||||||
|
Restart=always
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF
|
||||||
|
systemctl daemon-reload
|
||||||
systemctl start bentopdf
|
systemctl start bentopdf
|
||||||
msg_ok "Started Service"
|
msg_ok "Started Service"
|
||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
@@ -59,4 +156,4 @@ description
|
|||||||
msg_ok "Completed successfully!\n"
|
msg_ok "Completed successfully!\n"
|
||||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:8080${CL}"
|
echo -e "${TAB}${GATEWAY}${BGN}https://${IP}:8443${CL}"
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@ source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxV
|
|||||||
# Copyright (c) 2021-2026 community-scripts ORG
|
# Copyright (c) 2021-2026 community-scripts ORG
|
||||||
# Author: Michelle Zitzerman (Sinofage)
|
# Author: Michelle Zitzerman (Sinofage)
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
# Source: https://beszel.dev/
|
# Source: https://beszel.dev/ | Github: https://github.com/henrygd/beszel
|
||||||
|
|
||||||
APP="Beszel"
|
APP="Beszel"
|
||||||
var_tags="${var_tags:-monitoring}"
|
var_tags="${var_tags:-monitoring}"
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
#!/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/tphakala/birdnet-go
|
||||||
|
|
||||||
|
APP="BirdNET-Go"
|
||||||
|
var_tags="${var_tags:-monitoring;ai;nature}"
|
||||||
|
var_cpu="${var_cpu:-4}"
|
||||||
|
var_ram="${var_ram:-2048}"
|
||||||
|
var_disk="${var_disk:-12}"
|
||||||
|
var_os="${var_os:-debian}"
|
||||||
|
var_version="${var_version:-13}"
|
||||||
|
var_unprivileged="${var_unprivileged:-1}"
|
||||||
|
var_gpu="${var_gpu:-no}"
|
||||||
|
|
||||||
|
header_info "$APP"
|
||||||
|
variables
|
||||||
|
color
|
||||||
|
catch_errors
|
||||||
|
|
||||||
|
function update_script() {
|
||||||
|
header_info
|
||||||
|
check_container_storage
|
||||||
|
check_container_resources
|
||||||
|
|
||||||
|
if [[ ! -f /usr/local/bin/birdnet-go ]]; then
|
||||||
|
msg_error "No ${APP} Installation Found!"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
if check_for_gh_release "birdnet" "tphakala/birdnet-go"; then
|
||||||
|
msg_info "Stopping Service"
|
||||||
|
systemctl stop birdnet
|
||||||
|
msg_ok "Stopped Service"
|
||||||
|
|
||||||
|
fetch_and_deploy_gh_release "birdnet" "tphakala/birdnet-go" "prebuild" "latest" "/opt/birdnet" "birdnet-go-linux-amd64.tar.gz"
|
||||||
|
|
||||||
|
msg_info "Deploying Binary"
|
||||||
|
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
|
||||||
|
ldconfig
|
||||||
|
msg_ok "Deployed Binary"
|
||||||
|
|
||||||
|
msg_info "Starting Service"
|
||||||
|
systemctl start birdnet
|
||||||
|
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 "${TAB}${GATEWAY}${BGN}http://${IP}:8080${CL}"
|
||||||
+1
-1
@@ -3,7 +3,7 @@ source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxV
|
|||||||
# Copyright (c) 2021-2026 community-scripts ORG
|
# Copyright (c) 2021-2026 community-scripts ORG
|
||||||
# Author: Slaviša Arežina (tremor021)
|
# Author: Slaviša Arežina (tremor021)
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
# Source: https://github.com/bitmagnet/bitmagnet
|
# Source: https://github.com/bitmagnet-io/bitmagnet
|
||||||
|
|
||||||
APP="Bitmagnet"
|
APP="Bitmagnet"
|
||||||
var_tags="${var_tags:-os}"
|
var_tags="${var_tags:-os}"
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@ source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxV
|
|||||||
# Copyright (c) 2021-2026 tteck
|
# Copyright (c) 2021-2026 tteck
|
||||||
# Author: tteck (tteckster)
|
# Author: tteck (tteckster)
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
# Source: https://0xerr0r.github.io/blocky
|
# Source: https://0xerr0r.github.io/blocky | Github: https://github.com/0xERR0R/blocky
|
||||||
|
|
||||||
APP="Blocky"
|
APP="Blocky"
|
||||||
var_tags="${var_tags:-adblock}"
|
var_tags="${var_tags:-adblock}"
|
||||||
|
|||||||
-112
@@ -1,112 +0,0 @@
|
|||||||
#!/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/booklore-app/BookLore
|
|
||||||
|
|
||||||
APP="BookLore"
|
|
||||||
var_tags="${var_tags:-books;library}"
|
|
||||||
var_cpu="${var_cpu:-3}"
|
|
||||||
var_ram="${var_ram:-3072}"
|
|
||||||
var_disk="${var_disk:-7}"
|
|
||||||
var_os="${var_os:-debian}"
|
|
||||||
var_version="${var_version:-13}"
|
|
||||||
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/booklore ]]; then
|
|
||||||
msg_error "No ${APP} Installation Found!"
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
|
|
||||||
if check_for_gh_release "booklore" "booklore-app/BookLore"; then
|
|
||||||
JAVA_VERSION="25" setup_java
|
|
||||||
NODE_VERSION="22" setup_nodejs
|
|
||||||
setup_mariadb
|
|
||||||
setup_yq
|
|
||||||
|
|
||||||
msg_info "Stopping Service"
|
|
||||||
systemctl stop booklore
|
|
||||||
msg_ok "Stopped Service"
|
|
||||||
|
|
||||||
if grep -qE "^BOOKLORE_(DATA_PATH|BOOKDROP_PATH|BOOKS_PATH|PORT)=" /opt/booklore_storage/.env 2>/dev/null; then
|
|
||||||
msg_info "Migrating old environment variables"
|
|
||||||
sed -i 's/^BOOKLORE_DATA_PATH=/APP_PATH_CONFIG=/g' /opt/booklore_storage/.env
|
|
||||||
sed -i 's/^BOOKLORE_BOOKDROP_PATH=/APP_BOOKDROP_FOLDER=/g' /opt/booklore_storage/.env
|
|
||||||
sed -i '/^BOOKLORE_BOOKS_PATH=/d' /opt/booklore_storage/.env
|
|
||||||
sed -i '/^BOOKLORE_PORT=/d' /opt/booklore_storage/.env
|
|
||||||
msg_ok "Migrated old environment variables"
|
|
||||||
fi
|
|
||||||
|
|
||||||
msg_info "Backing up old installation"
|
|
||||||
mv /opt/booklore /opt/booklore_bak
|
|
||||||
msg_ok "Backed up old installation"
|
|
||||||
|
|
||||||
fetch_and_deploy_gh_release "booklore" "booklore-app/BookLore" "tarball"
|
|
||||||
|
|
||||||
msg_info "Building Frontend"
|
|
||||||
cd /opt/booklore/booklore-ui
|
|
||||||
$STD npm install --force
|
|
||||||
$STD npm run build --configuration=production
|
|
||||||
msg_ok "Built Frontend"
|
|
||||||
|
|
||||||
msg_info "Embedding Frontend into Backend"
|
|
||||||
mkdir -p /opt/booklore/booklore-api/src/main/resources/static
|
|
||||||
cp -r /opt/booklore/booklore-ui/dist/booklore/browser/* /opt/booklore/booklore-api/src/main/resources/static/
|
|
||||||
msg_ok "Embedded Frontend into Backend"
|
|
||||||
|
|
||||||
msg_info "Building Backend"
|
|
||||||
cd /opt/booklore/booklore-api
|
|
||||||
APP_VERSION=$(get_latest_github_release "booklore-app/BookLore")
|
|
||||||
yq eval ".app.version = \"${APP_VERSION}\"" -i src/main/resources/application.yaml
|
|
||||||
$STD ./gradlew clean build -x test --no-daemon
|
|
||||||
mkdir -p /opt/booklore/dist
|
|
||||||
JAR_PATH=$(find /opt/booklore/booklore-api/build/libs -maxdepth 1 -type f -name "booklore-api-*.jar" ! -name "*plain*" | head -n1)
|
|
||||||
if [[ -z "$JAR_PATH" ]]; then
|
|
||||||
msg_error "Backend JAR not found"
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
cp "$JAR_PATH" /opt/booklore/dist/app.jar
|
|
||||||
msg_ok "Built Backend"
|
|
||||||
|
|
||||||
if systemctl is-active --quiet nginx 2>/dev/null; then
|
|
||||||
msg_info "Removing Nginx (no longer needed)"
|
|
||||||
systemctl disable --now nginx
|
|
||||||
$STD apt-get purge -y nginx nginx-common
|
|
||||||
msg_ok "Removed Nginx"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! grep -q "^SERVER_PORT=" /opt/booklore_storage/.env 2>/dev/null; then
|
|
||||||
echo "SERVER_PORT=6060" >>/opt/booklore_storage/.env
|
|
||||||
fi
|
|
||||||
|
|
||||||
sed -i 's|ExecStart=/usr/bin/java -jar|ExecStart=/usr/bin/java -XX:+UseG1GC -XX:+UseStringDeduplication -XX:+UseCompactObjectHeaders -jar|' /etc/systemd/system/booklore.service
|
|
||||||
systemctl daemon-reload
|
|
||||||
|
|
||||||
msg_info "Starting Service"
|
|
||||||
systemctl start booklore
|
|
||||||
rm -rf /opt/booklore_bak
|
|
||||||
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 "${TAB}${GATEWAY}${BGN}http://${IP}:6060${CL}"
|
|
||||||
@@ -29,6 +29,7 @@ function update_script() {
|
|||||||
exit
|
exit
|
||||||
fi
|
fi
|
||||||
setup_mariadb
|
setup_mariadb
|
||||||
|
ensure_dependencies git
|
||||||
if check_for_gh_release "bookstack" "BookStackApp/BookStack"; then
|
if check_for_gh_release "bookstack" "BookStackApp/BookStack"; then
|
||||||
msg_info "Stopping Apache2"
|
msg_info "Stopping Apache2"
|
||||||
systemctl stop apache2
|
systemctl stop apache2
|
||||||
|
|||||||
+33
-20
@@ -29,28 +29,41 @@ function update_script() {
|
|||||||
exit
|
exit
|
||||||
fi
|
fi
|
||||||
if check_for_gh_release "bytestash" "jordan-dalby/ByteStash"; then
|
if check_for_gh_release "bytestash" "jordan-dalby/ByteStash"; then
|
||||||
read -rp "${TAB3}Did you make a backup via application WebUI? (y/n): " backuped
|
msg_info "Stopping Services"
|
||||||
if [[ "$backuped" =~ ^[Yy]$ ]]; then
|
systemctl stop bytestash-backend bytestash-frontend
|
||||||
msg_info "Stopping Services"
|
msg_ok "Services Stopped"
|
||||||
systemctl stop bytestash-backend bytestash-frontend
|
|
||||||
msg_ok "Services Stopped"
|
|
||||||
|
|
||||||
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "bytestash" "jordan-dalby/ByteStash" "tarball"
|
msg_info "Backing up data"
|
||||||
|
tmp_dir="/opt/bytestash-data-backup"
|
||||||
msg_info "Configuring ByteStash"
|
mkdir -p "$tmp_dir"
|
||||||
cd /opt/bytestash/server
|
if [[ -d /opt/bytestash/data ]]; then
|
||||||
$STD npm install
|
cp -r /opt/bytestash/data "$tmp_dir"/data
|
||||||
cd /opt/bytestash/client
|
elif [[ -d /opt/data ]]; then
|
||||||
$STD npm install
|
cp -r /opt/data "$tmp_dir"/data
|
||||||
msg_ok "Updated ByteStash"
|
|
||||||
|
|
||||||
msg_info "Starting Services"
|
|
||||||
systemctl start bytestash-backend bytestash-frontend
|
|
||||||
msg_ok "Started Services"
|
|
||||||
else
|
|
||||||
msg_error "PLEASE MAKE A BACKUP FIRST!"
|
|
||||||
exit
|
|
||||||
fi
|
fi
|
||||||
|
msg_ok "Data backed up"
|
||||||
|
|
||||||
|
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "bytestash" "jordan-dalby/ByteStash" "tarball"
|
||||||
|
|
||||||
|
msg_info "Restoring data"
|
||||||
|
if [[ -d "$tmp_dir"/data ]]; then
|
||||||
|
mkdir -p /opt/bytestash/data
|
||||||
|
cp -r "$tmp_dir"/data/* /opt/bytestash/data/
|
||||||
|
rm -rf "$tmp_dir"
|
||||||
|
fi
|
||||||
|
msg_ok "Data restored"
|
||||||
|
|
||||||
|
msg_info "Configuring ByteStash"
|
||||||
|
cd /opt/bytestash/server
|
||||||
|
$STD npm install
|
||||||
|
cd /opt/bytestash/client
|
||||||
|
$STD npm install
|
||||||
|
msg_ok "Updated ByteStash"
|
||||||
|
|
||||||
|
msg_info "Starting Services"
|
||||||
|
systemctl start bytestash-backend bytestash-frontend
|
||||||
|
msg_ok "Started Services"
|
||||||
|
|
||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
fi
|
fi
|
||||||
exit
|
exit
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@ source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxV
|
|||||||
# Copyright (c) 2021-2026 tteck
|
# Copyright (c) 2021-2026 tteck
|
||||||
# Author: tteck (tteckster)
|
# Author: tteck (tteckster)
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
# Source: https://caddyserver.com/
|
# Source: https://caddyserver.com/ | Github: https://github.com/caddyserver/caddy
|
||||||
|
|
||||||
APP="Caddy"
|
APP="Caddy"
|
||||||
var_tags="${var_tags:-webserver}"
|
var_tags="${var_tags:-webserver}"
|
||||||
|
|||||||
+1
-1
@@ -44,7 +44,7 @@ function update_script() {
|
|||||||
|
|
||||||
msg_info "Installing Dependencies"
|
msg_info "Installing Dependencies"
|
||||||
cd /opt/calibre-web
|
cd /opt/calibre-web
|
||||||
$STD uv venv
|
$STD uv venv --clear /opt/calibre-web/.venv
|
||||||
$STD uv pip install --python /opt/calibre-web/.venv/bin/python --no-cache-dir --upgrade pip setuptools wheel
|
$STD uv pip install --python /opt/calibre-web/.venv/bin/python --no-cache-dir --upgrade pip setuptools wheel
|
||||||
$STD uv pip install --python /opt/calibre-web/.venv/bin/python --no-cache-dir -r requirements.txt
|
$STD uv pip install --python /opt/calibre-web/.venv/bin/python --no-cache-dir -r requirements.txt
|
||||||
msg_ok "Installed Dependencies"
|
msg_ok "Installed Dependencies"
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxV
|
|||||||
# Copyright (c) 2021-2026 tteck
|
# Copyright (c) 2021-2026 tteck
|
||||||
# Author: tteck (tteckster)
|
# Author: tteck (tteckster)
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
# Source: https://changedetection.io/
|
# Source: https://changedetection.io/ | Github: https://github.com/dgtlmoon/changedetection.io
|
||||||
|
|
||||||
APP="Change Detection"
|
APP="Change Detection"
|
||||||
var_tags="${var_tags:-monitoring;crawler}"
|
var_tags="${var_tags:-monitoring;crawler}"
|
||||||
@@ -34,11 +34,11 @@ function update_script() {
|
|||||||
NODE_VERSION="24" setup_nodejs
|
NODE_VERSION="24" setup_nodejs
|
||||||
|
|
||||||
msg_info "Updating ${APP}"
|
msg_info "Updating ${APP}"
|
||||||
$STD pip3 install changedetection.io --upgrade
|
$STD pip3 install changedetection.io --upgrade --break-system-packages --ignore-installed typing_extensions
|
||||||
msg_ok "Updated ${APP}"
|
msg_ok "Updated ${APP}"
|
||||||
|
|
||||||
msg_info "Updating Playwright"
|
msg_info "Updating Playwright"
|
||||||
$STD pip3 install playwright --upgrade
|
$STD pip3 install playwright --upgrade --break-system-packages
|
||||||
msg_ok "Updated Playwright"
|
msg_ok "Updated Playwright"
|
||||||
|
|
||||||
if [[ -f /etc/systemd/system/browserless.service ]]; then
|
if [[ -f /etc/systemd/system/browserless.service ]]; then
|
||||||
|
|||||||
+3
-2
@@ -11,7 +11,7 @@ var_cpu="${var_cpu:-2}"
|
|||||||
var_ram="${var_ram:-2048}"
|
var_ram="${var_ram:-2048}"
|
||||||
var_disk="${var_disk:-6}"
|
var_disk="${var_disk:-6}"
|
||||||
var_os="${var_os:-debian}"
|
var_os="${var_os:-debian}"
|
||||||
var_version="${var_version:-12}"
|
var_version="${var_version:-13}"
|
||||||
var_unprivileged="${var_unprivileged:-1}"
|
var_unprivileged="${var_unprivileged:-1}"
|
||||||
|
|
||||||
header_info "$APP"
|
header_info "$APP"
|
||||||
@@ -29,10 +29,11 @@ function update_script() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
RELEASE=$(curl -fsSL https://api.github.com/repos/checkmk/checkmk/tags | grep "name" | awk '{print substr($2, 3, length($2)-4) }' | tr ' ' '\n' | grep -Ev 'rc|b' | sort -V | tail -n 1)
|
RELEASE=$(curl -fsSL https://api.github.com/repos/checkmk/checkmk/tags | grep "name" | awk '{print substr($2, 3, length($2)-4) }' | tr ' ' '\n' | grep -Ev 'rc|b' | sort -V | tail -n 1)
|
||||||
|
RELEASE="${RELEASE%%+*}"
|
||||||
msg_info "Updating ${APP} to v${RELEASE}"
|
msg_info "Updating ${APP} to v${RELEASE}"
|
||||||
$STD omd stop monitoring
|
$STD omd stop monitoring
|
||||||
$STD omd cp monitoring monitoringbackup
|
$STD omd cp monitoring monitoringbackup
|
||||||
curl -fsSL "https://download.checkmk.com/checkmk/${RELEASE}/check-mk-raw-${RELEASE}_0.bookworm_amd64.deb" -o "/opt/checkmk.deb"
|
curl -fsSL "https://download.checkmk.com/checkmk/${RELEASE}/check-mk-raw-${RELEASE}_0.$(get_os_info codename)_amd64.deb" -o "/opt/checkmk.deb"
|
||||||
$STD apt-get install -y /opt/checkmk.deb
|
$STD apt-get install -y /opt/checkmk.deb
|
||||||
$STD omd --force -V ${RELEASE}.cre update --conflict=install monitoring
|
$STD omd --force -V ${RELEASE}.cre update --conflict=install monitoring
|
||||||
$STD omd start monitoring
|
$STD omd start monitoring
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@ source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxV
|
|||||||
# Copyright (c) 2021-2026 community-scripts ORG
|
# Copyright (c) 2021-2026 community-scripts ORG
|
||||||
# Author: MickLesk (CanbiZ)
|
# Author: MickLesk (CanbiZ)
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
# Source: https://cloudreve.org/
|
# Source: https://cloudreve.org/ | Github: https://github.com/cloudreve/cloudreve
|
||||||
|
|
||||||
APP="Cloudreve"
|
APP="Cloudreve"
|
||||||
var_tags="${var_tags:-cloud}"
|
var_tags="${var_tags:-cloud}"
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@ source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxV
|
|||||||
# Copyright (c) 2021-2026 tteck
|
# Copyright (c) 2021-2026 tteck
|
||||||
# Author: tteck | Co-Author: havardthom
|
# Author: tteck | Co-Author: havardthom
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
# Source: https://cockpit-project.org/
|
# Source: https://github.com/cockpit-project/cockpit
|
||||||
|
|
||||||
APP="Cockpit"
|
APP="Cockpit"
|
||||||
var_tags="${var_tags:-monitoring;network}"
|
var_tags="${var_tags:-monitoring;network}"
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@ source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxV
|
|||||||
# Copyright (c) 2021-2026 tteck
|
# Copyright (c) 2021-2026 tteck
|
||||||
# Author: tteck (tteckster)
|
# Author: tteck (tteckster)
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
# Source: https://www.commafeed.com/#/welcome
|
# Source: https://www.commafeed.com/#/welcome | Github: https://github.com/Athou/commafeed
|
||||||
|
|
||||||
APP="CommaFeed"
|
APP="CommaFeed"
|
||||||
var_tags="${var_tags:-rss-reader}"
|
var_tags="${var_tags:-rss-reader}"
|
||||||
|
|||||||
+3
-1
@@ -24,7 +24,7 @@ function update_script() {
|
|||||||
header_info
|
header_info
|
||||||
check_container_storage
|
check_container_storage
|
||||||
check_container_resources
|
check_container_resources
|
||||||
if [[ ! -d /var ]]; then
|
if [[ ! -d /opt/convertx ]]; then
|
||||||
msg_error "No ${APP} Installation Found!"
|
msg_error "No ${APP} Installation Found!"
|
||||||
exit
|
exit
|
||||||
fi
|
fi
|
||||||
@@ -33,6 +33,8 @@ function update_script() {
|
|||||||
systemctl stop convertx
|
systemctl stop convertx
|
||||||
msg_info "Stopped Service"
|
msg_info "Stopped Service"
|
||||||
|
|
||||||
|
ensure_dependencies libreoffice-writer
|
||||||
|
|
||||||
msg_info "Move data-Folder"
|
msg_info "Move data-Folder"
|
||||||
if [[ -d /opt/convertx/data ]]; then
|
if [[ -d /opt/convertx/data ]]; then
|
||||||
mv /opt/convertx/data /opt/data
|
mv /opt/convertx/data /opt/data
|
||||||
|
|||||||
+29
-4
@@ -19,6 +19,8 @@ variables
|
|||||||
color
|
color
|
||||||
catch_errors
|
catch_errors
|
||||||
|
|
||||||
|
ADDON_SCRIPT="https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/addon/coolify.sh"
|
||||||
|
|
||||||
function update_script() {
|
function update_script() {
|
||||||
header_info
|
header_info
|
||||||
check_container_storage
|
check_container_storage
|
||||||
@@ -29,10 +31,33 @@ function update_script() {
|
|||||||
exit
|
exit
|
||||||
fi
|
fi
|
||||||
|
|
||||||
msg_info "Updating Coolify"
|
msg_warn "⚠️ ${APP} has been migrated to an addon script."
|
||||||
$STD bash <(curl -fsSL https://cdn.coollabs.io/coolify/install.sh)
|
echo ""
|
||||||
msg_ok "Updated Coolify"
|
msg_info "This is a one-time migration. After this, you can update ${APP} anytime with:"
|
||||||
msg_ok "Updated successfully!"
|
echo -e "${TAB}${TAB}${GN}update_coolify${CL} or ${GN}bash <(curl -fsSL ${ADDON_SCRIPT})${CL}"
|
||||||
|
echo ""
|
||||||
|
read -r -p "${TAB}Migrate update function now? [y/N]: " CONFIRM
|
||||||
|
if [[ ! "${CONFIRM,,}" =~ ^(y|yes)$ ]]; then
|
||||||
|
msg_warn "Migration skipped. The old update will continue to work for now."
|
||||||
|
msg_info "Updating ${APP} (legacy)"
|
||||||
|
$STD bash <(curl -fsSL https://cdn.coollabs.io/coolify/install.sh)
|
||||||
|
msg_ok "Updated ${APP}"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
msg_info "Migrating update function"
|
||||||
|
TMP_UPDATE=$(mktemp)
|
||||||
|
cat <<'MIGRATION_EOF' >"$TMP_UPDATE"
|
||||||
|
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/addon/coolify.sh)"
|
||||||
|
MIGRATION_EOF
|
||||||
|
mv "$TMP_UPDATE" /usr/bin/update
|
||||||
|
chmod +x /usr/bin/update
|
||||||
|
|
||||||
|
ln -sf /usr/bin/update /usr/bin/update_coolify 2>/dev/null || true
|
||||||
|
msg_ok "Migration complete"
|
||||||
|
|
||||||
|
msg_info "Running addon update"
|
||||||
|
type=update bash <(curl -fsSL "${ADDON_SCRIPT}")
|
||||||
exit
|
exit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@ source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxV
|
|||||||
# Copyright (c) 2021-2026 community-scripts ORG
|
# Copyright (c) 2021-2026 community-scripts ORG
|
||||||
# Author: Michel Roegl-Brunner (michelroegl-brunner)
|
# Author: Michel Roegl-Brunner (michelroegl-brunner)
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
# Source: https://https://cosmos-cloud.io/
|
# Source: https://cosmos-cloud.io/ | Github: https://github.com/azukaar/Cosmos-Server
|
||||||
|
|
||||||
APP="Cosmos"
|
APP="Cosmos"
|
||||||
var_tags="${var_tags:-cloud;docker}"
|
var_tags="${var_tags:-cloud;docker}"
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxV
|
|||||||
# Copyright (c) 2021-2026 community-scripts ORG
|
# Copyright (c) 2021-2026 community-scripts ORG
|
||||||
# Author: CrazyWolf13
|
# Author: CrazyWolf13
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
# Source: https://gitlab.com/crafty-controller/crafty-4
|
# Source: https://docs.craftycontrol.com/pages/getting-started/installation/linux/
|
||||||
|
|
||||||
APP="Crafty-Controller"
|
APP="Crafty-Controller"
|
||||||
var_tags="${var_tags:-gaming}"
|
var_tags="${var_tags:-gaming}"
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@ source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxV
|
|||||||
# Copyright (c) 2021-2026 tteck
|
# Copyright (c) 2021-2026 tteck
|
||||||
# Author: tteck (tteckster)
|
# Author: tteck (tteckster)
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
# Source: https://cronicle.net/
|
# Source: https://cronicle.net/ | Github: https://github.com/jhuckaby/Cronicle
|
||||||
|
|
||||||
APP="Cronicle"
|
APP="Cronicle"
|
||||||
var_tags="${var_tags:-task-scheduler}"
|
var_tags="${var_tags:-task-scheduler}"
|
||||||
|
|||||||
+20
-17
@@ -3,7 +3,7 @@ source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxV
|
|||||||
# Copyright (c) 2021-2026 community-scripts ORG
|
# Copyright (c) 2021-2026 community-scripts ORG
|
||||||
# Author: Jakub Matraszek (jmatraszek)
|
# Author: Jakub Matraszek (jmatraszek)
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
# Source: https://www.cross-seed.org
|
# Source: https://www.cross-seed.org | Github: https://github.com/cross-seed/cross-seed
|
||||||
|
|
||||||
APP="cross-seed"
|
APP="cross-seed"
|
||||||
var_tags="${var_tags:-arr}"
|
var_tags="${var_tags:-arr}"
|
||||||
@@ -20,26 +20,29 @@ color
|
|||||||
catch_errors
|
catch_errors
|
||||||
|
|
||||||
function update_script() {
|
function update_script() {
|
||||||
header_info
|
header_info
|
||||||
check_container_storage
|
check_container_storage
|
||||||
check_container_resources
|
check_container_resources
|
||||||
|
|
||||||
if command -v cross-seed &>/dev/null; then
|
NODE_VERSION="24" setup_nodejs
|
||||||
current_version=$(cross-seed --version)
|
ensure_dependencies build-essential
|
||||||
latest_version=$(npm show cross-seed version)
|
|
||||||
if [ "$current_version" != "$latest_version" ]; then
|
if command -v cross-seed &>/dev/null; then
|
||||||
msg_info "Updating cross-seed from version v${current_version} to v${latest_version}"
|
current_version=$(cross-seed --version)
|
||||||
$STD npm install -g cross-seed@latest
|
latest_version=$(npm show cross-seed version)
|
||||||
systemctl restart cross-seed
|
if [ "$current_version" != "$latest_version" ]; then
|
||||||
msg_ok "Updated successfully!"
|
msg_info "Updating cross-seed from version v${current_version} to v${latest_version}"
|
||||||
else
|
$STD npm install -g cross-seed@latest
|
||||||
msg_ok "cross-seed is already at v${current_version}"
|
systemctl restart cross-seed
|
||||||
fi
|
msg_ok "Updated successfully!"
|
||||||
else
|
else
|
||||||
msg_error "No cross-seed Installation Found!"
|
msg_ok "cross-seed is already at v${current_version}"
|
||||||
exit
|
|
||||||
fi
|
fi
|
||||||
|
else
|
||||||
|
msg_error "No cross-seed Installation Found!"
|
||||||
exit
|
exit
|
||||||
|
fi
|
||||||
|
exit
|
||||||
}
|
}
|
||||||
|
|
||||||
start
|
start
|
||||||
|
|||||||
+11
-5
@@ -33,17 +33,23 @@ function update_script() {
|
|||||||
systemctl stop cryptpad
|
systemctl stop cryptpad
|
||||||
msg_info "Stopped Service"
|
msg_info "Stopped Service"
|
||||||
|
|
||||||
msg_info "Backing up configuration"
|
msg_info "Creating backup"
|
||||||
[ -f /opt/cryptpad/config/config.js ] && mv /opt/cryptpad/config/config.js /opt/
|
[ -f /opt/cryptpad/config/config.js ] && mv /opt/cryptpad/config/config.js /opt/
|
||||||
msg_ok "Backed up configuration"
|
for dir in blob block customize data datastore www/common/onlyoffice/dist onlyoffice-conf; do
|
||||||
|
[ -d "/opt/cryptpad/${dir}" ] && mv "/opt/cryptpad/${dir}" "/tmp/cryptpad_${dir//\//_}"
|
||||||
|
done
|
||||||
|
msg_ok "Created backup"
|
||||||
|
|
||||||
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "cryptpad" "cryptpad/cryptpad" "tarball"
|
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "cryptpad" "cryptpad/cryptpad" "tarball"
|
||||||
|
|
||||||
msg_info "Restoring configuration"
|
msg_info "Restoring backup"
|
||||||
mv /opt/config.js /opt/cryptpad/config/
|
mv /opt/config.js /opt/cryptpad/config/
|
||||||
msg_ok "Configuration restored"
|
for dir in blob block customize data datastore www/common/onlyoffice/dist onlyoffice-conf; do
|
||||||
|
[ -d "/tmp/cryptpad_${dir//\//_}" ] && mv "/tmp/cryptpad_${dir//\//_}" "/opt/cryptpad/${dir}"
|
||||||
|
done
|
||||||
|
msg_ok "Restored backup"
|
||||||
|
|
||||||
msg_info "Updating CryptaPad"
|
msg_info "Updating CryptPad"
|
||||||
cd /opt/cryptpad
|
cd /opt/cryptpad
|
||||||
$STD npm ci
|
$STD npm ci
|
||||||
$STD npm run install:components
|
$STD npm run install:components
|
||||||
|
|||||||
+64
@@ -0,0 +1,64 @@
|
|||||||
|
#!/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://dagu.sh/
|
||||||
|
|
||||||
|
APP="Dagu"
|
||||||
|
var_tags="${var_tags:-automation;workflow;scheduler}"
|
||||||
|
var_cpu="${var_cpu:-1}"
|
||||||
|
var_ram="${var_ram:-512}"
|
||||||
|
var_disk="${var_disk:-4}"
|
||||||
|
var_os="${var_os:-debian}"
|
||||||
|
var_version="${var_version:-13}"
|
||||||
|
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/dagu/dagu ]]; then
|
||||||
|
msg_error "No ${APP} Installation Found!"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
if check_for_gh_release "dagu" "dagucloud/dagu"; then
|
||||||
|
msg_info "Stopping Service"
|
||||||
|
systemctl stop dagu
|
||||||
|
msg_ok "Stopped Service"
|
||||||
|
|
||||||
|
msg_info "Backing up Data"
|
||||||
|
cp -r /opt/dagu/data /opt/dagu_data_backup
|
||||||
|
msg_ok "Backed up Data"
|
||||||
|
|
||||||
|
fetch_and_deploy_gh_release "dagu" "dagucloud/dagu" "prebuild" "latest" "/opt/dagu" "dagu_*_linux_amd64.tar.gz"
|
||||||
|
|
||||||
|
msg_info "Restoring Data"
|
||||||
|
mkdir -p /opt/dagu/data
|
||||||
|
cp -r /opt/dagu_data_backup/. /opt/dagu/data
|
||||||
|
rm -rf /opt/dagu_data_backup
|
||||||
|
msg_ok "Restored Data"
|
||||||
|
|
||||||
|
msg_info "Starting Service"
|
||||||
|
systemctl start dagu
|
||||||
|
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 "${TAB}${GATEWAY}${BGN}http://${IP}:8080${CL}"
|
||||||
+73
@@ -0,0 +1,73 @@
|
|||||||
|
#!/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: tteck (tteckster) | Co-Author: CrazyWolf13
|
||||||
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
|
# Source: https://dashy.to/
|
||||||
|
|
||||||
|
APP="Dashy"
|
||||||
|
var_tags="${var_tags:-dashboard}"
|
||||||
|
var_cpu="${var_cpu:-2}"
|
||||||
|
var_ram="${var_ram:-2048}"
|
||||||
|
var_disk="${var_disk:-6}"
|
||||||
|
var_os="${var_os:-debian}"
|
||||||
|
var_version="${var_version:-13}"
|
||||||
|
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/dashy/public/ ]]; then
|
||||||
|
msg_error "No ${APP} Installation Found!"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
if check_for_gh_release "dashy" "Lissy93/dashy"; then
|
||||||
|
msg_info "Stopping Service"
|
||||||
|
systemctl stop dashy
|
||||||
|
msg_ok "Stopped Service"
|
||||||
|
|
||||||
|
msg_info "Backing up conf.yml"
|
||||||
|
if [[ -f /opt/dashy/public/conf.yml ]]; then
|
||||||
|
cp -R /opt/dashy/public/conf.yml /opt/dashy_conf_backup.yml
|
||||||
|
else
|
||||||
|
cp -R /opt/dashy/user-data/conf.yml /opt/dashy_conf_backup.yml
|
||||||
|
fi
|
||||||
|
msg_ok "Backed up conf.yml"
|
||||||
|
|
||||||
|
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "dashy" "Lissy93/dashy" "prebuild" "latest" "/opt/dashy" "dashy-*.tar.gz"
|
||||||
|
|
||||||
|
msg_info "Updating Dashy"
|
||||||
|
cd /opt/dashy
|
||||||
|
$STD yarn install --ignore-engines --network-timeout 300000
|
||||||
|
msg_ok "Updated Dashy"
|
||||||
|
|
||||||
|
msg_info "Restoring conf.yml"
|
||||||
|
cp -R /opt/dashy_conf_backup.yml /opt/dashy/user-data
|
||||||
|
msg_ok "Restored conf.yml"
|
||||||
|
|
||||||
|
msg_info "Cleaning"
|
||||||
|
rm -rf /opt/dashy_conf_backup.yml /opt/dashy/public/conf.yml
|
||||||
|
msg_ok "Cleaned"
|
||||||
|
|
||||||
|
msg_info "Starting Dashy"
|
||||||
|
systemctl start dashy
|
||||||
|
msg_ok "Started Dashy"
|
||||||
|
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}:4000${CL}"
|
||||||
@@ -38,6 +38,31 @@ function update_script() {
|
|||||||
cp /opt/databasus/.env /opt/databasus.env.bak
|
cp /opt/databasus/.env /opt/databasus.env.bak
|
||||||
msg_ok "Backed up Configuration"
|
msg_ok "Backed up Configuration"
|
||||||
|
|
||||||
|
msg_info "Ensuring Database Clients"
|
||||||
|
# Create PostgreSQL version symlinks for compatibility
|
||||||
|
for v in 12 13 14 15 16 18; do
|
||||||
|
ln -sf /usr/lib/postgresql/17 /usr/lib/postgresql/$v
|
||||||
|
done
|
||||||
|
# Install MongoDB Database Tools via direct .deb (no APT repo for Debian 13)
|
||||||
|
if ! command -v mongodump &>/dev/null; then
|
||||||
|
[[ "$(get_os_info id)" == "ubuntu" ]] && MONGO_DIST="ubuntu2204" || MONGO_DIST="debian12"
|
||||||
|
fetch_and_deploy_from_url "https://fastdl.mongodb.org/tools/db/mongodb-database-tools-${MONGO_DIST}-x86_64-100.14.1.deb"
|
||||||
|
fi
|
||||||
|
[[ -f /usr/bin/mongodump ]] && ln -sf /usr/bin/mongodump /usr/local/mongodb-database-tools/bin/mongodump
|
||||||
|
[[ -f /usr/bin/mongorestore ]] && ln -sf /usr/bin/mongorestore /usr/local/mongodb-database-tools/bin/mongorestore
|
||||||
|
# Create MariaDB and MySQL client symlinks for compatibility
|
||||||
|
ensure_dependencies mariadb-client
|
||||||
|
mkdir -p /usr/local/mariadb-{10.6,12.1}/bin /usr/local/mysql-{5.7,8.0,8.4,9}/bin /usr/local/mongodb-database-tools/bin
|
||||||
|
for dir in /usr/local/mariadb-{10.6,12.1}/bin; do
|
||||||
|
ln -sf /usr/bin/mariadb-dump "$dir/mariadb-dump"
|
||||||
|
ln -sf /usr/bin/mariadb "$dir/mariadb"
|
||||||
|
done
|
||||||
|
for dir in /usr/local/mysql-{5.7,8.0,8.4,9}/bin; do
|
||||||
|
ln -sf /usr/bin/mariadb-dump "$dir/mysqldump"
|
||||||
|
ln -sf /usr/bin/mariadb "$dir/mysql"
|
||||||
|
done
|
||||||
|
msg_ok "Ensured Database Clients"
|
||||||
|
|
||||||
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "databasus" "databasus/databasus" "tarball" "latest" "/opt/databasus"
|
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "databasus" "databasus/databasus" "tarball" "latest" "/opt/databasus"
|
||||||
|
|
||||||
msg_info "Updating Databasus"
|
msg_info "Updating Databasus"
|
||||||
@@ -49,6 +74,7 @@ function update_script() {
|
|||||||
$STD /root/go/bin/swag init -g cmd/main.go -o swagger
|
$STD /root/go/bin/swag init -g cmd/main.go -o swagger
|
||||||
$STD env CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o databasus ./cmd/main.go
|
$STD env CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o databasus ./cmd/main.go
|
||||||
mv /opt/databasus/backend/databasus /opt/databasus/databasus
|
mv /opt/databasus/backend/databasus /opt/databasus/databasus
|
||||||
|
mkdir -p /opt/databasus/ui/build
|
||||||
cp -r /opt/databasus/frontend/dist/* /opt/databasus/ui/build/
|
cp -r /opt/databasus/frontend/dist/* /opt/databasus/ui/build/
|
||||||
cp -r /opt/databasus/backend/migrations /opt/databasus/
|
cp -r /opt/databasus/backend/migrations /opt/databasus/
|
||||||
chown -R postgres:postgres /opt/databasus
|
chown -R postgres:postgres /opt/databasus
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ function update_script() {
|
|||||||
exit
|
exit
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
ensure_dependencies libgeos++-dev libxml2-dev libxslt-dev libjemalloc-dev
|
||||||
|
|
||||||
if check_for_gh_release "dawarich" "Freika/dawarich"; then
|
if check_for_gh_release "dawarich" "Freika/dawarich"; then
|
||||||
msg_info "Stopping Services"
|
msg_info "Stopping Services"
|
||||||
systemctl stop dawarich-web dawarich-worker
|
systemctl stop dawarich-web dawarich-worker
|
||||||
|
|||||||
@@ -1,17 +1,18 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
|
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://ui.com/download/unifi
|
|
||||||
|
|
||||||
APP="Unifi"
|
# Copyright (c) 2021-2026 community-scripts ORG
|
||||||
var_tags="${var_tags:-network;unifi}"
|
# Author: mitchscobell
|
||||||
var_cpu="${var_cpu:-2}"
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
var_ram="${var_ram:-2048}"
|
# Source: https://ddclient.net/
|
||||||
var_disk="${var_disk:-8}"
|
|
||||||
|
APP="ddclient"
|
||||||
|
var_tags="${var_tags:-network}"
|
||||||
|
var_cpu="${var_cpu:-1}"
|
||||||
|
var_ram="${var_ram:-512}"
|
||||||
|
var_disk="${var_disk:-2}"
|
||||||
var_os="${var_os:-debian}"
|
var_os="${var_os:-debian}"
|
||||||
var_version="${var_version:-12}"
|
var_version="${var_version:-13}"
|
||||||
var_unprivileged="${var_unprivileged:-1}"
|
var_unprivileged="${var_unprivileged:-1}"
|
||||||
|
|
||||||
header_info "$APP"
|
header_info "$APP"
|
||||||
@@ -23,16 +24,16 @@ function update_script() {
|
|||||||
header_info
|
header_info
|
||||||
check_container_storage
|
check_container_storage
|
||||||
check_container_resources
|
check_container_resources
|
||||||
if [[ ! -d /usr/lib/unifi ]]; then
|
if [[ ! -f /etc/ddclient.conf ]]; then
|
||||||
msg_error "No ${APP} Installation Found!"
|
msg_error "No ${APP} Installation Found!"
|
||||||
exit
|
exit
|
||||||
fi
|
fi
|
||||||
|
|
||||||
JAVA_VERSION="21" setup_java
|
msg_info "Updating ddclient"
|
||||||
|
$STD apt update
|
||||||
msg_info "Updating ${APP}"
|
$STD apt install --only-upgrade -y ddclient
|
||||||
$STD apt update --allow-releaseinfo-change
|
$STD systemctl restart ddclient
|
||||||
ensure_dependencies unifi
|
msg_ok "Updated ddclient"
|
||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
exit
|
exit
|
||||||
}
|
}
|
||||||
@@ -43,5 +44,3 @@ description
|
|||||||
|
|
||||||
msg_ok "Completed successfully!\n"
|
msg_ok "Completed successfully!\n"
|
||||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
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}"
|
|
||||||
+6
-25
@@ -1,9 +1,9 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
|
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
|
||||||
# Copyright (c) 2021-2026 community-scripts ORG
|
# Copyright (c) 2021-2026 community-scripts ORG
|
||||||
# Author: DragoQC
|
# Author: DragoQC | Co-Author: nickheyer
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
# Source: https://discopanel.app/
|
# Source: https://discopanel.app/ | Github: https://github.com/nickheyer/discopanel
|
||||||
|
|
||||||
APP="DiscoPanel"
|
APP="DiscoPanel"
|
||||||
var_tags="${var_tags:-gaming}"
|
var_tags="${var_tags:-gaming}"
|
||||||
@@ -38,34 +38,15 @@ function update_script() {
|
|||||||
|
|
||||||
msg_info "Creating Backup"
|
msg_info "Creating Backup"
|
||||||
mkdir -p /opt/discopanel_backup_temp
|
mkdir -p /opt/discopanel_backup_temp
|
||||||
cp -r /opt/discopanel/data/discopanel.db \
|
cp /opt/discopanel/data/discopanel.db /opt/discopanel_backup_temp/discopanel.db
|
||||||
/opt/discopanel/data/.recovery_key \
|
|
||||||
/opt/discopanel_backup_temp/
|
|
||||||
if [[ -d /opt/discopanel/data/servers ]]; then
|
|
||||||
cp -r /opt/discopanel/data/servers /opt/discopanel_backup_temp/
|
|
||||||
fi
|
|
||||||
msg_ok "Created Backup"
|
msg_ok "Created Backup"
|
||||||
|
|
||||||
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "discopanel" "nickheyer/discopanel" "tarball" "latest" "/opt/discopanel"
|
fetch_and_deploy_gh_release "discopanel" "nickheyer/discopanel" "prebuild" "latest" "/opt/discopanel" "discopanel-linux-amd64.tar.gz"
|
||||||
|
ln -sf /opt/discopanel/discopanel-linux-amd64 /opt/discopanel/discopanel
|
||||||
msg_info "Setting up DiscoPanel"
|
|
||||||
cd /opt/discopanel
|
|
||||||
$STD make gen
|
|
||||||
cd /opt/discopanel/web/discopanel
|
|
||||||
$STD npm install
|
|
||||||
$STD npm run build
|
|
||||||
msg_ok "Built Web Interface"
|
|
||||||
|
|
||||||
setup_go
|
|
||||||
|
|
||||||
msg_info "Building DiscoPanel"
|
|
||||||
cd /opt/discopanel
|
|
||||||
$STD go build -o discopanel cmd/discopanel/main.go
|
|
||||||
msg_ok "Built DiscoPanel"
|
|
||||||
|
|
||||||
msg_info "Restoring Data"
|
msg_info "Restoring Data"
|
||||||
mkdir -p /opt/discopanel/data
|
mkdir -p /opt/discopanel/data
|
||||||
cp -a /opt/discopanel_backup_temp/. /opt/discopanel/data/
|
mv /opt/discopanel_backup_temp/discopanel.db /opt/discopanel/data/discopanel.db
|
||||||
rm -rf /opt/discopanel_backup_temp
|
rm -rf /opt/discopanel_backup_temp
|
||||||
msg_ok "Restored Data"
|
msg_ok "Restored Data"
|
||||||
|
|
||||||
|
|||||||
+4
-2
@@ -70,7 +70,7 @@ function update_script() {
|
|||||||
source /opt/dispatcharr/.env
|
source /opt/dispatcharr/.env
|
||||||
set +o allexport
|
set +o allexport
|
||||||
if [[ -n "$POSTGRES_DB" ]] && [[ -n "$POSTGRES_USER" ]] && [[ -n "$POSTGRES_PASSWORD" ]]; then
|
if [[ -n "$POSTGRES_DB" ]] && [[ -n "$POSTGRES_USER" ]] && [[ -n "$POSTGRES_PASSWORD" ]]; then
|
||||||
PGPASSWORD=$POSTGRES_PASSWORD pg_dump -U $POSTGRES_USER -h ${POSTGRES_HOST:-localhost} $POSTGRES_DB >/tmp/dispatcharr_db_$(date +%F).sql
|
PGPASSWORD=$POSTGRES_PASSWORD pg_dump -U "$POSTGRES_USER" -h "${POSTGRES_HOST:-localhost}" -p "${POSTGRES_PORT:-5432}" "$POSTGRES_DB" >/tmp/dispatcharr_db_$(date +%F).sql
|
||||||
msg_info "Database backup created"
|
msg_info "Database backup created"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
@@ -110,7 +110,9 @@ function update_script() {
|
|||||||
|
|
||||||
msg_info "Building Frontend"
|
msg_info "Building Frontend"
|
||||||
cd /opt/dispatcharr/frontend
|
cd /opt/dispatcharr/frontend
|
||||||
$STD npm install --legacy-peer-deps
|
node -e "const p=require('./package.json');p.overrides=p.overrides||{};p.overrides['webworkify-webpack']='2.1.3';require('fs').writeFileSync('package.json',JSON.stringify(p,null,2));"
|
||||||
|
rm -f package-lock.json
|
||||||
|
$STD npm install --no-audit --progress=false
|
||||||
$STD npm run build
|
$STD npm run build
|
||||||
msg_ok "Built Frontend"
|
msg_ok "Built Frontend"
|
||||||
|
|
||||||
|
|||||||
+32
-11
@@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
|
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
|
||||||
# Copyright (c) 2021-2026 tteck
|
# Copyright (c) 2021-2026 tteck
|
||||||
# Author: tteck (tteckster)
|
# Author: tteck (tteckster) | Migration: MickLesk (CanbiZ)
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
# Source: https://dockge.kuma.pet/
|
# Source: https://dockge.kuma.pet/
|
||||||
|
|
||||||
@@ -19,26 +19,47 @@ variables
|
|||||||
color
|
color
|
||||||
catch_errors
|
catch_errors
|
||||||
|
|
||||||
|
ADDON_SCRIPT="https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/addon/dockge.sh"
|
||||||
|
|
||||||
function update_script() {
|
function update_script() {
|
||||||
header_info
|
header_info
|
||||||
check_container_storage
|
check_container_storage
|
||||||
check_container_resources
|
check_container_resources
|
||||||
|
|
||||||
if [[ ! -d /opt/dockge ]]; then
|
if [[ ! -d /opt/dockge ]]; then
|
||||||
msg_error "No ${APP} Installation Found!"
|
msg_error "No ${APP} Installation Found!"
|
||||||
exit
|
exit
|
||||||
fi
|
fi
|
||||||
|
|
||||||
msg_info "Updating base system"
|
msg_warn "⚠️ ${APP} has been migrated to an addon script."
|
||||||
$STD apt update
|
echo ""
|
||||||
$STD apt upgrade -y
|
msg_info "This is a one-time migration. After this, you can update ${APP} anytime with:"
|
||||||
msg_ok "Base system updated"
|
echo -e "${TAB}${TAB}${GN}update_dockge${CL} or ${GN}bash <(curl -fsSL ${ADDON_SCRIPT})${CL}"
|
||||||
|
echo ""
|
||||||
|
read -r -p "${TAB}Migrate update function now? [y/N]: " CONFIRM
|
||||||
|
if [[ ! "${CONFIRM,,}" =~ ^(y|yes)$ ]]; then
|
||||||
|
msg_warn "Migration skipped. The old update will continue to work for now."
|
||||||
|
msg_info "Updating ${APP} (legacy)"
|
||||||
|
cd /opt/dockge
|
||||||
|
$STD docker compose pull
|
||||||
|
$STD docker compose up -d
|
||||||
|
msg_ok "Updated ${APP}"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
msg_info "Updating Dockge"
|
msg_info "Migrating update function"
|
||||||
cd /opt/dockge
|
TMP_UPDATE=$(mktemp)
|
||||||
$STD docker compose pull
|
cat <<'MIGRATION_EOF' >"$TMP_UPDATE"
|
||||||
$STD docker compose up -d
|
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/addon/dockge.sh)"
|
||||||
msg_ok "Updated Dockge"
|
MIGRATION_EOF
|
||||||
msg_ok "Updated successfully!"
|
mv "$TMP_UPDATE" /usr/bin/update
|
||||||
|
chmod +x /usr/bin/update
|
||||||
|
|
||||||
|
ln -sf /usr/bin/update /usr/bin/update_dockge 2>/dev/null || true
|
||||||
|
msg_ok "Migration complete"
|
||||||
|
|
||||||
|
msg_info "Running addon update"
|
||||||
|
type=update bash <(curl -fsSL "${ADDON_SCRIPT}")
|
||||||
exit
|
exit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user