mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-14 06:28:32 +09:00
Compare commits
1398
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
959b03b5f4 | ||
|
|
f501d34179 | ||
|
|
3657438467 | ||
|
|
2976b1842b | ||
|
|
8cac3b35c9 | ||
|
|
d514501d57 | ||
|
|
83bb9d89c8 | ||
|
|
0117605572 | ||
|
|
72e14c17ba | ||
|
|
aa0ebdb97e | ||
|
|
3d4b2933e1 | ||
|
|
922ff5ea64 | ||
|
|
fce3200265 | ||
|
|
3b35db2681 | ||
|
|
c7da0cf33d | ||
|
|
78272521bb | ||
|
|
8e39380ee6 | ||
|
|
fb58447ba1 | ||
|
|
2ffe8f3387 | ||
|
|
4194525933 | ||
|
|
44799dafa2 | ||
|
|
30b32c9a35 | ||
|
|
d1b4b82895 | ||
|
|
9bc43c0c08 | ||
|
|
13960a0bb3 | ||
|
|
64cb159d65 | ||
|
|
d2173fe879 | ||
|
|
49eb8cdd81 | ||
|
|
b4fc1241ae | ||
|
|
54f1b37666 | ||
|
|
8bda151596 | ||
|
|
ab19c0d1ac | ||
|
|
68cb2a4bbb | ||
|
|
17746fcdc4 | ||
|
|
c890956e4f | ||
|
|
8a5d4a8bdb | ||
|
|
0ba15ee46a | ||
|
|
85d9ef7386 | ||
|
|
f8d85f0e5e | ||
|
|
7f674474b5 | ||
|
|
c9fdf8fead | ||
|
|
c17091768c | ||
|
|
e0640d68ff | ||
|
|
3292dc5f89 | ||
|
|
86e29b61e3 | ||
|
|
f8d3c70a91 | ||
|
|
74c6fad260 | ||
|
|
bcb30eea88 | ||
|
|
d59ddc2214 | ||
|
|
e87b593f46 | ||
|
|
5a2d81ebbb | ||
|
|
50c28aa8fa | ||
|
|
af7724dbf6 | ||
|
|
be314788b3 | ||
|
|
5b3f69bf27 | ||
|
|
d7aa6ec2aa | ||
|
|
20e3474393 | ||
|
|
3694300d86 | ||
|
|
54ec74e4f9 | ||
|
|
aa3b058ce6 | ||
|
|
44bc29b101 | ||
|
|
b07dcc368d | ||
|
|
0967bf3136 | ||
|
|
edc913096a | ||
|
|
cca8227ca6 | ||
|
|
45b78a13c2 | ||
|
|
6acd7f3d22 | ||
|
|
7d2c51a57f | ||
|
|
575a5adbef | ||
|
|
5695510980 | ||
|
|
c16d414d93 | ||
|
|
e7b13fd19f | ||
|
|
f22261f218 | ||
|
|
901ed623f6 | ||
|
|
1198b61648 | ||
|
|
d564ca5691 | ||
|
|
b7e92cbfe0 | ||
|
|
1cd62eb661 | ||
|
|
7e177a1c90 | ||
|
|
78471d8a85 | ||
|
|
6b6ae13919 | ||
|
|
7197371123 | ||
|
|
70fd9e6331 | ||
|
|
c14b7d4cb3 | ||
|
|
0f0ff5f3df | ||
|
|
b4c614d21a | ||
|
|
bef5e33eec | ||
|
|
e5a568acca | ||
|
|
a208b56354 | ||
|
|
71be6c1de4 | ||
|
|
eae905b1da | ||
|
|
10cd4f96a4 | ||
|
|
9d74daf8ad | ||
|
|
6f344def93 | ||
|
|
72f9f9c396 | ||
|
|
c8755885d4 | ||
|
|
12d503d4c5 | ||
|
|
2f6201bcbd | ||
|
|
ec681e6061 | ||
|
|
0fc6fad11d | ||
|
|
eb329f2cd0 | ||
|
|
9a20821332 | ||
|
|
4749eb7f86 | ||
|
|
2d83fd2a93 | ||
|
|
d180af6ba2 | ||
|
|
4810eb3e24 | ||
|
|
48a19dedd8 | ||
|
|
cadf7ea532 | ||
|
|
fc60d05f17 | ||
|
|
5072488f1e | ||
|
|
7a5b9a0ded | ||
|
|
4ce4d4e09a | ||
|
|
82abd03a37 | ||
|
|
93d1f8af46 | ||
|
|
a19002652b | ||
|
|
6534ee4300 | ||
|
|
4db13b0375 | ||
|
|
a5c1362f4a | ||
|
|
454fefdb92 | ||
|
|
f390e610b9 | ||
|
|
ece622e800 | ||
|
|
bc17922b02 | ||
|
|
a32d8e4f52 | ||
|
|
12daeb758d | ||
|
|
fff67ed9af | ||
|
|
d0b4816a5f | ||
|
|
0febad324c | ||
|
|
dcc3273889 | ||
|
|
e9a4f33a7e | ||
|
|
ae820ba4ea | ||
|
|
94f1239050 | ||
|
|
acc1392a53 | ||
|
|
a6a9789091 | ||
|
|
fdb7410976 | ||
|
|
b146b8ee33 | ||
|
|
4b1afc953f | ||
|
|
4ecbe9603c | ||
|
|
847d449882 | ||
|
|
bef20cba85 | ||
|
|
ebf91ccc76 | ||
|
|
abfaff16c2 | ||
|
|
89fa895a0a | ||
|
|
334fef52e1 | ||
|
|
aa42bf13ce | ||
|
|
c486c2d3d0 | ||
|
|
0ec1cee99e | ||
|
|
ccbe4857a1 | ||
|
|
7f8b0afedb | ||
|
|
e94b7d7ad8 | ||
|
|
27baa38fd1 | ||
|
|
4af10dd3e3 | ||
|
|
269d33cab2 | ||
|
|
170e12595b | ||
|
|
b82bbaa2dd | ||
|
|
b8f3dbddbf | ||
|
|
663572fd10 | ||
|
|
5033cf7203 | ||
|
|
0fcab2f8f0 | ||
|
|
c3d790f664 | ||
|
|
0906a85d6f | ||
|
|
4da8dec4ac | ||
|
|
d6e3254a16 | ||
|
|
6dc698ff5e | ||
|
|
39e48458da | ||
|
|
c5453f83e8 | ||
|
|
510cc1b916 | ||
|
|
e7859fefb1 | ||
|
|
46a356cc40 | ||
|
|
bd56174870 | ||
|
|
965bb5f634 | ||
|
|
7937d5f802 | ||
|
|
f1373a63c3 | ||
|
|
e0d7625c39 | ||
|
|
f8505d19f7 | ||
|
|
1515a8487f | ||
|
|
7a4aa42d4b | ||
|
|
0ef1cd14c3 | ||
|
|
795e190bda | ||
|
|
d00389ab30 | ||
|
|
3071bc7525 | ||
|
|
6de6be2358 | ||
|
|
c51c222c47 | ||
|
|
e218ba21de | ||
|
|
de358c0def | ||
|
|
4b88d64b2d | ||
|
|
ee1c861eb2 | ||
|
|
6a24ac3f4e | ||
|
|
8b312c610e | ||
|
|
2e3e3a1536 | ||
|
|
5c63d81ffd | ||
|
|
c402c52a8a | ||
|
|
317fedeef9 | ||
|
|
002502a7fa | ||
|
|
1997850d55 | ||
|
|
d346eb0e88 | ||
|
|
7c5fa2180a | ||
|
|
c748c8af4e | ||
|
|
ba59a13149 | ||
|
|
3f4160b138 | ||
|
|
5f4295e399 | ||
|
|
4e730832c7 | ||
|
|
d7c00d4556 | ||
|
|
154b65afe5 | ||
|
|
fcc2a3f64b | ||
|
|
80456861ac | ||
|
|
0c4f016ba2 | ||
|
|
cc5545c333 | ||
|
|
6e28092cdc | ||
|
|
8b6910d505 | ||
|
|
d87e31efaf | ||
|
|
6618a6baf4 | ||
|
|
22b8f5454b | ||
|
|
801bd3f106 | ||
|
|
e26c8c870d | ||
|
|
f4e545e090 | ||
|
|
2006fc0d8d | ||
|
|
d456048e69 | ||
|
|
fd35b4da24 | ||
|
|
283d179b05 | ||
|
|
3093e7334b | ||
|
|
02c82f0038 | ||
|
|
e1eecc3b6c | ||
|
|
bf3d73a5f7 | ||
|
|
05257d6439 | ||
|
|
532e828fe6 | ||
|
|
12a407aca8 | ||
|
|
5ca458dada | ||
|
|
0aeff01c2d | ||
|
|
2ac164d5b8 | ||
|
|
14d475df9a | ||
|
|
f3c777b244 | ||
|
|
1544e58e76 | ||
|
|
5d0c9c7cbe | ||
|
|
8f58fcc4c4 | ||
|
|
5799ef705d | ||
|
|
0de7dde1ce | ||
|
|
7b39e5a79d | ||
|
|
583c791016 | ||
|
|
bc5dcdfe21 | ||
|
|
973aaced96 | ||
|
|
3e9ee908f8 | ||
|
|
e7347b582c | ||
|
|
71b7cffabc | ||
|
|
da9e9ff0be | ||
|
|
c6941d5905 | ||
|
|
a3cf960660 | ||
|
|
7eebfca20b | ||
|
|
e9167d96ec | ||
|
|
1664050ef7 | ||
|
|
7fa00c0e89 | ||
|
|
81d69c41f5 | ||
|
|
4e6b837ccc | ||
|
|
a9f7a23c0d | ||
|
|
07301adc6d | ||
|
|
c6630008b5 | ||
|
|
cdcaba34ce | ||
|
|
09b9a57e38 | ||
|
|
79d7c85832 | ||
|
|
eb0e8366bc | ||
|
|
cf9752db4f | ||
|
|
d6fb3b2c50 | ||
|
|
b04fdc68df | ||
|
|
706c41aad9 | ||
|
|
db9ec0605e | ||
|
|
a95172bf88 | ||
|
|
597116a0b4 | ||
|
|
811341bc2f | ||
|
|
98fa41dcf0 | ||
|
|
b52a0b5d5f | ||
|
|
effeaaa435 | ||
|
|
27fc634bc9 | ||
|
|
69d93f9fee | ||
|
|
00620715da | ||
|
|
1ec8f31253 | ||
|
|
1abde06824 | ||
|
|
b54016653b | ||
|
|
ee74d61f27 | ||
|
|
1f18d3262d | ||
|
|
8ea7707b37 | ||
|
|
7b40df5d6c | ||
|
|
6f98de33f7 | ||
|
|
efe94ed094 | ||
|
|
603b936536 | ||
|
|
d87351eefe | ||
|
|
76e6891f5b | ||
|
|
5040ae2c10 | ||
|
|
87df92e2c2 | ||
|
|
237aff666d | ||
|
|
11645cbf28 | ||
|
|
e297a6a653 | ||
|
|
1eed347ffb | ||
|
|
4aa7a3e181 | ||
|
|
69786d3b49 | ||
|
|
2fb5fb1abb | ||
|
|
a9265cbb39 | ||
|
|
ee2d11ee0a | ||
|
|
632067b552 | ||
|
|
840dc3dfa5 | ||
|
|
4e6f9b539c | ||
|
|
98cce4815d | ||
|
|
b375abc20a | ||
|
|
21cb7ba69c | ||
|
|
be69333eaf | ||
|
|
9a074adb11 | ||
|
|
2df82b2b5e | ||
|
|
d691047884 | ||
|
|
c2e7fde5bc | ||
|
|
7e4d5137f8 | ||
|
|
376afd2ad6 | ||
|
|
e3fcedbec5 | ||
|
|
7c9564bcad | ||
|
|
cfed6cc4e0 | ||
|
|
c7bd1be3e4 | ||
|
|
2161d84701 | ||
|
|
eaeeb3b502 | ||
|
|
dc32a7c70e | ||
|
|
ab0b483fbe | ||
|
|
6e2f90b03c | ||
|
|
5e0806f479 | ||
|
|
dfdfffe5de | ||
|
|
f5e32aed31 | ||
|
|
710c1aeaa8 | ||
|
|
af49cd6cc4 | ||
|
|
ca719e7b5e | ||
|
|
ab4069ed0e | ||
|
|
12bfaa83ba | ||
|
|
1076728241 | ||
|
|
360b984adc | ||
|
|
dcdf7e1d93 | ||
|
|
e8cb167dbf | ||
|
|
0b3418dcbe | ||
|
|
ec7649193c | ||
|
|
2b8a743dc5 | ||
|
|
39f9beda5a | ||
|
|
f0b3c82cfd | ||
|
|
2808edf6d0 | ||
|
|
071263188a | ||
|
|
f9108f24ce | ||
|
|
e98b77a54a | ||
|
|
2636e9cc13 | ||
|
|
944b586f22 | ||
|
|
4f968bbc47 | ||
|
|
d433a039b5 | ||
|
|
b30ea361d3 | ||
|
|
9908518f5b | ||
|
|
364084c819 | ||
|
|
c488906131 | ||
|
|
39c72f0fb0 | ||
|
|
3736d94d73 | ||
|
|
192cec689a | ||
|
|
e895c41bf0 | ||
|
|
997d98c65c | ||
|
|
c9ae5b6ee8 | ||
|
|
a728be4062 | ||
|
|
fce81367fb | ||
|
|
5a4edc0b59 | ||
|
|
713ae5f7f5 | ||
|
|
eaee820216 | ||
|
|
564c5ae164 | ||
|
|
dd8ed6f205 | ||
|
|
ed8c412415 | ||
|
|
12417a6942 | ||
|
|
d05f6c9aaa | ||
|
|
0ca035c547 | ||
|
|
dfd46ccc2c | ||
|
|
f6df3169ca | ||
|
|
5b280898c5 | ||
|
|
2a9e25c788 | ||
|
|
463c03fb6d | ||
|
|
153dad11e1 | ||
|
|
e2d05a44a8 | ||
|
|
30ba55bd4d | ||
|
|
9def9fbef6 | ||
|
|
fa3fd0027c | ||
|
|
7e1b934637 | ||
|
|
33a118d12a | ||
|
|
01f53a168d | ||
|
|
336b8b7dcd | ||
|
|
48d0034239 | ||
|
|
677ef8491e | ||
|
|
6a6119ed1e | ||
|
|
931327d1dc | ||
|
|
858a2d9e2b | ||
|
|
841fb7af41 | ||
|
|
08e65d41c0 | ||
|
|
f76c4dc041 | ||
|
|
f1f8ba2031 | ||
|
|
5ab8d745c0 | ||
|
|
ff62bc89a4 | ||
|
|
838bbdb5ec | ||
|
|
1c36a59b2c | ||
|
|
6730a242db | ||
|
|
e62ae77643 | ||
|
|
f4f39e6a89 | ||
|
|
00bf74cef5 | ||
|
|
c1c45d835f | ||
|
|
bbfe809bef | ||
|
|
e0843ac4f5 | ||
|
|
43741cdad8 | ||
|
|
b8e3807262 | ||
|
|
3304f01a84 | ||
|
|
2ba463235b | ||
|
|
15136fed59 | ||
|
|
6013581dd9 | ||
|
|
7a91f128e9 | ||
|
|
963ffc5550 | ||
|
|
a90991612c | ||
|
|
50ad23b760 | ||
|
|
425dab983b | ||
|
|
a0825e77c4 | ||
|
|
88038a1d5b | ||
|
|
c2c0fdb445 | ||
|
|
dcd5f09d6a | ||
|
|
590b1f36fd | ||
|
|
168ac727f1 | ||
|
|
deb86dd92e | ||
|
|
7ccec4d3b8 | ||
|
|
2f38bcdf26 | ||
|
|
f2785941aa | ||
|
|
ea9f83a443 | ||
|
|
bd6ca7290e | ||
|
|
b85e975fb5 | ||
|
|
b6e504f68c | ||
|
|
5fde6eb484 | ||
|
|
b16989d567 | ||
|
|
c9754ac11a | ||
|
|
f34e4a5115 | ||
|
|
44b3615298 | ||
|
|
211e98307d | ||
|
|
18c303abf6 | ||
|
|
7021a58090 | ||
|
|
320725a587 | ||
|
|
8450edc072 | ||
|
|
a1e2bf2c8d | ||
|
|
82b2f4ec5e | ||
|
|
c92e5d03a7 | ||
|
|
91340c5c84 | ||
|
|
045dd5d027 | ||
|
|
a21b9c4659 | ||
|
|
4b1b869802 | ||
|
|
1ab7e7dfcc | ||
|
|
31c53d2dff | ||
|
|
412a1ae79d | ||
|
|
0b2306ec3d | ||
|
|
242ed3a934 | ||
|
|
70e1ce682a | ||
|
|
7601bf98ee | ||
|
|
c7ec2a0f58 | ||
|
|
6a5e0056a8 | ||
|
|
78d105b46e | ||
|
|
c68d62b8a0 | ||
|
|
df58020f4c | ||
|
|
f052ce05aa | ||
|
|
eedfd9275f | ||
|
|
416af4bec4 | ||
|
|
108d282ddd | ||
|
|
a6103244b0 | ||
|
|
38935c83c5 | ||
|
|
c157ab5752 | ||
|
|
574a93257c | ||
|
|
ba7d8781cf | ||
|
|
3256af8d92 | ||
|
|
86043212f2 | ||
|
|
5d85e88532 | ||
|
|
e2abfd476a | ||
|
|
487febac8e | ||
|
|
a3454e8245 | ||
|
|
bf7567b768 | ||
|
|
ac3450ab32 | ||
|
|
5d034becb8 | ||
|
|
f9397d0db9 | ||
|
|
9005139dc8 | ||
|
|
d93604afa2 | ||
|
|
c4f0b2ece0 | ||
|
|
98a42f612b | ||
|
|
cc75e1318d | ||
|
|
9027cbdf3e | ||
|
|
2119e10ed5 | ||
|
|
87f3eb3c81 | ||
|
|
f9bb8bd585 | ||
|
|
bc47a724af | ||
|
|
f32356801d | ||
|
|
efd677f32b | ||
|
|
3cec27ba57 | ||
|
|
1f810ba04d | ||
|
|
522cf08e61 | ||
|
|
025c01ab13 | ||
|
|
dc41b53d60 | ||
|
|
3b552e00ef | ||
|
|
56e04e7b53 | ||
|
|
deac653a9e | ||
|
|
ed9528834d | ||
|
|
4cecbf1f43 | ||
|
|
b019f4a91f | ||
|
|
34b6ecfbd2 | ||
|
|
4ef9c4c65b | ||
|
|
3276039e41 | ||
|
|
03d1354562 | ||
|
|
964845d7a7 | ||
|
|
3bc5dd8e0f | ||
|
|
17292fd6a5 | ||
|
|
f753659899 | ||
|
|
7412ec3395 | ||
|
|
570c8776c4 | ||
|
|
910db6734b | ||
|
|
9e614026d7 | ||
|
|
b38e7c6433 | ||
|
|
83c8e91955 | ||
|
|
0532dd0440 | ||
|
|
a08615e306 | ||
|
|
f4c5fee17e | ||
|
|
c5aaf65a10 | ||
|
|
951e39da3d | ||
|
|
b693d84d2b | ||
|
|
9bbf6c513b | ||
|
|
50cec92738 | ||
|
|
c212d315f4 | ||
|
|
1861432a53 | ||
|
|
d0c6146429 | ||
|
|
550e6b05a1 | ||
|
|
5b6949170f | ||
|
|
f32bc37794 | ||
|
|
8ee2279b4b | ||
|
|
6339c3b8ad | ||
|
|
7c9274847f | ||
|
|
5d1dddc093 | ||
|
|
04481d7235 | ||
|
|
a3d6cf37cb | ||
|
|
ed10f9d323 | ||
|
|
4b278a0da8 | ||
|
|
1281045648 | ||
|
|
69c42cff90 | ||
|
|
7d56481aba | ||
|
|
91a2604e9e | ||
|
|
a9dc74a520 | ||
|
|
a9cc04d277 | ||
|
|
8cb097f954 | ||
|
|
78f783f0c4 | ||
|
|
d14998ff69 | ||
|
|
ca7ddd9272 | ||
|
|
84dcf6b8a8 | ||
|
|
a59b80ce11 | ||
|
|
007f338823 | ||
|
|
7d34d25497 | ||
|
|
7375ac9d80 | ||
|
|
6af33c7188 | ||
|
|
33737e0f79 | ||
|
|
5afbf67a70 | ||
|
|
580401d2dc | ||
|
|
38b7c63431 | ||
|
|
57d08cd091 | ||
|
|
91e2d31614 | ||
|
|
d375dc7946 | ||
|
|
3fffce2a4a | ||
|
|
376c509083 | ||
|
|
156315fd5a | ||
|
|
c7b9e9b9bd | ||
|
|
12397032e3 | ||
|
|
4a285cbb11 | ||
|
|
6d600990fe | ||
|
|
e1bc6c2f7e | ||
|
|
3e79530389 | ||
|
|
d0c84b3d9b | ||
|
|
3affd295e8 | ||
|
|
7b15e5be0f | ||
|
|
adab646d1e | ||
|
|
de1fd95a99 | ||
|
|
4bc5593f9f | ||
|
|
172791316b | ||
|
|
b30a4f5d14 | ||
|
|
f254ed679b | ||
|
|
258fe6f742 | ||
|
|
cfa20b7093 | ||
|
|
569146c5bc | ||
|
|
1b1d48b05e | ||
|
|
cadca2c18e | ||
|
|
2e3f78b3c6 | ||
|
|
b57545b1a4 | ||
|
|
e490be2f35 | ||
|
|
ab07fd23cf | ||
|
|
c1fd2234b8 | ||
|
|
3af43b3366 | ||
|
|
0e470f532e | ||
|
|
c541b86c00 | ||
|
|
53b3fa2f4a | ||
|
|
67e01be34a | ||
|
|
81fd8c9aad | ||
|
|
bcef7b3123 | ||
|
|
a98d8ef679 | ||
|
|
a5af857564 | ||
|
|
2830221949 | ||
|
|
84aa8880f5 | ||
|
|
395ec1d60f | ||
|
|
e6ee3b8059 | ||
|
|
61a13e1c1a | ||
|
|
fc0e2628a4 | ||
|
|
87fdfd9c34 | ||
|
|
88a5ff9c45 | ||
|
|
320949a79d | ||
|
|
3a862f1484 | ||
|
|
5da256df12 | ||
|
|
baf2cbf3fd | ||
|
|
74782dc4f2 | ||
|
|
7d8778495f | ||
|
|
53399ffb44 | ||
|
|
35d73eae76 | ||
|
|
54128e049a | ||
|
|
7d8d0ff804 | ||
|
|
2e8f381efc | ||
|
|
b29da84282 | ||
|
|
2988c846c8 | ||
|
|
8e91c1412b | ||
|
|
5b2099c777 | ||
|
|
f97841a58f | ||
|
|
0421c86039 | ||
|
|
d17f320bd7 | ||
|
|
f708586c59 | ||
|
|
905af5dd5a | ||
|
|
5fea319f4e | ||
|
|
01fd11fea9 | ||
|
|
d028679b90 | ||
|
|
4a93b677af | ||
|
|
d79cd99050 | ||
|
|
167862a8a6 | ||
|
|
48b569b9d4 | ||
|
|
75be6aa492 | ||
|
|
9fe65d5036 | ||
|
|
bfa9bf221d | ||
|
|
184eeb0846 | ||
|
|
0eff26a1c9 | ||
|
|
d729f641ff | ||
|
|
044a2c101d | ||
|
|
38e2c8db3e | ||
|
|
1b22d14f3d | ||
|
|
98cceae59d | ||
|
|
3e32414849 | ||
|
|
7707b9531c | ||
|
|
86745e01e9 | ||
|
|
098830a95a | ||
|
|
cf83f66911 | ||
|
|
c577b97f35 | ||
|
|
8cc485cf81 | ||
|
|
6c36d934f7 | ||
|
|
63e3be5750 | ||
|
|
cdecda7f78 | ||
|
|
4ad2858773 | ||
|
|
fda41bb57a | ||
|
|
ce08f82a92 | ||
|
|
ef067f36c6 | ||
|
|
fc2b6b5299 | ||
|
|
55846b24ea | ||
|
|
20a15ac11d | ||
|
|
667ac7da8e | ||
|
|
1b81c14c48 | ||
|
|
ceec183d38 | ||
|
|
69ddc07ebb | ||
|
|
2f008b8653 | ||
|
|
3d38d3f694 | ||
|
|
ad86a04e67 | ||
|
|
600c15e17d | ||
|
|
08c9fe9886 | ||
|
|
43924e3ac5 | ||
|
|
824b5c86c9 | ||
|
|
a2a68847fd | ||
|
|
2019909a5e | ||
|
|
d46c8d49c6 | ||
|
|
45530ebbf5 | ||
|
|
9cdad046b1 | ||
|
|
b6c6928073 | ||
|
|
dd1ee999a4 | ||
|
|
c506d6d5e3 | ||
|
|
8a65832a65 | ||
|
|
fd6ae4abd7 | ||
|
|
24b84c419c | ||
|
|
746a75187a | ||
|
|
10ba2ca896 | ||
|
|
977b6767cd | ||
|
|
f00c6ee47a | ||
|
|
82859dc2f6 | ||
|
|
328dc06ab0 | ||
|
|
ea6e4a75db | ||
|
|
69ca462930 | ||
|
|
f38619d974 | ||
|
|
6c0ce9369b | ||
|
|
00c1b19809 | ||
|
|
2fd5daf104 | ||
|
|
fbf0f6adfe | ||
|
|
d91b5bec66 | ||
|
|
0f24cfb6ef | ||
|
|
7a6691cdbe | ||
|
|
73d3a4f843 | ||
|
|
091755fe78 | ||
|
|
1fb2790bb9 | ||
|
|
798e64b224 | ||
|
|
a2d6477b42 | ||
|
|
a2ca24eeb4 | ||
|
|
8dcd00a8fe | ||
|
|
be8a52c823 | ||
|
|
43e420b0ab | ||
|
|
f8947adf62 | ||
|
|
81fccaf0ab | ||
|
|
7a42291baf | ||
|
|
d9f983b08e | ||
|
|
2f159852a7 | ||
|
|
5ef402b8ee | ||
|
|
a8d6e5ab73 | ||
|
|
e805a3797f | ||
|
|
8f4fa82a9e | ||
|
|
d2438b2fdd | ||
|
|
133640ef2b | ||
|
|
8e0516a8c3 | ||
|
|
d784c0692e | ||
|
|
fffa265117 | ||
|
|
5367c0ab42 | ||
|
|
7f8f09ee51 | ||
|
|
a70924d4b0 | ||
|
|
1a5925f9cb | ||
|
|
43c778aae4 | ||
|
|
34cf8f821f | ||
|
|
226cfd062e | ||
|
|
e8f4e35c32 | ||
|
|
ef559f3d8c | ||
|
|
ee7206ac66 | ||
|
|
1ba9592308 | ||
|
|
d07f520b13 | ||
|
|
632f4c7b6c | ||
|
|
1f627c9cc5 | ||
|
|
cc110b9f5a | ||
|
|
f06d65db54 | ||
|
|
f8a04b8985 | ||
|
|
908e1b8bd4 | ||
|
|
f392636857 | ||
|
|
150115cc0c | ||
|
|
710a6f1c5d | ||
|
|
7c3e722085 | ||
|
|
d8f2aa3184 | ||
|
|
e828398e06 | ||
|
|
31d7cb81d6 | ||
|
|
214d19d45a | ||
|
|
d3170fc320 | ||
|
|
9a229c1b73 | ||
|
|
a036d9a2e1 | ||
|
|
d5bfa5a73d | ||
|
|
4534822355 | ||
|
|
bff29d8f07 | ||
|
|
bec34ea147 | ||
|
|
3be4171256 | ||
|
|
5bcaa7cfac | ||
|
|
ea93ef5352 | ||
|
|
8734956d86 | ||
|
|
519b3a6127 | ||
|
|
9b3773c1e6 | ||
|
|
e12b60078a | ||
|
|
7cb8f9f4ae | ||
|
|
622bd124b9 | ||
|
|
fed8b2d089 | ||
|
|
12718eabbc | ||
|
|
ab68b61653 | ||
|
|
639ade3802 | ||
|
|
3f1f899b23 | ||
|
|
51cb750502 | ||
|
|
1e6c332eae | ||
|
|
18ae2e563e | ||
|
|
a4d039c910 | ||
|
|
6163fd5644 | ||
|
|
3e2ddaca4f | ||
|
|
054a59e622 | ||
|
|
84d7290ed9 | ||
|
|
f4c1254d91 | ||
|
|
c01d22dc05 | ||
|
|
4c0f02d8a5 | ||
|
|
2770482baf | ||
|
|
8e39a00e34 | ||
|
|
7bd0d3a962 | ||
|
|
bc7f701e87 | ||
|
|
0d8116d73e | ||
|
|
255cbc1248 | ||
|
|
098aeef412 | ||
|
|
baa18aed5b | ||
|
|
b7c8dab019 | ||
|
|
587324fa38 | ||
|
|
cc3a9c8613 | ||
|
|
b0645300ec | ||
|
|
d7d4e8da03 | ||
|
|
16ae98e189 | ||
|
|
add0a3dfc6 | ||
|
|
90c349392b | ||
|
|
eb4562b6a6 | ||
|
|
6c634b686f | ||
|
|
48e03edccc | ||
|
|
cef6f11fd0 | ||
|
|
2757659989 | ||
|
|
f090395c21 | ||
|
|
dd1d554cc6 | ||
|
|
9c1b38aeaf | ||
|
|
902dd60ff9 | ||
|
|
2426a5769d | ||
|
|
66517c925b | ||
|
|
5f90e7d535 | ||
|
|
9d63eb15a9 | ||
|
|
c97bc53342 | ||
|
|
f5f60c66e7 | ||
|
|
3e15b97c8c | ||
|
|
6c08813f9b | ||
|
|
8158d44732 | ||
|
|
9bd0019759 | ||
|
|
a74f1b0e7b | ||
|
|
2b12f5db6c | ||
|
|
af4a52173c | ||
|
|
5bc1f21d46 | ||
|
|
917e437939 | ||
|
|
7ee4fb37d6 | ||
|
|
6155eec804 | ||
|
|
43d8637153 | ||
|
|
250db2fdab | ||
|
|
7bd021cd5c | ||
|
|
adb9a689f0 | ||
|
|
d8e0c2ec20 | ||
|
|
f98a74170a | ||
|
|
17b9821879 | ||
|
|
4b5bdefcb9 | ||
|
|
45cbabd94d | ||
|
|
8402eb53c8 | ||
|
|
d04ace5789 | ||
|
|
e94f587535 | ||
|
|
e73285060e | ||
|
|
f1734704ef | ||
|
|
59f6217267 | ||
|
|
90f4a222b7 | ||
|
|
749d2091eb | ||
|
|
8d34c6bcaa | ||
|
|
62577b25bb | ||
|
|
475f5a7dae | ||
|
|
1772b3aad0 | ||
|
|
7263b21a06 | ||
|
|
501adff13d | ||
|
|
12c6fb7b7f | ||
|
|
376168c922 | ||
|
|
cadab239a2 | ||
|
|
f57dc77c6d | ||
|
|
497a494c37 | ||
|
|
02069e8e5d | ||
|
|
626293392c | ||
|
|
dfe42ae3e3 | ||
|
|
453abfa145 | ||
|
|
8ebc9400ce | ||
|
|
1598f48edd | ||
|
|
cc92f37f0c | ||
|
|
9322aca6cb | ||
|
|
ee8fbd6f4f | ||
|
|
1acd61a112 | ||
|
|
e836686a71 | ||
|
|
ea6c417378 | ||
|
|
16cc9a9e69 | ||
|
|
6b5316fa84 | ||
|
|
a53f5d1289 | ||
|
|
de2ea99928 | ||
|
|
25f4332b9e | ||
|
|
f703969e80 | ||
|
|
b82681b77a | ||
|
|
ef248a8515 | ||
|
|
73a2345c26 | ||
|
|
9f33177eab | ||
|
|
d5a752c338 | ||
|
|
4021a2d697 | ||
|
|
bea4a6dcbc | ||
|
|
4f48e04cad | ||
|
|
5719dfe8a3 | ||
|
|
4fb14e85e8 | ||
|
|
1d84689b45 | ||
|
|
693aec2b4d | ||
|
|
c79c0ee138 | ||
|
|
e86e24a2db | ||
|
|
0f7ad484ce | ||
|
|
bcd95b2af9 | ||
|
|
32dcd5ed1c | ||
|
|
5119febb5b | ||
|
|
20cdfd3009 | ||
|
|
9f739427c4 | ||
|
|
0201cafd7e | ||
|
|
37f57bb29f | ||
|
|
ebd723679b | ||
|
|
961fa1f007 | ||
|
|
7900a4da0c | ||
|
|
8a24730884 | ||
|
|
1688e7dc50 | ||
|
|
aa267b54ec | ||
|
|
bc40073a02 | ||
|
|
a93f9dd0af | ||
|
|
53a9fdc4b6 | ||
|
|
cef600277c | ||
|
|
bdac438329 | ||
|
|
2d77f36a0b | ||
|
|
90aa810ce4 | ||
|
|
cf3af50464 | ||
|
|
3b5b20c139 | ||
|
|
24cd163acd | ||
|
|
49f76e5b40 | ||
|
|
871788f0a9 | ||
|
|
24138b70f1 | ||
|
|
da3332e711 | ||
|
|
06e5cf2032 | ||
|
|
d4b1923c23 | ||
|
|
42df4f6731 | ||
|
|
f1e6e94041 | ||
|
|
0cd12b2f32 | ||
|
|
5da4d24d38 | ||
|
|
7806d2ac02 | ||
|
|
2c4d182d1f | ||
|
|
dcd5f88d65 | ||
|
|
662f4ac93b | ||
|
|
a2480c6a02 | ||
|
|
c49460a44f | ||
|
|
6786dfe7e3 | ||
|
|
7d710d881a | ||
|
|
2ea2e79f6f | ||
|
|
cd42dd8ca7 | ||
|
|
f2eddeae4d | ||
|
|
8e1a8fc7e3 | ||
|
|
87c08b051f | ||
|
|
9d95a80857 | ||
|
|
9371b6d5de | ||
|
|
bdcf4b25c0 | ||
|
|
3dc344be65 | ||
|
|
17ed0f70aa | ||
|
|
be3e12e60d | ||
|
|
4261cc2ea5 | ||
|
|
88dbc27019 | ||
|
|
f38fc80c31 | ||
|
|
803fdaf443 | ||
|
|
55d85db401 | ||
|
|
7ce3d71c44 | ||
|
|
04e150e4bf | ||
|
|
0f6b118921 | ||
|
|
44277e6aa2 | ||
|
|
bb7e8cc6f1 | ||
|
|
32a64fb097 | ||
|
|
c4594397e7 | ||
|
|
6a188a4cdf | ||
|
|
0ca0defd24 | ||
|
|
b0b84f9c98 | ||
|
|
ef8d1225b5 | ||
|
|
240b7e4388 | ||
|
|
bd205d2250 | ||
|
|
e5e5bcccee | ||
|
|
a5395b0109 | ||
|
|
09cea4394f | ||
|
|
afeaddea22 | ||
|
|
45f694310a | ||
|
|
995f5118b2 | ||
|
|
415888a615 | ||
|
|
542fb9176a | ||
|
|
b8f8d8d859 | ||
|
|
0eef611b6d | ||
|
|
f0612ee860 | ||
|
|
8c85cce75c | ||
|
|
5036ac3efa | ||
|
|
9025e03422 | ||
|
|
e82e8529bf | ||
|
|
eb1ed69489 | ||
|
|
e81f3f7eae | ||
|
|
4b9964bc89 | ||
|
|
b4a2af75d0 | ||
|
|
8c3e3285f7 | ||
|
|
0a4f6ff9fb | ||
|
|
bfa1367ca2 | ||
|
|
bb81a2f165 | ||
|
|
7f448b1cab | ||
|
|
2dd35c0d6e | ||
|
|
0e73346c5f | ||
|
|
8476595507 | ||
|
|
7b9284edb9 | ||
|
|
c982b33212 | ||
|
|
3c8466d714 | ||
|
|
eeea391b63 | ||
|
|
5c2dca1c51 | ||
|
|
e6e4c6f7b5 | ||
|
|
5f6f9428ac | ||
|
|
ba54b61dcf | ||
|
|
8dc2bad843 | ||
|
|
3594cbd5ca | ||
|
|
21b1e4e719 | ||
|
|
50a17b6263 | ||
|
|
0a920def2b | ||
|
|
c4b1471923 | ||
|
|
ab08ed0d7c | ||
|
|
34c13a747d | ||
|
|
d559d8853d | ||
|
|
a96d9cd075 | ||
|
|
b163888cf3 | ||
|
|
b07e2c397c | ||
|
|
3eeba1da2b | ||
|
|
e160b1bf07 | ||
|
|
1199b36d1a | ||
|
|
7a506478c7 | ||
|
|
6faa40e0c2 | ||
|
|
768657d7e5 | ||
|
|
7157cca22f | ||
|
|
7aec79d3ad | ||
|
|
4357d5ec5d | ||
|
|
7c1c8b2749 | ||
|
|
15656bd5c8 | ||
|
|
c4897a7026 | ||
|
|
e993a47720 | ||
|
|
0d4c65ad79 | ||
|
|
f09bdb2b00 | ||
|
|
f1400ae58e | ||
|
|
b5496097d2 | ||
|
|
d5fb495e19 | ||
|
|
00e716bc3f | ||
|
|
ea4edd668f | ||
|
|
a22db125a9 | ||
|
|
e7f68c2e20 | ||
|
|
933b13f3fa | ||
|
|
0be6c9c734 | ||
|
|
5aac331368 | ||
|
|
57ec484626 | ||
|
|
9cd832bfa9 | ||
|
|
299cc40ff5 | ||
|
|
6d305bacdf | ||
|
|
6fd3177844 | ||
|
|
5586d34293 | ||
|
|
d43d242b16 | ||
|
|
9f620e8c4b | ||
|
|
6c9afcc734 | ||
|
|
43d6c85f7e | ||
|
|
78056e0041 | ||
|
|
e83a2d6aec | ||
|
|
bac06fe182 | ||
|
|
8ff6518797 | ||
|
|
f0e7c25e4c | ||
|
|
0da94965dc | ||
|
|
d82eed16b7 | ||
|
|
b26748a2a7 | ||
|
|
a2d7f5e8cc | ||
|
|
72ffa3bd9a | ||
|
|
e2fccaee74 | ||
|
|
e41b209cb8 | ||
|
|
2517caf674 | ||
|
|
b9ec0d5f53 | ||
|
|
02e614632f | ||
|
|
3ca73901c9 | ||
|
|
c379eed266 | ||
|
|
5bac4fd719 | ||
|
|
dd610e4c0f | ||
|
|
bf080cb001 | ||
|
|
169088df26 | ||
|
|
4a2a29f154 | ||
|
|
1054962008 | ||
|
|
8bc8603460 | ||
|
|
6538b0bfeb | ||
|
|
9d2339bb3b | ||
|
|
096f38d365 | ||
|
|
1046edd903 | ||
|
|
cbf504dbb8 | ||
|
|
8491872908 | ||
|
|
c207918e90 | ||
|
|
12717f692b | ||
|
|
36d630b37b | ||
|
|
5333fe7c3a | ||
|
|
efae78056e | ||
|
|
6eca64a8f7 | ||
|
|
fcb629ca06 | ||
|
|
289f1af253 | ||
|
|
8adc3ecb0b | ||
|
|
e328c001a1 | ||
|
|
f796a31613 | ||
|
|
e1bab2e353 | ||
|
|
1c135176d2 | ||
|
|
723f0d6e6e | ||
|
|
e14d193b43 | ||
|
|
9d1733bdb3 | ||
|
|
e06436d6f5 | ||
|
|
4f67e2b362 | ||
|
|
8aa3415d73 | ||
|
|
74f22e89ce | ||
|
|
7d826d1602 | ||
|
|
8aa39bc7db | ||
|
|
36dcf51024 | ||
|
|
3e74180bdc | ||
|
|
45ed740575 | ||
|
|
8092ad8c4d | ||
|
|
b4d9cdc584 | ||
|
|
36b85512c6 | ||
|
|
14ae64f5f3 | ||
|
|
990176ac7c | ||
|
|
69ef46356b | ||
|
|
bd88c7b04b | ||
|
|
03641f622f | ||
|
|
3b1eb56713 | ||
|
|
059bcc6c53 | ||
|
|
82043ce2a8 | ||
|
|
470e752fba | ||
|
|
3cc7b9050c | ||
|
|
b1f7c78c7e | ||
|
|
8f20b29b16 | ||
|
|
19efbd3d61 | ||
|
|
f35c0effa2 | ||
|
|
8363cc0844 | ||
|
|
5a11cacbae | ||
|
|
27151a9487 | ||
|
|
c152b25deb | ||
|
|
04d3afaf7b | ||
|
|
dbc63e9ef7 | ||
|
|
ce91ff95ab | ||
|
|
d75a29f099 | ||
|
|
cb889b1160 | ||
|
|
8db4f5cb63 | ||
|
|
d297dc5805 | ||
|
|
9b8659a40b | ||
|
|
96c5db3f5d | ||
|
|
78e403819e | ||
|
|
805acf4e5e | ||
|
|
9f099a9127 | ||
|
|
4d15c39cd7 | ||
|
|
827451d12d | ||
|
|
03603662c6 | ||
|
|
34eb10cd88 | ||
|
|
82941c08c9 | ||
|
|
8d21c97d08 | ||
|
|
71a56f590d | ||
|
|
38297c4fe7 | ||
|
|
cf7ec06d85 | ||
|
|
f2ea10f951 | ||
|
|
bbd93df239 | ||
|
|
9a6ab93e01 | ||
|
|
38eed7cce6 | ||
|
|
79064c3399 | ||
|
|
0496b2f530 | ||
|
|
9d0be1ebd1 | ||
|
|
9ad026b8ce | ||
|
|
14de5971d5 | ||
|
|
5474be3efa | ||
|
|
9a54bbba2d | ||
|
|
5a0110ccc8 | ||
|
|
d032d577bf | ||
|
|
243954c9c5 | ||
|
|
ba1be73389 | ||
|
|
af3ad02962 | ||
|
|
53ddca725e | ||
|
|
094fb0d1c8 | ||
|
|
dc230926a4 | ||
|
|
026ace6747 | ||
|
|
374db9ed2b | ||
|
|
5ee59c4675 | ||
|
|
33605171a8 | ||
|
|
89fac5b088 | ||
|
|
4a34b942b7 | ||
|
|
fc3065ebe4 | ||
|
|
23493b4ac2 | ||
|
|
13344096b7 | ||
|
|
a800430997 | ||
|
|
509562e6da | ||
|
|
88d85919f1 | ||
|
|
154e223284 | ||
|
|
58732f7770 | ||
|
|
cb4c847d41 | ||
|
|
d3976e33f8 | ||
|
|
8e17970632 | ||
|
|
c0048504db | ||
|
|
5015452280 | ||
|
|
c504b68354 | ||
|
|
5d2e5932a4 | ||
|
|
cf1a7d7a8a | ||
|
|
14a935db81 | ||
|
|
f98a40062a | ||
|
|
f7ebc1492c | ||
|
|
da3922586a | ||
|
|
28184f8d4d | ||
|
|
a4e7522ca0 | ||
|
|
59b3d30323 | ||
|
|
53cac0b614 | ||
|
|
82c29398d3 | ||
|
|
6d289e31c7 | ||
|
|
5ec02c3089 | ||
|
|
9940273cd9 | ||
|
|
21c7b9872e | ||
|
|
fa99ec6f8f | ||
|
|
78f7db9250 | ||
|
|
c101610c46 | ||
|
|
6d383c7d0a | ||
|
|
2ca756d219 | ||
|
|
1153327c75 | ||
|
|
42e45a0e3a | ||
|
|
9f5a5b16d3 | ||
|
|
44ecd928f0 | ||
|
|
3f5c8d8d0a | ||
|
|
e32c5b73a7 | ||
|
|
21e806b991 | ||
|
|
29e244d4eb | ||
|
|
0b6edf5690 | ||
|
|
9af7719d34 | ||
|
|
9e5b4da954 | ||
|
|
b807234806 | ||
|
|
3445b94af3 | ||
|
|
c226eb7211 | ||
|
|
3afad20e36 | ||
|
|
86497155cd | ||
|
|
af82974c8a | ||
|
|
bd4117fa0a | ||
|
|
f004685424 | ||
|
|
b268320406 | ||
|
|
7a33b3198a | ||
|
|
66791d3ca2 | ||
|
|
a0d4a33fd4 | ||
|
|
fdd12194b1 | ||
|
|
bf11445299 | ||
|
|
61bf8f6ad3 | ||
|
|
52282bfccf | ||
|
|
cf3a31ac42 | ||
|
|
f56ccf5ef5 | ||
|
|
51e2eee15a | ||
|
|
de97bf908d | ||
|
|
099fb80da2 | ||
|
|
022ccc794d | ||
|
|
987768e8dc | ||
|
|
a3ffe963c3 | ||
|
|
b51562d0e3 | ||
|
|
38e86acffe | ||
|
|
38a299d852 | ||
|
|
55b25c919d | ||
|
|
2af4cc98fd | ||
|
|
e68b5b8b5a | ||
|
|
317b4e26c0 | ||
|
|
af5bee9149 | ||
|
|
26939eccce | ||
|
|
54360708d9 | ||
|
|
e441c7229c | ||
|
|
54e5fe6ef9 | ||
|
|
6fc0f1ccd7 | ||
|
|
6cd30d893a | ||
|
|
dceb9061d9 | ||
|
|
21438b2d8f | ||
|
|
793e853eb3 | ||
|
|
9cbe0efbbb | ||
|
|
9219b886fe | ||
|
|
2377a4c9d0 | ||
|
|
986c586683 | ||
|
|
7be52fa9fc | ||
|
|
32d7ae3eef | ||
|
|
ef6fb4903f | ||
|
|
0fe3f7523d | ||
|
|
9991534c83 | ||
|
|
455681b24c | ||
|
|
14e63085dd | ||
|
|
e8cb1cefbd | ||
|
|
919e890011 | ||
|
|
299172c8aa | ||
|
|
6cac93ef39 | ||
|
|
e5c8ef7d60 | ||
|
|
d0b4688a6c | ||
|
|
e0464ee5be | ||
|
|
cbcd299bd9 | ||
|
|
1300e5a690 | ||
|
|
fbd653d8e0 | ||
|
|
eb4f41e80c | ||
|
|
589a01a2da | ||
|
|
aae6b99761 | ||
|
|
5d35047734 | ||
|
|
98d10215d6 | ||
|
|
6656628bba | ||
|
|
37f46fc62d | ||
|
|
9efd2b0a73 | ||
|
|
b1fb2c14a1 | ||
|
|
c5d910425e | ||
|
|
0a9e64d36a | ||
|
|
7d02b7959f | ||
|
|
0670380360 | ||
|
|
904987795a | ||
|
|
4ee1b2294a | ||
|
|
97eb84fd46 | ||
|
|
5eb7822691 | ||
|
|
79cf57abe4 | ||
|
|
075bdb5128 | ||
|
|
65698051ac | ||
|
|
95559f17d8 | ||
|
|
aabc13e3cb | ||
|
|
b71ced9b2e | ||
|
|
bb34c73069 | ||
|
|
94bbbd1021 | ||
|
|
670a3a970e | ||
|
|
7a938c85f6 | ||
|
|
3a6bc4bc7b | ||
|
|
c54d7bcc88 | ||
|
|
b81bfc80fd | ||
|
|
d8bad50eec | ||
|
|
3fe6217809 | ||
|
|
50a947a722 | ||
|
|
7fe5aad16e | ||
|
|
97d559f749 | ||
|
|
188f783fae | ||
|
|
3a064dd728 | ||
|
|
202856c0f7 | ||
|
|
406340fa65 | ||
|
|
735ecc1cca | ||
|
|
7b646f891e | ||
|
|
19264d7f81 | ||
|
|
76ce060d13 | ||
|
|
9b3dc19037 | ||
|
|
5821a68816 | ||
|
|
e21544eac2 | ||
|
|
1f0f7d1222 | ||
|
|
69e0086144 | ||
|
|
61ce8729de | ||
|
|
44869b0ce4 | ||
|
|
213dd53ee8 | ||
|
|
844952db51 | ||
|
|
eda29c0e34 | ||
|
|
5834e32aa5 | ||
|
|
a59f3d0d0c | ||
|
|
5b8a46d087 | ||
|
|
677e6e5d6e | ||
|
|
62f40116be | ||
|
|
d2d199e136 | ||
|
|
39e2c89d5c | ||
|
|
15f4417c68 | ||
|
|
943b948de7 | ||
|
|
b7f75e25ad | ||
|
|
2af0405317 | ||
|
|
a2099fb0e2 | ||
|
|
52781cfa2d | ||
|
|
af7469fa1f | ||
|
|
4c14ba0a5e | ||
|
|
b49cf349a8 | ||
|
|
02406925d7 | ||
|
|
aad7e1a551 | ||
|
|
a98a9fe6a9 | ||
|
|
ac6fcc8c40 | ||
|
|
b0e882645e | ||
|
|
8c431c7562 | ||
|
|
3e267b8104 | ||
|
|
7c5cab2144 | ||
|
|
5cb893245f | ||
|
|
aa1c636cc2 | ||
|
|
c285854b71 | ||
|
|
01a29d629b | ||
|
|
bd381ccc74 | ||
|
|
c3e747aaa4 | ||
|
|
480d56125d | ||
|
|
7ec155eac1 | ||
|
|
c8ff177f85 | ||
|
|
f276bb1cd2 | ||
|
|
208632e648 | ||
|
|
8cfac127f5 | ||
|
|
ac76bee5a3 | ||
|
|
171dc7e5b7 | ||
|
|
051985b767 | ||
|
|
1eb85410bf | ||
|
|
6697db7cf8 | ||
|
|
56f6009390 | ||
|
|
d339b82f8e | ||
|
|
82eb87bc47 | ||
|
|
991be1c5a2 | ||
|
|
0d96a4574a | ||
|
|
61b4511ae4 | ||
|
|
137edc7cfb | ||
|
|
14e772a751 | ||
|
|
32afbf12d6 | ||
|
|
ffaf5119d8 | ||
|
|
10bc8c1efa | ||
|
|
85a03a9e39 | ||
|
|
51ee6567b4 | ||
|
|
090220a29d | ||
|
|
e7973b8be0 | ||
|
|
b5324c9223 | ||
|
|
edb8d80077 | ||
|
|
ddee116339 | ||
|
|
bdacaea4a8 | ||
|
|
9e28e02b5d | ||
|
|
3527dc95a2 | ||
|
|
27c7b2722d | ||
|
|
ba96f52ed6 | ||
|
|
2c8b3ff45c | ||
|
|
631bc2307a | ||
|
|
8f4f9a8601 | ||
|
|
1c920f966e | ||
|
|
2b1de38949 | ||
|
|
d5daf61dbd | ||
|
|
06c42ce02f | ||
|
|
4f21430880 | ||
|
|
9731bac40f | ||
|
|
b144e650f2 | ||
|
|
ef6536644c | ||
|
|
17eab43245 | ||
|
|
fbd7f1e3b8 | ||
|
|
25af7516a4 | ||
|
|
c020eded31 | ||
|
|
5331c0216a | ||
|
|
528777926c | ||
|
|
47b5c3d4f0 | ||
|
|
d9bfca66d6 | ||
|
|
ded51b65d3 | ||
|
|
ddc8837d4f | ||
|
|
df16957c95 | ||
|
|
f38b19d4bd | ||
|
|
f7cd4f2c74 | ||
|
|
a078392888 | ||
|
|
3060f23f8c |
No files matched your search
+45
-41
@@ -1,22 +1,21 @@
|
||||
FROM chrislusf/seaweedfs:4.31 AS seaweedfs
|
||||
FROM chrislusf/seaweedfs:4.47 AS seaweedfs
|
||||
|
||||
FROM erlang:28.5.0.1
|
||||
FROM erlang:28.5.0.6
|
||||
|
||||
ARG USERNAME=vscode
|
||||
ARG USER_UID=1000
|
||||
ARG USER_GID=1000
|
||||
ARG NODE_MAJOR=24
|
||||
ARG ELP_VERSION=2026-02-27
|
||||
ARG HELM_VERSION=4.2.0
|
||||
ARG PNPM_VERSION=10.29.3
|
||||
ARG WASM_BINDGEN_VERSION=0.2.122
|
||||
ARG NODE_MAJOR=26
|
||||
ARG ELP_VERSION=2026-08-10
|
||||
ARG PNPM_VERSION=11.27.0
|
||||
ARG WASM_BINDGEN_VERSION=0.2.128
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
acl \
|
||||
bash \
|
||||
brotli \
|
||||
build-essential \
|
||||
ca-certificates \
|
||||
clang \
|
||||
@@ -33,6 +32,7 @@ RUN apt-get update \
|
||||
jq \
|
||||
libasound2 \
|
||||
libatk-bridge2.0-0 \
|
||||
libaom-dev \
|
||||
libavcodec-dev \
|
||||
libavfilter-dev \
|
||||
libavformat-dev \
|
||||
@@ -42,19 +42,25 @@ RUN apt-get update \
|
||||
libfido2-dev \
|
||||
libgbm1 \
|
||||
libgtk-3-0 \
|
||||
libimage-exiftool-perl \
|
||||
libnotify4 \
|
||||
libnss3 \
|
||||
libpipewire-0.3-dev \
|
||||
libpulse-dev \
|
||||
libsecret-1-0 \
|
||||
libudev-dev \
|
||||
libuv1-dev \
|
||||
libcurl4-openssl-dev \
|
||||
libswresample-dev \
|
||||
libswscale-dev \
|
||||
libdav1d-dev \
|
||||
libde265-dev \
|
||||
liblcms2-dev \
|
||||
libvips-dev \
|
||||
libyuv-dev \
|
||||
libwayland-dev \
|
||||
libwebp-dev \
|
||||
nasm \
|
||||
yasm \
|
||||
libssl-dev \
|
||||
libx11-xcb1 \
|
||||
libxcb-dri3-0 \
|
||||
@@ -71,16 +77,15 @@ RUN apt-get update \
|
||||
ninja-build \
|
||||
openssh-client \
|
||||
pkg-config \
|
||||
protobuf-compiler \
|
||||
python3 \
|
||||
python3-pip \
|
||||
rsync \
|
||||
python3-venv \
|
||||
sudo \
|
||||
rpm \
|
||||
unzip \
|
||||
webp \
|
||||
xz-utils \
|
||||
xdg-utils \
|
||||
zlib1g-dev \
|
||||
zstd \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
@@ -90,6 +95,7 @@ RUN apt-get update \
|
||||
bat \
|
||||
btop \
|
||||
docker-cli \
|
||||
docker-compose \
|
||||
dnsutils \
|
||||
fd-find \
|
||||
gdb \
|
||||
@@ -122,24 +128,33 @@ RUN apt-get update \
|
||||
&& ln -sf /usr/bin/batcat /usr/local/bin/bat \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN curl -fsSL https://deb.nodesource.com/setup_${NODE_MAJOR}.x | bash - \
|
||||
RUN curl --retry 5 --retry-delay 2 --retry-all-errors -fsSL https://deb.nodesource.com/setup_${NODE_MAJOR}.x | bash - \
|
||||
&& apt-get install -y --no-install-recommends nodejs \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& corepack enable
|
||||
&& npm install -g "pnpm@${PNPM_VERSION}" \
|
||||
&& pnpm --version
|
||||
|
||||
RUN ARCH="$(dpkg --print-architecture)" \
|
||||
&& case "$ARCH" in \
|
||||
amd64) HELM_ARCH="amd64" ;; \
|
||||
arm64) HELM_ARCH="arm64" ;; \
|
||||
*) echo "Unsupported architecture for Helm: $ARCH" >&2; exit 1 ;; \
|
||||
esac \
|
||||
&& curl -fsSL "https://get.helm.sh/helm-v${HELM_VERSION}-linux-${HELM_ARCH}.tar.gz" -o /tmp/helm.tgz \
|
||||
&& tar -C /tmp -xzf /tmp/helm.tgz "linux-${HELM_ARCH}/helm" \
|
||||
&& mv "/tmp/linux-${HELM_ARCH}/helm" /usr/local/bin/helm \
|
||||
&& chmod +x /usr/local/bin/helm \
|
||||
&& rm -rf /tmp/helm.tgz "/tmp/linux-${HELM_ARCH}"
|
||||
RUN python3 -m pip install --break-system-packages --no-cache-dir awscli
|
||||
|
||||
RUN python3 -m pip install --break-system-packages --no-cache-dir awscli cqlsh
|
||||
COPY fluxer_media_proxy/tools/install-native-deps.sh /tmp/fluxer-install-native-deps.sh
|
||||
RUN /tmp/fluxer-install-native-deps.sh /usr/local \
|
||||
&& rm /tmp/fluxer-install-native-deps.sh
|
||||
|
||||
ENV PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:/usr/local/lib64/pkgconfig
|
||||
ENV LD_LIBRARY_PATH=/usr/local/lib
|
||||
|
||||
RUN printf '%s\n' \
|
||||
'#include <libheif/heif.h>' \
|
||||
'#include <string.h>' \
|
||||
'#if !LIBHEIF_HAVE_VERSION(1, 23, 0)' \
|
||||
'#error the source-built libheif headers must win the include search' \
|
||||
'#endif' \
|
||||
'int main(void) { return strcmp(heif_get_version(), LIBHEIF_VERSION) != 0; }' \
|
||||
>/tmp/fluxer-heif-probe.c \
|
||||
&& cc /tmp/fluxer-heif-probe.c $(pkg-config --cflags --libs libheif) -o /tmp/fluxer-heif-probe \
|
||||
&& /tmp/fluxer-heif-probe \
|
||||
&& [ "$(pkg-config --variable=prefix libheif)" = /usr/local ] \
|
||||
&& rm /tmp/fluxer-heif-probe.c /tmp/fluxer-heif-probe
|
||||
|
||||
COPY tools/fonts/requirements.txt /tmp/fluxer-fonts-requirements.txt
|
||||
RUN python3 -m pip install --break-system-packages --no-cache-dir -r /tmp/fluxer-fonts-requirements.txt \
|
||||
@@ -147,18 +162,13 @@ RUN python3 -m pip install --break-system-packages --no-cache-dir -r /tmp/fluxer
|
||||
&& pyftsubset --help >/dev/null \
|
||||
&& python3 -c "import fontTools, brotli"
|
||||
|
||||
RUN if ! command -v rebar3 >/dev/null 2>&1; then \
|
||||
curl -fsSL https://s3.amazonaws.com/rebar3/rebar3 -o /usr/local/bin/rebar3 \
|
||||
&& chmod +x /usr/local/bin/rebar3; \
|
||||
fi
|
||||
|
||||
RUN ARCH="$(dpkg --print-architecture)" \
|
||||
&& case "$ARCH" in \
|
||||
amd64) ELP_ARCH="x86_64" ;; \
|
||||
arm64) ELP_ARCH="aarch64" ;; \
|
||||
*) echo "Unsupported architecture for ELP: $ARCH" >&2; exit 1 ;; \
|
||||
esac \
|
||||
&& curl -fsSL "https://github.com/WhatsApp/erlang-language-platform/releases/download/${ELP_VERSION}/elp-linux-${ELP_ARCH}-unknown-linux-gnu-otp-28.tar.gz" -o /tmp/elp.tgz \
|
||||
&& curl --retry 5 --retry-delay 2 --retry-all-errors -fsSL "https://github.com/WhatsApp/erlang-language-platform/releases/download/${ELP_VERSION}/elp-linux-${ELP_ARCH}-unknown-linux-gnu-otp-28.5.tar.gz" -o /tmp/elp.tgz \
|
||||
&& tar -C /usr/local/bin -xzf /tmp/elp.tgz elp \
|
||||
&& chmod +x /usr/local/bin/elp \
|
||||
&& rm /tmp/elp.tgz
|
||||
@@ -179,16 +189,10 @@ ENV DOCKER_HOST="unix:///var/run/docker.sock" \
|
||||
ENV CC_wasm32_unknown_unknown="clang" \
|
||||
AR_wasm32_unknown_unknown="llvm-ar"
|
||||
|
||||
RUN curl -fsSL https://sh.rustup.rs | sh -s -- -y --profile default --component clippy,rustfmt \
|
||||
RUN curl --retry 5 --retry-delay 2 --retry-all-errors -fsSL https://sh.rustup.rs | sh -s -- -y --profile minimal --component clippy,rustfmt \
|
||||
&& rustup target add wasm32-unknown-unknown \
|
||||
&& cargo install cargo-watch --locked \
|
||||
&& cargo install wasm-bindgen-cli --version "${WASM_BINDGEN_VERSION}" --locked
|
||||
|
||||
RUN corepack prepare "pnpm@${PNPM_VERSION}" --activate \
|
||||
&& pnpm --version
|
||||
|
||||
RUN sudo apt-get update \
|
||||
&& sudo apt-get install -y --no-install-recommends python3-venv \
|
||||
&& sudo rm -rf /var/lib/apt/lists/*
|
||||
&& cargo install wasm-bindgen-cli --version "${WASM_BINDGEN_VERSION}" --locked \
|
||||
&& rm -rf "/home/${USERNAME}/.cargo/registry" "/home/${USERNAME}/.cargo/git"
|
||||
|
||||
WORKDIR /workspaces/fluxer
|
||||
@@ -5,20 +5,17 @@
|
||||
"workspaceFolder": "/workspaces/fluxer",
|
||||
"shutdownAction": "stopCompose",
|
||||
"remoteUser": "vscode",
|
||||
"hostRequirements": {
|
||||
"cpus": 4,
|
||||
"memory": "8gb",
|
||||
"storage": "32gb"
|
||||
},
|
||||
"remoteEnv": {
|
||||
"DOCKER_HOST": "unix:///var/run/docker.sock"
|
||||
},
|
||||
"runServices": ["workspace", "postgres", "valkey", "nats", "livekit", "meilisearch", "mailpit"],
|
||||
"forwardPorts": [
|
||||
3000, 8088, 8080, 8771, 8082, 3010, 3020, 8100, 8101, 8102, 8103, 8104, 8105, 8106, 8107, 8108, 8109, 8110, 8111,
|
||||
8112, 8113, 8114, 8115, 8116, 8117, 8118, 8119, 8120, 8121, 8122, 8123, 8124, 8125, 3900, 8888, 9333, 9340, 23646,
|
||||
4222, 7700, 7880, 7900, 9200, 8000
|
||||
],
|
||||
"forwardPorts": [3000, 8088, 8080, 8771, 8082, 8773, 3020, 8333],
|
||||
"portsAttributes": {
|
||||
"8000": {
|
||||
"label": "Zensical docs",
|
||||
"onAutoForward": "openBrowserOnce"
|
||||
},
|
||||
"8088": {
|
||||
"label": "Fluxer dev proxy",
|
||||
"onAutoForward": "notify"
|
||||
@@ -29,40 +26,23 @@
|
||||
"3020": {
|
||||
"label": "Fluxer admin"
|
||||
},
|
||||
"8100": {
|
||||
"label": "Fluxer Rust service health"
|
||||
},
|
||||
"3900": {
|
||||
"8333": {
|
||||
"label": "SeaweedFS S3"
|
||||
},
|
||||
"8888": {
|
||||
"label": "SeaweedFS filer"
|
||||
},
|
||||
"9333": {
|
||||
"label": "SeaweedFS master"
|
||||
},
|
||||
"9340": {
|
||||
"label": "SeaweedFS volume"
|
||||
},
|
||||
"23646": {
|
||||
"label": "SeaweedFS admin"
|
||||
},
|
||||
"7880": {
|
||||
"label": "LiveKit"
|
||||
},
|
||||
"7700": {
|
||||
"label": "Meilisearch"
|
||||
},
|
||||
"9200": {
|
||||
"label": "Elasticsearch"
|
||||
"8773": {
|
||||
"label": "Fluxer app proxy"
|
||||
}
|
||||
},
|
||||
"postCreateCommand": "sudo chown -R vscode:vscode /workspaces/fluxer/target && find /workspaces/fluxer -maxdepth 4 -type d -name node_modules -prune -exec sudo chown -R vscode:vscode {} + && sudo chown -R vscode:vscode /home/vscode/.local/share/pnpm && cargo run -p fluxer-dev -- bootstrap",
|
||||
"postStartCommand": "bash /workspaces/fluxer/.devcontainer/fix-docker-socket.sh && cargo run -p fluxer-dev -- post-start && bash /workspaces/fluxer/fluxer_docs/serve.sh --daemon",
|
||||
"postCreateCommand": "bash /workspaces/fluxer/.devcontainer/fix-docker-socket.sh && bash /workspaces/fluxer/.devcontainer/fix-workspace-permissions.sh && cargo run -p fluxer-dev -- bootstrap",
|
||||
"postStartCommand": "bash /workspaces/fluxer/.devcontainer/fix-docker-socket.sh && bash /workspaces/fluxer/.devcontainer/fix-workspace-permissions.sh && cargo run -p fluxer-dev -- post-start",
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
"settings": {
|
||||
"editor.defaultFormatter": "biomejs.biome"
|
||||
"editor.defaultFormatter": "biomejs.biome",
|
||||
"erlang.includePaths": ["."],
|
||||
"search.exclude": {
|
||||
"**/_build/default/lib/fluxer_gateway": true
|
||||
}
|
||||
},
|
||||
"extensions": [
|
||||
"biomejs.biome",
|
||||
|
||||
@@ -7,15 +7,27 @@ services:
|
||||
dockerfile: .devcontainer/Dockerfile
|
||||
command: sleep infinity
|
||||
init: true
|
||||
env_file:
|
||||
- ../config/env/development.env
|
||||
environment:
|
||||
FLUXER_SEARCH_ENGINE: meilisearch
|
||||
FLUXER_SEARCH_URL: http://meilisearch:7700
|
||||
FLUXER_SEARCH_API_KEY: fluxer-dev-meilisearch
|
||||
FLUXER_POSTGRES_HOST: postgres
|
||||
FLUXER_SELF_HOSTED: "true"
|
||||
DOCKER_HOST: unix:///var/run/docker.sock
|
||||
pnpm_config_store_dir: /home/vscode/.local/share/pnpm/store
|
||||
FLUXER_PUBLIC_PORT: "${FLUXER_DEV_PROXY_PORT:-8088}"
|
||||
FLUXER_PUBLIC_URL: "http://localhost:${FLUXER_DEV_PROXY_PORT:-8088}"
|
||||
FLUXER_API_ENDPOINT: "http://localhost:${FLUXER_DEV_PROXY_PORT:-8088}/api"
|
||||
FLUXER_API_CLIENT_ENDPOINT: "http://localhost:${FLUXER_DEV_PROXY_PORT:-8088}/api"
|
||||
FLUXER_APP_ENDPOINT: "http://localhost:${FLUXER_DEV_PROXY_PORT:-8088}"
|
||||
FLUXER_GATEWAY_ENDPOINT: "ws://localhost:${FLUXER_DEV_PROXY_PORT:-8088}/gateway"
|
||||
FLUXER_MEDIA_ENDPOINT: "http://localhost:${FLUXER_DEV_PROXY_PORT:-8088}/media"
|
||||
FLUXER_STATIC_CDN_ENDPOINT: "http://localhost:${FLUXER_DEV_PROXY_PORT:-8088}"
|
||||
FLUXER_ADMIN_ENDPOINT: "http://localhost:${FLUXER_DEV_PROXY_PORT:-8088}/admin"
|
||||
FLUXER_MEDIA_PROXY_PUBLIC_ENDPOINT: "http://localhost:${FLUXER_DEV_PROXY_PORT:-8088}/media"
|
||||
FLUXER_S3_PUBLIC_ENDPOINT: "http://localhost:${FLUXER_DEV_PROXY_PORT:-8088}"
|
||||
FLUXER_LIVEKIT_URL: "ws://localhost:${FLUXER_DEV_PROXY_PORT:-8088}/livekit"
|
||||
FLUXER_LIVEKIT_INTERNAL_URL: "http://livekit:7880"
|
||||
FLUXER_MEDIA_PROXY_UPLOAD_RELAY_ENDPOINT: "http://localhost:${FLUXER_DEV_PROXY_PORT:-8088}/media"
|
||||
FLUXER_GATEWAY_MEDIA_PROXY_ENDPOINT: "http://localhost:${FLUXER_DEV_PROXY_PORT:-8088}/media"
|
||||
FLUXER_GATEWAY_STATIC_CDN_ENDPOINT: "http://localhost:${FLUXER_DEV_PROXY_PORT:-8088}"
|
||||
FLUXER_ADMIN_OAUTH_REDIRECT_URI: "http://localhost:${FLUXER_DEV_PROXY_PORT:-8088}/admin/oauth2_callback"
|
||||
FLUXER_PASSKEY_ADDITIONAL_ALLOWED_ORIGINS: "http://localhost,http://localhost:${FLUXER_DEV_PROXY_PORT:-8088}"
|
||||
volumes:
|
||||
- ..:/workspaces/fluxer:cached
|
||||
- type: volume
|
||||
@@ -73,11 +85,6 @@ services:
|
||||
target: /workspaces/fluxer/packages/hono/node_modules
|
||||
volume:
|
||||
nocopy: true
|
||||
- type: volume
|
||||
source: package-hono-types-node-modules
|
||||
target: /workspaces/fluxer/packages/hono_types/node_modules
|
||||
volume:
|
||||
nocopy: true
|
||||
- type: volume
|
||||
source: package-i18n-node-modules
|
||||
target: /workspaces/fluxer/packages/i18n/node_modules
|
||||
@@ -153,21 +160,11 @@ services:
|
||||
target: /workspaces/fluxer/fluxer_api/pkgs/http_client/node_modules
|
||||
volume:
|
||||
nocopy: true
|
||||
- type: volume
|
||||
source: fluxer-api-initialization-node-modules
|
||||
target: /workspaces/fluxer/fluxer_api/pkgs/initialization/node_modules
|
||||
volume:
|
||||
nocopy: true
|
||||
- type: volume
|
||||
source: fluxer-api-kv-client-node-modules
|
||||
target: /workspaces/fluxer/fluxer_api/pkgs/kv_client/node_modules
|
||||
volume:
|
||||
nocopy: true
|
||||
- type: volume
|
||||
source: fluxer-api-locale-node-modules
|
||||
target: /workspaces/fluxer/fluxer_api/pkgs/locale/node_modules
|
||||
volume:
|
||||
nocopy: true
|
||||
- type: volume
|
||||
source: fluxer-api-media-proxy-utils-node-modules
|
||||
target: /workspaces/fluxer/fluxer_api/pkgs/media_proxy_utils/node_modules
|
||||
@@ -188,11 +185,6 @@ services:
|
||||
target: /workspaces/fluxer/fluxer_api/pkgs/rate_limit/node_modules
|
||||
volume:
|
||||
nocopy: true
|
||||
- type: volume
|
||||
source: fluxer-api-sms-node-modules
|
||||
target: /workspaces/fluxer/fluxer_api/pkgs/sms/node_modules
|
||||
volume:
|
||||
nocopy: true
|
||||
- type: volume
|
||||
source: fluxer-api-virus-scan-node-modules
|
||||
target: /workspaces/fluxer/fluxer_api/pkgs/virus_scan/node_modules
|
||||
@@ -236,45 +228,30 @@ services:
|
||||
source: ${FLUXER_DOCKER_SOCKET:-/var/run/docker.sock}
|
||||
target: /var/run/docker.sock
|
||||
ports:
|
||||
- "${FLUXER_DEV_DOCS_PORT:-8000}:8000"
|
||||
- "${FLUXER_DEV_RSPACK_PORT:-3000}:3000"
|
||||
- "${FLUXER_DEV_PROXY_PORT:-8088}:8088"
|
||||
- "${FLUXER_DEV_APP_PROXY_PORT:-8080}:8080"
|
||||
- "${FLUXER_DEV_API_PORT:-8771}:8771"
|
||||
- "${FLUXER_DEV_GATEWAY_PORT:-8082}:8082"
|
||||
- "${FLUXER_DEV_MARKETING_PORT:-3010}:3010"
|
||||
- "${FLUXER_DEV_ADMIN_PORT:-3020}:3020"
|
||||
- "${FLUXER_DEV_RUST_SERVICE_PORTS:-8100-8125}:8100-8125"
|
||||
- "${FLUXER_DEV_SEAWEEDFS_S3_PORT:-3900}:8333"
|
||||
- "${FLUXER_DEV_SEAWEEDFS_FILER_PORT:-8888}:8888"
|
||||
- "${FLUXER_DEV_SEAWEEDFS_MASTER_PORT:-9333}:9333"
|
||||
- "${FLUXER_DEV_SEAWEEDFS_VOLUME_PORT:-9340}:9340"
|
||||
- "${FLUXER_DEV_SEAWEEDFS_ADMIN_PORT:-23646}:23646"
|
||||
- "127.0.0.1:${FLUXER_DEV_RSPACK_PORT:-3000}:3000"
|
||||
- "127.0.0.1:${FLUXER_DEV_PROXY_PORT:-8088}:8088"
|
||||
- "127.0.0.1:${FLUXER_DEV_API_PORT:-8080}:8080"
|
||||
- "127.0.0.1:${FLUXER_DEV_GATEWAY_PORT:-8771}:8771"
|
||||
- "127.0.0.1:${FLUXER_DEV_MEDIA_PROXY_PORT:-8082}:8082"
|
||||
- "127.0.0.1:${FLUXER_DEV_APP_PROXY_PORT:-8773}:8773"
|
||||
- "127.0.0.1:${FLUXER_DEV_ADMIN_PORT:-3020}:3020"
|
||||
- "127.0.0.1:${FLUXER_DEV_SEAWEEDFS_S3_PORT:-3900}:8333"
|
||||
depends_on:
|
||||
- postgres
|
||||
- valkey
|
||||
- nats
|
||||
- livekit
|
||||
- meilisearch
|
||||
- mailpit
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
valkey:
|
||||
condition: service_started
|
||||
nats:
|
||||
condition: service_started
|
||||
livekit:
|
||||
condition: service_started
|
||||
meilisearch:
|
||||
condition: service_healthy
|
||||
mailpit:
|
||||
condition: service_started
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway"
|
||||
|
||||
cassandra:
|
||||
image: cassandra:5.0.8
|
||||
profiles:
|
||||
- full
|
||||
environment:
|
||||
CASSANDRA_CLUSTER_NAME: fluxer-dev
|
||||
CASSANDRA_DC: datacenter1
|
||||
CASSANDRA_ENDPOINT_SNITCH: GossipingPropertyFileSnitch
|
||||
HEAP_NEWSIZE: 128M
|
||||
MAX_HEAP_SIZE: 768M
|
||||
volumes:
|
||||
- cassandra-data:/var/lib/cassandra
|
||||
ports:
|
||||
- "${FLUXER_DEV_CASSANDRA_PORT:-9042}:9042"
|
||||
|
||||
postgres:
|
||||
image: postgres:16-alpine
|
||||
environment:
|
||||
@@ -284,60 +261,62 @@ services:
|
||||
volumes:
|
||||
- postgres-data:/var/lib/postgresql/data
|
||||
ports:
|
||||
- "${FLUXER_DEV_POSTGRES_PORT:-5432}:5432"
|
||||
- "127.0.0.1:${FLUXER_DEV_POSTGRES_PORT:-5432}:5432"
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U fluxer -d fluxer"]
|
||||
interval: 2s
|
||||
timeout: 5s
|
||||
retries: 30
|
||||
start_period: 5s
|
||||
|
||||
valkey:
|
||||
image: valkey/valkey:8.1.7-alpine
|
||||
image: valkey/valkey:9.1.2-alpine
|
||||
command: ["valkey-server", "--save", "", "--appendonly", "no"]
|
||||
ports:
|
||||
- "${FLUXER_DEV_VALKEY_PORT:-6379}:6379"
|
||||
- "127.0.0.1:${FLUXER_DEV_VALKEY_PORT:-6379}:6379"
|
||||
|
||||
nats:
|
||||
image: nats:2.14.2-alpine
|
||||
image: nats:2.14.7-alpine
|
||||
command: ["-js", "-sd", "/data", "-m", "8222"]
|
||||
volumes:
|
||||
- nats-data:/data
|
||||
ports:
|
||||
- "${FLUXER_DEV_NATS_PORT:-4222}:4222"
|
||||
- "${FLUXER_DEV_NATS_MONITOR_PORT:-8222}:8222"
|
||||
- "127.0.0.1:${FLUXER_DEV_NATS_PORT:-4222}:4222"
|
||||
- "127.0.0.1:${FLUXER_DEV_NATS_MONITOR_PORT:-8222}:8222"
|
||||
|
||||
livekit:
|
||||
image: livekit/livekit-server:v1.12.0
|
||||
command: ["--config", "/etc/livekit.yaml", "--bind", "0.0.0.0"]
|
||||
environment:
|
||||
LIVEKIT_RTC_TCP_PORT: "${FLUXER_DEV_LIVEKIT_TCP_PORT:-7881}"
|
||||
LIVEKIT_RTC_UDP_PORT_START: "${FLUXER_DEV_LIVEKIT_UDP_PORT:-7882}"
|
||||
LIVEKIT_RTC_UDP_PORT_END: "${FLUXER_DEV_LIVEKIT_UDP_PORT:-7882}"
|
||||
volumes:
|
||||
- ./livekit.yaml:/etc/livekit.yaml:ro
|
||||
ports:
|
||||
- "${FLUXER_DEV_LIVEKIT_PORT:-7880}:7880"
|
||||
- "${FLUXER_DEV_LIVEKIT_TCP_PORT:-7881}:7881"
|
||||
- "${FLUXER_DEV_LIVEKIT_UDP_PORTS:-7882-7892}:7882-7892/udp"
|
||||
|
||||
elasticsearch:
|
||||
image: docker.elastic.co/elasticsearch/elasticsearch:9.3.2
|
||||
profiles:
|
||||
- full
|
||||
environment:
|
||||
discovery.type: single-node
|
||||
xpack.security.enabled: "true"
|
||||
xpack.security.http.ssl.enabled: "false"
|
||||
ELASTIC_PASSWORD: fluxer-dev-elasticsearch
|
||||
ES_JAVA_OPTS: "-Xms512m -Xmx512m"
|
||||
volumes:
|
||||
- elasticsearch-data:/usr/share/elasticsearch/data
|
||||
ports:
|
||||
- "${FLUXER_DEV_ELASTICSEARCH_PORT:-9200}:9200"
|
||||
- "127.0.0.1:${FLUXER_DEV_LIVEKIT_PORT:-7880}:7880"
|
||||
- "127.0.0.1:${FLUXER_DEV_LIVEKIT_TCP_PORT:-7881}:${FLUXER_DEV_LIVEKIT_TCP_PORT:-7881}"
|
||||
- "127.0.0.1:${FLUXER_DEV_LIVEKIT_UDP_PORT:-7882}:${FLUXER_DEV_LIVEKIT_UDP_PORT:-7882}/udp"
|
||||
|
||||
meilisearch:
|
||||
image: getmeili/meilisearch:v1.12
|
||||
image: getmeili/meilisearch:v1.53
|
||||
environment:
|
||||
MEILI_NO_ANALYTICS: "true"
|
||||
MEILI_UPGRADE_DB: "true"
|
||||
MEILI_MASTER_KEY: fluxer-dev-meilisearch
|
||||
volumes:
|
||||
- meilisearch-data:/meili_data
|
||||
ports:
|
||||
- "${FLUXER_DEV_MEILISEARCH_PORT:-7700}:7700"
|
||||
- "127.0.0.1:${FLUXER_DEV_MEILISEARCH_PORT:-7700}:7700"
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "--fail", "--silent", "http://127.0.0.1:7700/health"]
|
||||
interval: 2s
|
||||
timeout: 5s
|
||||
retries: 30
|
||||
start_period: 5s
|
||||
|
||||
mailpit:
|
||||
image: axllent/mailpit:v1.30
|
||||
image: axllent/mailpit:v1.31
|
||||
environment:
|
||||
MP_DATABASE: /data/mailpit.db
|
||||
MP_MAX_MESSAGES: 5000
|
||||
@@ -360,7 +339,6 @@ volumes:
|
||||
package-errors-node-modules:
|
||||
package-geo-utils-node-modules:
|
||||
package-hono-node-modules:
|
||||
package-hono-types-node-modules:
|
||||
package-i18n-node-modules:
|
||||
package-instance-bootstrap-node-modules:
|
||||
package-ip-utils-node-modules:
|
||||
@@ -376,14 +354,11 @@ volumes:
|
||||
fluxer-api-email-node-modules:
|
||||
fluxer-api-geoip-node-modules:
|
||||
fluxer-api-http-client-node-modules:
|
||||
fluxer-api-initialization-node-modules:
|
||||
fluxer-api-kv-client-node-modules:
|
||||
fluxer-api-locale-node-modules:
|
||||
fluxer-api-media-proxy-utils-node-modules:
|
||||
fluxer-api-mime-utils-node-modules:
|
||||
fluxer-api-nats-node-modules:
|
||||
fluxer-api-rate-limit-node-modules:
|
||||
fluxer-api-sms-node-modules:
|
||||
fluxer-api-virus-scan-node-modules:
|
||||
fluxer-api-worker-node-modules:
|
||||
fluxer-app-list-utils-node-modules:
|
||||
@@ -394,9 +369,7 @@ volumes:
|
||||
cargo-registry:
|
||||
cargo-git:
|
||||
rust-target:
|
||||
cassandra-data:
|
||||
nats-data:
|
||||
elasticsearch-data:
|
||||
meilisearch-data:
|
||||
mailpit-data:
|
||||
postgres-data:
|
||||
@@ -1,10 +1,10 @@
|
||||
#!/usr/bin/env bash
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
set -uo pipefail
|
||||
set -euo pipefail
|
||||
|
||||
SOCKET="${DOCKER_SOCKET:-/var/run/docker.sock}"
|
||||
USER_NAME="${USER:-vscode}"
|
||||
USER_NAME="$(id -un)"
|
||||
|
||||
if [ ! -S "$SOCKET" ]; then
|
||||
echo "fix-docker-socket: no socket at $SOCKET; skipping (Docker-in-devcontainer will not work)"
|
||||
@@ -16,31 +16,11 @@ if docker version --format '{{.Server.Version}}' >/dev/null 2>&1; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
socket_gid="$(stat -c '%g' "$SOCKET" 2>/dev/null || echo "")"
|
||||
if [ -z "$socket_gid" ]; then
|
||||
echo "fix-docker-socket: could not stat $SOCKET; skipping" >&2
|
||||
exit 0
|
||||
fi
|
||||
|
||||
sudo sh -c '
|
||||
set -e
|
||||
gid="$1"
|
||||
user="$2"
|
||||
socket="$3"
|
||||
if ! getent group "$gid" >/dev/null 2>&1; then
|
||||
groupadd --gid "$gid" docker-host
|
||||
fi
|
||||
group_name="$(getent group "$gid" | cut -d: -f1)"
|
||||
usermod --append --groups "$group_name" "$user"
|
||||
chgrp "$gid" "$socket"
|
||||
chmod g+rw "$socket"
|
||||
' sh "$socket_gid" "$USER_NAME" "$SOCKET" || {
|
||||
echo "fix-docker-socket: could not adjust $SOCKET; run docker with sudo" >&2
|
||||
exit 0
|
||||
}
|
||||
sudo setfacl --modify "user:${USER_NAME}:rw" "$SOCKET"
|
||||
|
||||
if docker version --format '{{.Server.Version}}' >/dev/null 2>&1; then
|
||||
echo "fix-docker-socket: $SOCKET is now usable as $USER_NAME (gid $socket_gid)"
|
||||
echo "fix-docker-socket: $SOCKET is now usable as $USER_NAME"
|
||||
else
|
||||
echo "fix-docker-socket: $SOCKET still unreachable as $USER_NAME; run docker with sudo" >&2
|
||||
echo "fix-docker-socket: $SOCKET is still unreachable as $USER_NAME" >&2
|
||||
exit 1
|
||||
fi
|
||||
@@ -0,0 +1,39 @@
|
||||
#!/usr/bin/env bash
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
owner="$(id -u):$(id -g)"
|
||||
|
||||
repair_tree() {
|
||||
local path="$1"
|
||||
local unwritable
|
||||
if [ ! -d "$path" ]; then
|
||||
echo "fix-workspace-permissions: expected mount is missing: $path" >&2
|
||||
exit 1
|
||||
fi
|
||||
unwritable="$(find "$path" -xdev \( -type d -o -type f \) ! -writable -print -quit 2>/dev/null || true)"
|
||||
if [ ! -w "$path" ] || [ -n "$unwritable" ]; then
|
||||
sudo find "$path" -xdev \( -type d -o -type f \) -exec chown "$owner" {} +
|
||||
fi
|
||||
unwritable="$(find "$path" -xdev \( -type d -o -type f \) ! -writable -print -quit 2>/dev/null || true)"
|
||||
if [ ! -w "$path" ] || [ -n "$unwritable" ]; then
|
||||
echo "fix-workspace-permissions: $path is not writable as $(id -un)" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
for path in \
|
||||
/workspaces/fluxer/target \
|
||||
/home/vscode/.cargo/registry \
|
||||
/home/vscode/.cargo/git \
|
||||
/home/vscode/.local \
|
||||
/home/vscode/.local/share/pnpm/store; do
|
||||
repair_tree "$path"
|
||||
done
|
||||
|
||||
while IFS= read -r -d '' path; do
|
||||
if mountpoint -q "$path"; then
|
||||
repair_tree "$path"
|
||||
fi
|
||||
done < <(find /workspaces/fluxer -maxdepth 4 -type d -name node_modules -prune -print0)
|
||||
@@ -1,11 +1,10 @@
|
||||
port: 7880
|
||||
|
||||
keys:
|
||||
devkey: secret
|
||||
devkey: fluxer-livekit-development-secret
|
||||
|
||||
rtc:
|
||||
tcp_port: 7881
|
||||
udp_port: 7882-7892
|
||||
node_ip: 127.0.0.1
|
||||
use_mdns: true
|
||||
stun_servers:
|
||||
|
||||
+11
-4
@@ -7,10 +7,16 @@ QUICK=0
|
||||
SKIP_INSTALL=0
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--quick) QUICK=1 ;;
|
||||
--skip-install) SKIP_INSTALL=1 ;;
|
||||
-h|--help) sed -n '2,25p' "$0"; exit 0 ;;
|
||||
*) echo "unknown argument: $arg" >&2; exit 2 ;;
|
||||
--quick) QUICK=1 ;;
|
||||
--skip-install) SKIP_INSTALL=1 ;;
|
||||
-h | --help)
|
||||
sed -n '2,25p' "$0"
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo "unknown argument: $arg" >&2
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
@@ -64,6 +70,7 @@ stage "app: typecheck" pnpm --filter fluxer_app typecheck
|
||||
stage "app: unit tests" pnpm --filter fluxer_app exec vitest run
|
||||
|
||||
if [ "$QUICK" -eq 0 ]; then
|
||||
stage "desktop: typecheck" pnpm --filter fluxer_desktop typecheck
|
||||
stage "app: production build" pnpm --filter fluxer_app build
|
||||
fi
|
||||
|
||||
|
||||
+8
-7
@@ -9,7 +9,6 @@
|
||||
**/.git/**
|
||||
/.github/
|
||||
/.pnpm-store/
|
||||
/fluxer_marketing
|
||||
|
||||
**/.env
|
||||
**/.env.*.local
|
||||
@@ -29,14 +28,19 @@
|
||||
**/node_modules/
|
||||
**/target/
|
||||
**/test-results.json
|
||||
/fluxer_docs/site/
|
||||
/fluxer_docs/dist/
|
||||
/fluxer_docs/.astro/
|
||||
/fluxer_app/.devserver-cache.json
|
||||
/fluxer_app/pkgs/libfluxcore/
|
||||
/fluxer_app/pkgs/libfluxwebp/
|
||||
/fluxer_app/src/features/i18n/locales/*/messages.mjs
|
||||
/fluxer_app/src/features/messaging/utils/markdown/parser/MarkdownParserWasmBytes.ts
|
||||
/fluxer_app/src/features/theme/styles/generated/
|
||||
/fluxer_app/src/features/ui/components/SVGMasks.tsx
|
||||
/fluxer_app/src/features/ui/constants/AvatarStatusGeometry.ts
|
||||
/fluxer_static/desktop/spellcheck/dictionaries/*/*
|
||||
!/fluxer_static/desktop/spellcheck/dictionaries/[email protected]/LICENSE
|
||||
!/fluxer_static/desktop/spellcheck/dictionaries/[email protected]/LICENSE
|
||||
/fluxer_gateway/priv/
|
||||
|
||||
/fluxer_media_proxy/fuzz/artifacts/
|
||||
@@ -44,16 +48,13 @@
|
||||
/packages/markdown_parser/rust/fuzz/artifacts/
|
||||
/packages/markdown_parser/rust/fuzz/corpus/
|
||||
|
||||
/fluxer_media_proxy/.benchmark-cache/
|
||||
/fluxer_media_proxy/bench-results/
|
||||
|
||||
/app-dist-output/
|
||||
/artifacts/
|
||||
/desktop-shared-assets/
|
||||
/desktop-modules/
|
||||
/s3_payload/
|
||||
/upload_staging/
|
||||
|
||||
/deploy/helm/**/Chart.lock
|
||||
/deploy/helm/**/charts/
|
||||
|
||||
/fluxer_desktop/
|
||||
|
||||
|
||||
@@ -9,6 +9,33 @@ max_line_length = 120
|
||||
indent_style = tab
|
||||
indent_size = 2
|
||||
|
||||
[*.rs]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
max_line_length = 100
|
||||
|
||||
[*.{erl,hrl,app.src,escript}]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
max_line_length = 96
|
||||
|
||||
[fluxer_gateway/{rebar.config,elvis.config,.erlfmt}]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
max_line_length = 96
|
||||
|
||||
[*.{c,h,py}]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
[fluxer_app/rust/libfluxwebp/**.{c,h}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[*.{md,mdx,proto,tpl}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[*.{yml,yaml,Dockerfile}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
* text=auto
|
||||
fluxer_static/** -text -diff
|
||||
fluxer_static/**/*.md text diff
|
||||
fluxer_static/*.sh text eol=lf diff
|
||||
fluxer_static/*.sha256 text eol=lf diff
|
||||
packages/fonts/files/** -text -diff
|
||||
fluxer_app/src/features/voice/utils/noise_suppression/deepfilternet3/*.wasm -text -diff
|
||||
fluxer_app/src/features/voice/utils/noise_suppression/deepfilternet3/*.tar.gz -text -diff
|
||||
fluxer_app/src/features/i18n/locales/** linguist-generated
|
||||
**/weblate/locales/** linguist-generated
|
||||
fluxer_api/src/api/openapi/openapi.json linguist-generated
|
||||
fluxer_admin/openapi-admin.json linguist-generated
|
||||
@@ -1,7 +1,2 @@
|
||||
/.github/CODEOWNERS @fluxerapp/developers
|
||||
/.github/workflows/ @fluxerapp/developers
|
||||
/fluxer_marketing @fluxerapp/developers
|
||||
/.gitmodules @fluxerapp/developers
|
||||
/.github/workflows/dispatch-private-marketing-build.yaml @fluxerapp/developers
|
||||
/packages/i18n/marketing/ @fluxerapp/developers
|
||||
/scripts/setup-private-marketing.sh @fluxerapp/developers
|
||||
+9
-27
@@ -1,24 +1,24 @@
|
||||
# Contributing to Fluxer
|
||||
|
||||
This policy applies to all issues, discussions, commits and pull requests.
|
||||
This policy applies to all commits and pull requests.
|
||||
|
||||
## Scope
|
||||
|
||||
To prevent spam, only approved contributors may submit pull requests.
|
||||
|
||||
To request approval, comment on an existing issue and ask to implement it. For work that extends beyond a defect fix, open a [discussion](https://github.com/orgs/fluxerapp/discussions) first.
|
||||
To request approval, comment on the [feedback.fluxer.com](https://feedback.fluxer.com) post you want to implement and ask to work on it. For work that extends beyond a defect fix, post a feature request there first.
|
||||
|
||||
Every pull request must:
|
||||
|
||||
- Target the repository's default branch.
|
||||
- Include a closing reference for each repository issue it resolves.
|
||||
- Link each feedback.fluxer.com post it resolves.
|
||||
- Receive approval from a maintainer before it is merged.
|
||||
|
||||
Place each closing reference on a separate line:
|
||||
Place each link on a separate line:
|
||||
|
||||
```text
|
||||
Closes #123
|
||||
Closes #456
|
||||
Resolves https://feedback.fluxer.com/p/123
|
||||
Resolves https://feedback.fluxer.com/p/456
|
||||
```
|
||||
|
||||
## Authorship
|
||||
@@ -78,32 +78,14 @@ Complete every section of the pull request template. Clearly describe:
|
||||
|
||||
## Reports and other contributions
|
||||
|
||||
Use the [bug report form](https://github.com/fluxerapp/fluxer/issues/new?template=bug-report.yaml) to report reproducible defects.
|
||||
Report bugs and request features at [feedback.fluxer.com](https://feedback.fluxer.com).
|
||||
|
||||
Report security vulnerabilities privately through the channels specified in the [security policy](https://github.com/fluxerapp/fluxer/blob/main/.github/SECURITY.md). Do not report vulnerabilities in public issues or discussions.
|
||||
Report security vulnerabilities privately through [fluxer.app/security](https://fluxer.app/security). Never post them publicly.
|
||||
|
||||
Use [discussions](https://github.com/orgs/fluxerapp/discussions) for feature proposals and self-hosting questions.
|
||||
Read the [operator documentation](https://fluxer.dev) for self-hosting questions.
|
||||
|
||||
Submit translations through [Weblate](https://weblate.fluxer.tools), not through pull requests.
|
||||
|
||||
All repository activity is governed by the [Code of Conduct](https://github.com/fluxerapp/fluxer/blob/main/.github/CODE_OF_CONDUCT.md).
|
||||
|
||||
Fluxer is distributed under the [GNU Affero General Public License, version 3.0 or later](https://github.com/fluxerapp/fluxer/blob/main/LICENSE). By adding a DCO sign-off, you certify that you have the right to submit the contribution under that licence.
|
||||
|
||||
## Private marketing project
|
||||
|
||||
The marketing implementation is maintained in a private repository at the `fluxer_marketing` submodule path. The public workspace, bootstrap, checks, and development stack work without initializing it.
|
||||
|
||||
Authorized maintainers can initialize only that submodule and install its independent dependencies:
|
||||
|
||||
```sh
|
||||
./scripts/setup-private-marketing.sh
|
||||
pnpm --dir fluxer_marketing install --frozen-lockfile
|
||||
cargo metadata --locked --manifest-path fluxer_marketing/Cargo.toml
|
||||
```
|
||||
|
||||
To run the private marketing service in the local development stack and direct application links to it, add this override to the ignored `config/env/local.env` file:
|
||||
|
||||
```sh
|
||||
FLUXER_MARKETING_ENDPOINT=http://localhost:8088/marketing
|
||||
```
|
||||
@@ -1,41 +0,0 @@
|
||||
# yaml-language-server: $schema=https://www.schemastore.org/github-discussion.json
|
||||
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Search existing discussions before posting a feature proposal.
|
||||
|
||||
Report vulnerabilities through the [private form](https://github.com/fluxerapp/fluxer/security/advisories/new) or <[email protected]>.
|
||||
|
||||
- type: textarea
|
||||
id: problem
|
||||
attributes:
|
||||
label: Current problem
|
||||
description: State what you are trying to do and what prevents it.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: proposal
|
||||
attributes:
|
||||
label: Proposed change
|
||||
description: State the expected behaviour.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: notes
|
||||
attributes:
|
||||
label: Additional information
|
||||
description: Optional. Include constraints, trade-offs, related discussions, screenshots or mockups.
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: checkboxes
|
||||
id: checks
|
||||
attributes:
|
||||
label: Acknowledgements
|
||||
options:
|
||||
- label: I searched existing discussions.
|
||||
required: true
|
||||
@@ -16,4 +16,10 @@ Every commit made by a contributor must include the [Developer Certificate of Or
|
||||
|
||||
## Name and marks
|
||||
|
||||
The AGPL does not grant permission to use the Fluxer name, logo or other branding. Forks must use a distinct name and branding unless Fluxer Platform AB grants permission otherwise.
|
||||
Fluxer and the Fluxer logo are trademarks of Fluxer Platform AB. Neither the AGPL nor the CC BY-SA 4.0 licence on Fluxer artwork grants trademark rights. Fluxer Platform AB grants everyone the following permissions.
|
||||
|
||||
- You may distribute unmodified builds of Fluxer, or builds with light patches, under the Fluxer name and logo. Light patches are changes for packaging, portability, security and bug fixes, configuration defaults and translations. Linux distributions, nixpkgs, Flathub and container images are all covered.
|
||||
- A self-hosted instance running such a build may show the Fluxer name and logo under the instance's own name and domain, as long as it does not imply affiliation with or endorsement by Fluxer Platform AB.
|
||||
- You may refer to Fluxer by name to describe compatibility, for example "works with Fluxer".
|
||||
|
||||
Forks with substantive functional changes must use their own name and logo. Any other use needs permission from Fluxer Platform AB. Contact support@fluxer.com.
|
||||
@@ -1,84 +0,0 @@
|
||||
# yaml-language-server: $schema=https://www.schemastore.org/github-issue-forms.json
|
||||
name: Bug report
|
||||
description: Report a reproducible defect in Fluxer.
|
||||
type: Bug
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Search [open and closed issues](https://github.com/fluxerapp/fluxer/issues?q=is%3Aissue) before filing a report.
|
||||
|
||||
Report vulnerabilities through the [private form](https://github.com/fluxerapp/fluxer/security/advisories/new) or <[email protected]>. Send account and billing requests to <[email protected]>.
|
||||
|
||||
- type: textarea
|
||||
id: summary
|
||||
attributes:
|
||||
label: Observed behaviour
|
||||
description: State what happened and what you expected.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: steps
|
||||
attributes:
|
||||
label: Reproduction steps
|
||||
description: Give numbered steps starting from a fresh app or session.
|
||||
placeholder: |
|
||||
1. Go to ...
|
||||
2. Select ...
|
||||
3. Observe ...
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: build
|
||||
attributes:
|
||||
label: Build information
|
||||
description: >-
|
||||
Open User Settings, scroll to the bottom of the left sidebar, and select
|
||||
the build information. Fluxer copies it to the clipboard. On mobile,
|
||||
select the build information at the bottom of the settings list.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: dropdown
|
||||
id: surface
|
||||
attributes:
|
||||
label: Affected surface
|
||||
multiple: true
|
||||
options:
|
||||
- Desktop app
|
||||
- Web app
|
||||
- Voice, video, or Go Live
|
||||
- Self-hosted instance
|
||||
- HTTP API or Gateway
|
||||
- Documentation site
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: instance
|
||||
attributes:
|
||||
label: Instance
|
||||
description: For a self-hosted instance, include the release tag and database backend.
|
||||
placeholder: fluxer.app
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: textarea
|
||||
id: evidence
|
||||
attributes:
|
||||
label: Evidence
|
||||
description: Attach relevant logs, screenshots or recordings. Remove tokens, keys, private messages and other personal data. Configuration files may contain secrets.
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: checkboxes
|
||||
id: checks
|
||||
attributes:
|
||||
label: Acknowledgements
|
||||
options:
|
||||
- label: I searched open and closed issues.
|
||||
required: true
|
||||
- label: I removed secrets and unrelated personal data from the report.
|
||||
required: true
|
||||
@@ -1,18 +0,0 @@
|
||||
# yaml-language-server: $schema=https://www.schemastore.org/github-issue-config.json
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Account and billing support
|
||||
url: https://fluxer.app/help
|
||||
about: Find account help and support contact details.
|
||||
- name: Feature proposals
|
||||
url: https://github.com/orgs/fluxerapp/discussions
|
||||
about: Propose a feature in a discussion.
|
||||
- name: Security vulnerabilities
|
||||
url: https://github.com/fluxerapp/fluxer/security/advisories/new
|
||||
about: Submit a private vulnerability report.
|
||||
- name: Translations
|
||||
url: https://weblate.fluxer.tools
|
||||
about: Improve an existing locale or start a new one.
|
||||
- name: Self-hosting support
|
||||
url: https://fluxer.dev
|
||||
about: Read the operator documentation, then open a discussion if the problem remains.
|
||||
@@ -1,44 +0,0 @@
|
||||
# yaml-language-server: $schema=https://www.schemastore.org/github-issue-forms.json
|
||||
name: Documentation
|
||||
description: Report incorrect, missing or unclear documentation.
|
||||
type: Task
|
||||
labels:
|
||||
- docs
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
This form covers <https://fluxer.dev> and operator documentation.
|
||||
|
||||
- type: textarea
|
||||
id: issue
|
||||
attributes:
|
||||
label: Documentation defect
|
||||
description: State what the page says and what is correct. For missing content, state what information you needed.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: location
|
||||
attributes:
|
||||
label: Location
|
||||
description: Provide the page URL or file path and heading.
|
||||
placeholder: https://fluxer.dev/gateway/overview/
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: textarea
|
||||
id: suggestion
|
||||
attributes:
|
||||
label: Proposed wording
|
||||
description: Optional.
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: checkboxes
|
||||
id: checks
|
||||
attributes:
|
||||
label: Acknowledgements
|
||||
options:
|
||||
- label: I searched open and closed issues.
|
||||
required: true
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
# Security policy
|
||||
|
||||
Do not report a vulnerability in an issue, pull request, or discussion.
|
||||
Do not report a vulnerability in a pull request, on feedback.fluxer.com, in a Fluxer community, or in a direct message to staff.
|
||||
|
||||
Submit a report through [GitHub private vulnerability reporting](https://github.com/fluxerapp/fluxer/security/advisories/new) or email <security@fluxer.com>. Include the affected component, impact, reproduction steps, and supporting evidence. Remove unrelated personal data and secrets.
|
||||
Submit a report through <https://fluxer.app/security> or email <security@fluxer.com>. Include the affected component, impact, reproduction steps, and supporting evidence. Remove unrelated personal data and secrets.
|
||||
|
||||
The programme scope, testing rules, safe harbour, disclosure process, and reward terms are published at <https://fluxer.app/security>. That page is authoritative.
|
||||
@@ -1,10 +1,5 @@
|
||||
self-hosted-runner:
|
||||
labels:
|
||||
- blacksmith-4vcpu-ubuntu-2404
|
||||
- blacksmith-4vcpu-ubuntu-2404-arm
|
||||
- blacksmith-32vcpu-ubuntu-2404
|
||||
- blacksmith-32vcpu-ubuntu-2404-arm
|
||||
- blacksmith-32vcpu-windows-2025
|
||||
- fluxer-desktop-macos-arm64
|
||||
|
||||
config-variables: null
|
||||
@@ -0,0 +1,38 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
name: App Wasm cache
|
||||
description: Restore or save the shared application Wasm artifacts
|
||||
inputs:
|
||||
mode:
|
||||
description: Cache operation (restore or save)
|
||||
required: true
|
||||
outputs:
|
||||
cache-hit:
|
||||
description: Whether the restore found the exact artifact key
|
||||
value: ${{ steps.cache.outputs.cache-hit }}
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Resolve artifact key
|
||||
id: key
|
||||
if: always()
|
||||
shell: bash
|
||||
run: echo "key=app-wasm-${{ runner.os }}-1.98.1-${{ hashFiles('Cargo.lock', 'tools/ci/src/app_wasm.rs', 'fluxer_app/rust/libfluxcore/Cargo.toml', 'fluxer_app/rust/libfluxcore/Cargo.lock', 'fluxer_app/rust/libfluxcore/.cargo/config.toml', 'fluxer_app/rust/libfluxcore/src/**', 'fluxer_app/rust/libfluxwebp/Cargo.toml', 'fluxer_app/rust/libfluxwebp/Cargo.lock', 'fluxer_app/rust/libfluxwebp/src/**', 'fluxer_app/rust/libfluxwebp/shim/**', 'fluxer_app/rust/libfluxwebp/simd/**', 'packages/markdown_parser/rust/Cargo.toml', 'packages/markdown_parser/rust/.cargo/config.toml', 'packages/markdown_parser/rust/src/**') }}" >> "$GITHUB_OUTPUT"
|
||||
- name: Restore artifacts
|
||||
id: cache
|
||||
if: inputs.mode == 'restore'
|
||||
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9
|
||||
with:
|
||||
path: |
|
||||
fluxer_app/pkgs/libfluxcore
|
||||
fluxer_app/pkgs/libfluxwebp
|
||||
fluxer_app/src/features/messaging/utils/markdown/parser/MarkdownParserWasmBytes.ts
|
||||
key: ${{ steps.key.outputs.key }}
|
||||
- name: Save artifacts
|
||||
if: always() && inputs.mode == 'save'
|
||||
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9
|
||||
with:
|
||||
path: |
|
||||
fluxer_app/pkgs/libfluxcore
|
||||
fluxer_app/pkgs/libfluxwebp
|
||||
fluxer_app/src/features/messaging/utils/markdown/parser/MarkdownParserWasmBytes.ts
|
||||
key: ${{ steps.key.outputs.key }}
|
||||
@@ -0,0 +1,29 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
name: CI helper
|
||||
description: Restore or build the shared Rust CI helper
|
||||
inputs:
|
||||
save:
|
||||
description: Save a missing helper cache on main
|
||||
required: false
|
||||
default: 'false'
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Restore ci helper
|
||||
id: cache
|
||||
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9
|
||||
with:
|
||||
path: target/debug/fluxer-ci
|
||||
key: >-
|
||||
fluxer-ci-bin-${{ runner.os }}-1.98.1-${{ hashFiles('Cargo.lock', 'Cargo.toml',
|
||||
'tools/ci/Cargo.toml', 'tools/ci/src/**') }}
|
||||
- name: Build ci helper
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
shell: bash
|
||||
run: cargo build --locked --package fluxer-ci
|
||||
- name: Save ci helper
|
||||
if: inputs.save == 'true' && github.ref == 'refs/heads/main' && steps.cache.outputs.cache-hit != 'true'
|
||||
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9
|
||||
with:
|
||||
path: target/debug/fluxer-ci
|
||||
key: ${{ steps.cache.outputs.cache-primary-key }}
|
||||
@@ -22,17 +22,15 @@ f:docs:
|
||||
f:gateway:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: fluxer_gateway/**/*
|
||||
f:marketing:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- fluxer_marketing
|
||||
- packages/i18n/marketing/**/*
|
||||
f:media_proxy:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: fluxer_media_proxy/**/*
|
||||
f:messages:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: fluxer_messages/**/*
|
||||
f:push:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: fluxer_push/**/*
|
||||
f:snowflakes:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: fluxer_snowflakes/**/*
|
||||
@@ -69,9 +67,6 @@ p:geo-utils:
|
||||
p:hono:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: packages/hono/**/*
|
||||
p:hono-types:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: packages/hono_types/**/*
|
||||
p:i18n:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: packages/i18n/**/*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Closes #
|
||||
Resolves https://feedback.fluxer.com/p/
|
||||
|
||||
<!-- Repeat this line for each resolved issue, up to 20. Remove the placeholder only if no issue is resolved and the approval gate does not apply. -->
|
||||
<!-- Repeat this line for each feedback.fluxer.com post this resolves, up to 20. Remove the placeholder only if no post is resolved and the approval gate does not apply. -->
|
||||
|
||||
## Summary
|
||||
|
||||
|
||||
@@ -12,26 +12,11 @@ on:
|
||||
description: "Path to the Dockerfile to build"
|
||||
type: string
|
||||
required: true
|
||||
context:
|
||||
description: "Docker build context"
|
||||
type: string
|
||||
required: false
|
||||
default: "."
|
||||
build-version:
|
||||
description: "Explicit Fluxer CalVer build version (YYYY.MDD.MICRO, UTC HHMMSS without leading zeroes) to use instead of automatic UTC clock allocation"
|
||||
type: string
|
||||
required: false
|
||||
default: ""
|
||||
moving-tags:
|
||||
description: "Comma-separated moving tags to repoint at this build"
|
||||
type: string
|
||||
required: false
|
||||
default: "v1,latest"
|
||||
extra-build-args:
|
||||
description: "Additional Docker build args, one KEY=VALUE entry per line"
|
||||
type: string
|
||||
required: false
|
||||
default: ""
|
||||
permissions:
|
||||
actions: read
|
||||
contents: write
|
||||
@@ -58,13 +43,13 @@ jobs:
|
||||
outputs:
|
||||
build_version: ${{ steps.vars.outputs.build_version }}
|
||||
steps:
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
|
||||
env:
|
||||
GIT_CONFIG_GLOBAL: ${{ runner.temp }}/gitconfig
|
||||
- name: Set up Rust toolchain (CI helpers)
|
||||
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9
|
||||
uses: dtolnay/rust-toolchain@02cb101ec7c40f2c49e1d9714d64511d8e1b74de
|
||||
with:
|
||||
toolchain: "1.93.0"
|
||||
toolchain: "1.98.1"
|
||||
- name: Create token
|
||||
id: create-token
|
||||
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1
|
||||
@@ -80,7 +65,7 @@ jobs:
|
||||
GH_TOKEN: ${{ steps.create-token.outputs.token }}
|
||||
FLUXER_BUILD_VERSION: ${{ inputs['build-version'] }}
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- resolve-calver
|
||||
tools/ci/run.sh resolve-calver
|
||||
--github-output
|
||||
|
||||
build:
|
||||
@@ -97,32 +82,36 @@ jobs:
|
||||
matrix:
|
||||
include:
|
||||
- platform: amd64
|
||||
runner: blacksmith-4vcpu-ubuntu-2404
|
||||
runner: ubuntu-24.04
|
||||
- platform: arm64
|
||||
runner: blacksmith-4vcpu-ubuntu-2404-arm
|
||||
runner: ubuntu-24.04-arm
|
||||
steps:
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
|
||||
env:
|
||||
GIT_CONFIG_GLOBAL: ${{ runner.temp }}/gitconfig
|
||||
- uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5
|
||||
- uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee
|
||||
- name: resolve source date
|
||||
id: source
|
||||
run: echo "date=$(TZ=UTC git log -1 --no-show-signature --pretty=%cd --date=format-local:%Y-%m-%dT%H:%M:%SZ)" >> "$GITHUB_OUTPUT"
|
||||
- uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069
|
||||
- uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ github.token }}
|
||||
- uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf
|
||||
- uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc
|
||||
with:
|
||||
context: ${{ inputs.context }}
|
||||
context: .
|
||||
file: ${{ inputs.dockerfile }}
|
||||
push: true
|
||||
provenance: false
|
||||
provenance: mode=min
|
||||
platforms: linux/${{ matrix.platform }}
|
||||
tags: ghcr.io/${{ env.GHCR_OWNER }}/${{ inputs.image }}:${{ needs.meta.outputs.build_version }}-${{ matrix.platform }}
|
||||
build-args: |
|
||||
BUILD_VERSION=${{ needs.meta.outputs.build_version }}
|
||||
${{ inputs.extra-build-args }}
|
||||
cache-from: type=gha,scope=${{ inputs.image }}-${{ matrix.platform }}
|
||||
cache-to: type=gha,scope=${{ inputs.image }}-${{ matrix.platform }},mode=max,ignore-error=true
|
||||
SOURCE_SHA=${{ github.sha }}
|
||||
SOURCE_DATE=${{ steps.source.outputs.date }}
|
||||
cache-from: type=registry,ref=ghcr.io/${{ env.GHCR_OWNER }}/${{ inputs.image }}:buildcache-${{ matrix.platform }}
|
||||
cache-to: type=registry,ref=ghcr.io/${{ env.GHCR_OWNER }}/${{ inputs.image }}:buildcache-${{ matrix.platform }},mode=max,image-manifest=true,oci-mediatypes=true,ignore-error=true
|
||||
env:
|
||||
DOCKER_BUILD_SUMMARY: false
|
||||
DOCKER_BUILD_RECORD_UPLOAD: false
|
||||
@@ -136,15 +125,15 @@ jobs:
|
||||
contents: write
|
||||
packages: write
|
||||
steps:
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
|
||||
env:
|
||||
GIT_CONFIG_GLOBAL: ${{ runner.temp }}/gitconfig
|
||||
- name: Set up Rust toolchain (CI helpers)
|
||||
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9
|
||||
uses: dtolnay/rust-toolchain@02cb101ec7c40f2c49e1d9714d64511d8e1b74de
|
||||
with:
|
||||
toolchain: "1.93.0"
|
||||
- uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5
|
||||
- uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee
|
||||
toolchain: "1.98.1"
|
||||
- uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069
|
||||
- uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
@@ -176,7 +165,7 @@ jobs:
|
||||
VERSION: ${{ needs.meta.outputs.build_version }}
|
||||
RELEASE_BASELINE_SHA: ${{ vars.RELEASE_BASELINE_SHA }}
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- release
|
||||
tools/ci/run.sh release
|
||||
publish
|
||||
--component "${{ inputs.image }}"
|
||||
--build-version "${VERSION}"
|
||||
@@ -185,17 +174,12 @@ jobs:
|
||||
|
||||
- name: Advance moving image tags
|
||||
env:
|
||||
IMAGE: ghcr.io/${{ env.GHCR_OWNER }}/${{ inputs.image }}
|
||||
MOVING_TAGS: v1,latest
|
||||
VERSION: ${{ needs.meta.outputs.build_version }}
|
||||
MOVING_TAGS: ${{ inputs.moving-tags }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
tag_args=()
|
||||
IFS=',' read -ra moving <<< "${MOVING_TAGS}"
|
||||
for raw in "${moving[@]}"; do
|
||||
tag="$(echo "$raw" | xargs)"
|
||||
[ -n "$tag" ] && tag_args+=( "-t" "${IMAGE}:${tag}" )
|
||||
done
|
||||
if (( ${#tag_args[@]} > 0 )); then
|
||||
docker buildx imagetools create "${tag_args[@]}" "${IMAGE}:${VERSION}"
|
||||
fi
|
||||
run: >-
|
||||
tools/ci/run.sh image-set
|
||||
promote
|
||||
--component "${{ inputs.image }}"
|
||||
--build-version "${VERSION}"
|
||||
--registry "ghcr.io/${{ env.GHCR_OWNER }}"
|
||||
--moving-tags "${MOVING_TAGS}"
|
||||
@@ -15,6 +15,13 @@ permissions:
|
||||
contents: write
|
||||
packages: write
|
||||
|
||||
concurrency:
|
||||
group: publish-fluxer-app-proxy-self-hosted
|
||||
cancel-in-progress: false
|
||||
|
||||
env:
|
||||
GHCR_OWNER: ${{ github.repository_owner }}
|
||||
|
||||
jobs:
|
||||
approve:
|
||||
name: approve build release
|
||||
@@ -26,13 +33,208 @@ jobs:
|
||||
- name: approved
|
||||
run: echo "Build release approved."
|
||||
|
||||
build:
|
||||
meta:
|
||||
name: resolve metadata
|
||||
needs: approve
|
||||
uses: ./.github/workflows/_build-image.yaml
|
||||
secrets: inherit
|
||||
with:
|
||||
image: fluxer-app-proxy-self-hosted
|
||||
dockerfile: fluxer_app_proxy/Dockerfile
|
||||
build-version: ${{ inputs['build-version'] }}
|
||||
extra-build-args: |
|
||||
FLUXER_APP_PROXY_TIME_FREEZE_ENABLED=false
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 5
|
||||
permissions:
|
||||
contents: read
|
||||
outputs:
|
||||
build_version: ${{ steps.vars.outputs.build_version }}
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
|
||||
env:
|
||||
GIT_CONFIG_GLOBAL: ${{ runner.temp }}/gitconfig
|
||||
- name: Set up Rust toolchain (CI helpers)
|
||||
uses: dtolnay/rust-toolchain@02cb101ec7c40f2c49e1d9714d64511d8e1b74de
|
||||
with:
|
||||
toolchain: "1.98.1"
|
||||
- name: set variables
|
||||
id: vars
|
||||
run: >-
|
||||
tools/ci/run.sh build-app-proxy
|
||||
--step set_metadata
|
||||
--build-version "${{ inputs['build-version'] }}"
|
||||
|
||||
dist:
|
||||
name: build the canonical asset tree
|
||||
needs: meta
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 60
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
packages: write
|
||||
env:
|
||||
IMAGE_REPO: ghcr.io/${{ github.repository_owner }}/fluxer-app-proxy-self-hosted
|
||||
BUILD_VERSION: ${{ needs.meta.outputs.build_version }}
|
||||
PUBLIC_ASSET_BASE_URL: ""
|
||||
BUNDLE_LOCAL_ASSETS: "true"
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
|
||||
env:
|
||||
GIT_CONFIG_GLOBAL: ${{ runner.temp }}/gitconfig
|
||||
- name: Set up Rust toolchain (CI helpers)
|
||||
uses: dtolnay/rust-toolchain@02cb101ec7c40f2c49e1d9714d64511d8e1b74de
|
||||
with:
|
||||
toolchain: "1.98.1"
|
||||
- name: prepare docker config
|
||||
run: >-
|
||||
tools/ci/run.sh build-app-proxy
|
||||
--step prepare_docker_config
|
||||
- uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069
|
||||
- name: configure ghcr auth
|
||||
env:
|
||||
GHCR_USERNAME: ${{ github.actor }}
|
||||
GHCR_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: >-
|
||||
tools/ci/run.sh build-app-proxy
|
||||
--step configure_ghcr_auth
|
||||
|
||||
- name: build the dist once and publish it as the canonical asset image
|
||||
env:
|
||||
CACHE_FROM: type=registry,ref=ghcr.io/${{ env.GHCR_OWNER }}/fluxer-app-proxy-self-hosted:buildcache-dist
|
||||
CACHE_TO: type=registry,ref=ghcr.io/${{ env.GHCR_OWNER }}/fluxer-app-proxy-self-hosted:buildcache-dist,mode=max,image-manifest=true,oci-mediatypes=true,ignore-error=true
|
||||
DOCKER_BUILD_SUMMARY: false
|
||||
DOCKER_BUILD_RECORD_UPLOAD: false
|
||||
run: >-
|
||||
tools/ci/run.sh build-app-proxy
|
||||
--step build_dist
|
||||
|
||||
- name: generate asset manifest
|
||||
run: >-
|
||||
tools/ci/run.sh build-app-proxy
|
||||
--step generate_asset_manifest
|
||||
|
||||
- name: verify every manifest asset ships in the image
|
||||
run: >-
|
||||
tools/ci/run.sh build-app-proxy
|
||||
--step verify_published_assets
|
||||
|
||||
build:
|
||||
name: build ${{ matrix.platform }}
|
||||
needs: [meta, dist]
|
||||
runs-on: ${{ matrix.runner }}
|
||||
timeout-minutes: 75
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
packages: write
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- platform: amd64
|
||||
runner: ubuntu-24.04
|
||||
- platform: arm64
|
||||
runner: ubuntu-24.04-arm
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
|
||||
env:
|
||||
GIT_CONFIG_GLOBAL: ${{ runner.temp }}/gitconfig
|
||||
- name: resolve source date
|
||||
id: source
|
||||
run: echo "date=$(TZ=UTC git log -1 --no-show-signature --pretty=%cd --date=format-local:%Y-%m-%dT%H:%M:%SZ)" >> "$GITHUB_OUTPUT"
|
||||
- uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069
|
||||
- uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc
|
||||
with:
|
||||
context: .
|
||||
file: fluxer_app_proxy/Dockerfile
|
||||
push: true
|
||||
provenance: false
|
||||
platforms: linux/${{ matrix.platform }}
|
||||
tags: ghcr.io/${{ env.GHCR_OWNER }}/fluxer-app-proxy-self-hosted:${{ needs.meta.outputs.build_version }}-${{ matrix.platform }}
|
||||
build-args: |
|
||||
BUILD_VERSION=${{ needs.meta.outputs.build_version }}
|
||||
SOURCE_SHA=${{ github.sha }}
|
||||
SOURCE_DATE=${{ steps.source.outputs.date }}
|
||||
FLUXER_SELF_HOSTED=true
|
||||
APP_ASSETS_REF=ghcr.io/${{ env.GHCR_OWNER }}/fluxer-app-proxy-self-hosted:${{ needs.meta.outputs.build_version }}-assets
|
||||
APP_ASSETS_PLATFORM=linux/amd64
|
||||
cache-from: type=registry,ref=ghcr.io/${{ env.GHCR_OWNER }}/fluxer-app-proxy-self-hosted:buildcache-${{ matrix.platform }}
|
||||
cache-to: type=registry,ref=ghcr.io/${{ env.GHCR_OWNER }}/fluxer-app-proxy-self-hosted:buildcache-${{ matrix.platform }},mode=max,image-manifest=true,oci-mediatypes=true,ignore-error=true
|
||||
env:
|
||||
DOCKER_BUILD_SUMMARY: false
|
||||
DOCKER_BUILD_RECORD_UPLOAD: false
|
||||
|
||||
merge:
|
||||
name: merge multi-arch manifest
|
||||
needs: [meta, build]
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 20
|
||||
permissions:
|
||||
contents: write
|
||||
packages: write
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
|
||||
env:
|
||||
GIT_CONFIG_GLOBAL: ${{ runner.temp }}/gitconfig
|
||||
- name: Set up Rust toolchain (CI helpers)
|
||||
uses: dtolnay/rust-toolchain@02cb101ec7c40f2c49e1d9714d64511d8e1b74de
|
||||
with:
|
||||
toolchain: "1.98.1"
|
||||
- uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069
|
||||
- uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: verify cross-architecture asset parity
|
||||
env:
|
||||
APP_PROXY_ASSETS_REF: ghcr.io/${{ env.GHCR_OWNER }}/fluxer-app-proxy-self-hosted:${{ needs.meta.outputs.build_version }}-assets
|
||||
APP_PROXY_AMD64_REF: ghcr.io/${{ env.GHCR_OWNER }}/fluxer-app-proxy-self-hosted:${{ needs.meta.outputs.build_version }}-amd64
|
||||
APP_PROXY_ARM64_REF: ghcr.io/${{ env.GHCR_OWNER }}/fluxer-app-proxy-self-hosted:${{ needs.meta.outputs.build_version }}-arm64
|
||||
run: >-
|
||||
tools/ci/run.sh build-app-proxy
|
||||
--step verify_asset_parity
|
||||
|
||||
- name: create and push multi-arch manifest
|
||||
env:
|
||||
IMAGE: ghcr.io/${{ env.GHCR_OWNER }}/fluxer-app-proxy-self-hosted
|
||||
VERSION: ${{ needs.meta.outputs.build_version }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
docker buildx imagetools create -t "${IMAGE}:${VERSION}" \
|
||||
"${IMAGE}:${VERSION}-amd64" \
|
||||
"${IMAGE}:${VERSION}-arm64"
|
||||
docker buildx imagetools inspect "${IMAGE}:${VERSION}"
|
||||
|
||||
- name: Create token
|
||||
id: create-token
|
||||
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1
|
||||
with:
|
||||
client-id: ${{ vars.FLUXER_CI_APP_ID }}
|
||||
private-key: ${{ secrets.FLUXER_CI_APP_KEY }}
|
||||
owner: fluxerapp
|
||||
repositories: fluxer
|
||||
permission-contents: write
|
||||
- name: Publish GitHub release
|
||||
env:
|
||||
GH_TOKEN: ${{ steps.create-token.outputs.token }}
|
||||
SOURCE_SHA: ${{ github.sha }}
|
||||
VERSION: ${{ needs.meta.outputs.build_version }}
|
||||
RELEASE_BASELINE_SHA: ${{ vars.RELEASE_BASELINE_SHA }}
|
||||
run: >-
|
||||
tools/ci/run.sh release
|
||||
publish
|
||||
--component fluxer-app-proxy-self-hosted
|
||||
--build-version "${VERSION}"
|
||||
--source-sha "${SOURCE_SHA}"
|
||||
--previous-sha "${RELEASE_BASELINE_SHA}"
|
||||
|
||||
- name: Advance moving image tags
|
||||
env:
|
||||
VERSION: ${{ needs.meta.outputs.build_version }}
|
||||
run: >-
|
||||
tools/ci/run.sh image-set
|
||||
promote
|
||||
--component fluxer-app-proxy-self-hosted
|
||||
--build-version "${VERSION}"
|
||||
--registry "ghcr.io/${{ env.GHCR_OWNER }}"
|
||||
--moving-tags v1,latest
|
||||
@@ -43,97 +43,154 @@ jobs:
|
||||
outputs:
|
||||
build_version: ${{ steps.vars.outputs.build_version }}
|
||||
steps:
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
|
||||
env:
|
||||
GIT_CONFIG_GLOBAL: ${{ runner.temp }}/gitconfig
|
||||
- name: Set up Rust toolchain (CI helpers)
|
||||
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9
|
||||
uses: dtolnay/rust-toolchain@02cb101ec7c40f2c49e1d9714d64511d8e1b74de
|
||||
with:
|
||||
toolchain: "1.93.0"
|
||||
toolchain: "1.98.1"
|
||||
- name: set variables
|
||||
id: vars
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- build-app-proxy
|
||||
tools/ci/run.sh build-app-proxy
|
||||
--step set_metadata
|
||||
--build-version "${{ inputs['build-version'] }}"
|
||||
|
||||
build:
|
||||
name: build app-proxy (amd64)
|
||||
dist:
|
||||
name: build and publish the canonical asset tree
|
||||
needs: meta
|
||||
runs-on: blacksmith-4vcpu-ubuntu-2404
|
||||
timeout-minutes: 45
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
packages: write
|
||||
steps:
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
|
||||
env:
|
||||
GIT_CONFIG_GLOBAL: ${{ runner.temp }}/gitconfig
|
||||
- name: Set up Rust toolchain (CI helpers)
|
||||
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9
|
||||
with:
|
||||
toolchain: "1.93.0"
|
||||
- name: prepare docker config
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- build-app-proxy
|
||||
--step prepare_docker_config
|
||||
- uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5
|
||||
- name: configure ghcr auth
|
||||
env:
|
||||
GHCR_USERNAME: ${{ github.actor }}
|
||||
GHCR_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- build-app-proxy
|
||||
--step configure_ghcr_auth
|
||||
|
||||
- name: build and push image + extract assets
|
||||
env:
|
||||
BUILD_VERSION: ${{ needs.meta.outputs.build_version }}
|
||||
PUBLIC_ASSET_BASE_URL: https://fluxerstatic.com
|
||||
CACHE_FROM: type=gha,scope=fluxer-app-proxy
|
||||
CACHE_TO: type=gha,scope=fluxer-app-proxy,mode=max
|
||||
DOCKER_BUILD_SUMMARY: false
|
||||
DOCKER_BUILD_RECORD_UPLOAD: false
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- build-app-proxy
|
||||
--step build_and_extract
|
||||
|
||||
- name: generate asset manifest
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- build-app-proxy
|
||||
--step generate_asset_manifest
|
||||
|
||||
- name: upload assets to S3 static bucket
|
||||
env:
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
S3_ENDPOINT: https://ewr1.vultrobjects.com
|
||||
STATIC_BUCKET: fluxer-static
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- build-app-proxy
|
||||
--step upload_assets
|
||||
|
||||
build-arm64:
|
||||
name: build app-proxy (arm64)
|
||||
needs: meta
|
||||
runs-on: blacksmith-4vcpu-ubuntu-2404-arm
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 60
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
packages: write
|
||||
steps:
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
|
||||
env:
|
||||
GIT_CONFIG_GLOBAL: ${{ runner.temp }}/gitconfig
|
||||
- uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5
|
||||
- uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee
|
||||
- name: Set up Rust toolchain (CI helpers)
|
||||
uses: dtolnay/rust-toolchain@02cb101ec7c40f2c49e1d9714d64511d8e1b74de
|
||||
with:
|
||||
toolchain: "1.98.1"
|
||||
- name: prepare docker config
|
||||
run: >-
|
||||
tools/ci/run.sh build-app-proxy
|
||||
--step prepare_docker_config
|
||||
- uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069
|
||||
- name: configure ghcr auth
|
||||
env:
|
||||
GHCR_USERNAME: ${{ github.actor }}
|
||||
GHCR_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: >-
|
||||
tools/ci/run.sh build-app-proxy
|
||||
--step configure_ghcr_auth
|
||||
|
||||
- name: build the dist once and publish it as the canonical asset image
|
||||
env:
|
||||
BUILD_VERSION: ${{ needs.meta.outputs.build_version }}
|
||||
PUBLIC_ASSET_BASE_URL: https://fluxerstatic.com
|
||||
CACHE_FROM: type=registry,ref=ghcr.io/${{ env.GHCR_OWNER }}/fluxer-app-proxy:buildcache-dist
|
||||
CACHE_TO: type=registry,ref=ghcr.io/${{ env.GHCR_OWNER }}/fluxer-app-proxy:buildcache-dist,mode=max,image-manifest=true,oci-mediatypes=true,ignore-error=true
|
||||
DOCKER_BUILD_SUMMARY: false
|
||||
DOCKER_BUILD_RECORD_UPLOAD: false
|
||||
run: >-
|
||||
tools/ci/run.sh build-app-proxy
|
||||
--step build_dist
|
||||
|
||||
- name: generate asset manifest
|
||||
run: >-
|
||||
tools/ci/run.sh build-app-proxy
|
||||
--step generate_asset_manifest
|
||||
|
||||
- name: upload assets to S3 static bucket
|
||||
env:
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.STATIC_AWS_ACCESS_KEY_ID || secrets.AWS_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.STATIC_AWS_SECRET_ACCESS_KEY || secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
S3_ENDPOINT: ${{ vars.STATIC_S3_ENDPOINT }}
|
||||
STATIC_BUCKET: ${{ vars.STATIC_S3_BUCKET }}
|
||||
run: >-
|
||||
tools/ci/run.sh build-app-proxy
|
||||
--step upload_assets
|
||||
|
||||
- name: verify every uploaded asset is readable
|
||||
env:
|
||||
PUBLIC_ASSET_BASE_URL: https://fluxerstatic.com
|
||||
run: >-
|
||||
tools/ci/run.sh build-app-proxy
|
||||
--step verify_published_assets
|
||||
|
||||
build:
|
||||
name: build app-proxy (amd64)
|
||||
needs: [meta, dist]
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 45
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
packages: write
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
|
||||
env:
|
||||
GIT_CONFIG_GLOBAL: ${{ runner.temp }}/gitconfig
|
||||
- name: Set up Rust toolchain (CI helpers)
|
||||
uses: dtolnay/rust-toolchain@02cb101ec7c40f2c49e1d9714d64511d8e1b74de
|
||||
with:
|
||||
toolchain: "1.98.1"
|
||||
- name: resolve source date
|
||||
id: source
|
||||
run: echo "date=$(TZ=UTC git log -1 --no-show-signature --pretty=%cd --date=format-local:%Y-%m-%dT%H:%M:%SZ)" >> "$GITHUB_OUTPUT"
|
||||
- name: prepare docker config
|
||||
run: >-
|
||||
tools/ci/run.sh build-app-proxy
|
||||
--step prepare_docker_config
|
||||
- uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069
|
||||
- name: configure ghcr auth
|
||||
env:
|
||||
GHCR_USERNAME: ${{ github.actor }}
|
||||
GHCR_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: >-
|
||||
tools/ci/run.sh build-app-proxy
|
||||
--step configure_ghcr_auth
|
||||
|
||||
- name: build and push image
|
||||
env:
|
||||
BUILD_VERSION: ${{ needs.meta.outputs.build_version }}
|
||||
SOURCE_SHA: ${{ github.sha }}
|
||||
SOURCE_DATE: ${{ steps.source.outputs.date }}
|
||||
PUBLIC_ASSET_BASE_URL: https://fluxerstatic.com
|
||||
CACHE_FROM: type=registry,ref=ghcr.io/${{ env.GHCR_OWNER }}/fluxer-app-proxy:buildcache-amd64
|
||||
CACHE_TO: type=registry,ref=ghcr.io/${{ env.GHCR_OWNER }}/fluxer-app-proxy:buildcache-amd64,mode=max,image-manifest=true,oci-mediatypes=true,ignore-error=true
|
||||
DOCKER_BUILD_SUMMARY: false
|
||||
DOCKER_BUILD_RECORD_UPLOAD: false
|
||||
run: >-
|
||||
tools/ci/run.sh build-app-proxy
|
||||
--step build_image
|
||||
|
||||
build-arm64:
|
||||
name: build app-proxy (arm64)
|
||||
needs: [meta, dist]
|
||||
runs-on: ubuntu-24.04-arm
|
||||
timeout-minutes: 60
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
packages: write
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
|
||||
env:
|
||||
GIT_CONFIG_GLOBAL: ${{ runner.temp }}/gitconfig
|
||||
- name: resolve source date
|
||||
id: source
|
||||
run: echo "date=$(TZ=UTC git log -1 --no-show-signature --pretty=%cd --date=format-local:%Y-%m-%dT%H:%M:%SZ)" >> "$GITHUB_OUTPUT"
|
||||
- uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069
|
||||
- uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf
|
||||
- uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc
|
||||
with:
|
||||
context: .
|
||||
file: fluxer_app_proxy/Dockerfile
|
||||
@@ -144,9 +201,12 @@ jobs:
|
||||
build-args: |
|
||||
BUILD_VERSION=${{ needs.meta.outputs.build_version }}
|
||||
PUBLIC_ASSET_BASE_URL=https://fluxerstatic.com
|
||||
BUNDLE_LOCAL_ASSETS=false
|
||||
cache-from: type=gha,scope=fluxer-app-proxy-arm64
|
||||
cache-to: type=gha,scope=fluxer-app-proxy-arm64,mode=max,ignore-error=true
|
||||
SOURCE_SHA=${{ github.sha }}
|
||||
SOURCE_DATE=${{ steps.source.outputs.date }}
|
||||
APP_ASSETS_REF=ghcr.io/${{ env.GHCR_OWNER }}/fluxer-app-proxy:${{ needs.meta.outputs.build_version }}-assets
|
||||
APP_ASSETS_PLATFORM=linux/amd64
|
||||
cache-from: type=registry,ref=ghcr.io/${{ env.GHCR_OWNER }}/fluxer-app-proxy:buildcache-arm64
|
||||
cache-to: type=registry,ref=ghcr.io/${{ env.GHCR_OWNER }}/fluxer-app-proxy:buildcache-arm64,mode=max,image-manifest=true,oci-mediatypes=true,ignore-error=true
|
||||
env:
|
||||
DOCKER_BUILD_SUMMARY: false
|
||||
DOCKER_BUILD_RECORD_UPLOAD: false
|
||||
@@ -155,24 +215,33 @@ jobs:
|
||||
name: merge multi-arch manifest
|
||||
needs: [meta, build, build-arm64]
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 10
|
||||
timeout-minutes: 20
|
||||
permissions:
|
||||
contents: write
|
||||
packages: write
|
||||
steps:
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
|
||||
env:
|
||||
GIT_CONFIG_GLOBAL: ${{ runner.temp }}/gitconfig
|
||||
- name: Set up Rust toolchain (CI helpers)
|
||||
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9
|
||||
uses: dtolnay/rust-toolchain@02cb101ec7c40f2c49e1d9714d64511d8e1b74de
|
||||
with:
|
||||
toolchain: "1.93.0"
|
||||
- uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5
|
||||
- uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee
|
||||
toolchain: "1.98.1"
|
||||
- uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069
|
||||
- uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: verify cross-architecture asset parity
|
||||
env:
|
||||
APP_PROXY_ASSETS_REF: ghcr.io/${{ env.GHCR_OWNER }}/fluxer-app-proxy:${{ needs.meta.outputs.build_version }}-assets
|
||||
APP_PROXY_AMD64_REF: ghcr.io/${{ env.GHCR_OWNER }}/fluxer-app-proxy:${{ needs.meta.outputs.build_version }}
|
||||
APP_PROXY_ARM64_REF: ghcr.io/${{ env.GHCR_OWNER }}/fluxer-app-proxy:${{ needs.meta.outputs.build_version }}-arm64
|
||||
run: >-
|
||||
tools/ci/run.sh build-app-proxy
|
||||
--step verify_asset_parity
|
||||
|
||||
- name: fuse amd64 + arm64 into a multi-arch manifest
|
||||
env:
|
||||
IMAGE: ghcr.io/${{ env.GHCR_OWNER }}/fluxer-app-proxy
|
||||
@@ -203,7 +272,7 @@ jobs:
|
||||
VERSION: ${{ needs.meta.outputs.build_version }}
|
||||
RELEASE_BASELINE_SHA: ${{ vars.RELEASE_BASELINE_SHA }}
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- release
|
||||
tools/ci/run.sh release
|
||||
publish
|
||||
--component fluxer-app-proxy
|
||||
--build-version "${VERSION}"
|
||||
@@ -212,10 +281,11 @@ jobs:
|
||||
|
||||
- name: Advance moving image tags
|
||||
env:
|
||||
IMAGE: ghcr.io/${{ env.GHCR_OWNER }}/fluxer-app-proxy
|
||||
VERSION: ${{ needs.meta.outputs.build_version }}
|
||||
run: >-
|
||||
docker buildx imagetools create
|
||||
-t "${IMAGE}:v1"
|
||||
-t "${IMAGE}:latest"
|
||||
"${IMAGE}:${VERSION}"
|
||||
tools/ci/run.sh image-set
|
||||
promote
|
||||
--component fluxer-app-proxy
|
||||
--build-version "${VERSION}"
|
||||
--registry "ghcr.io/${{ env.GHCR_OWNER }}"
|
||||
--moving-tags v1,latest
|
||||
@@ -0,0 +1,355 @@
|
||||
name: build desktop modules
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
channel:
|
||||
description: Release channel to ship renderer modules on. The live shell on that channel stays as it is.
|
||||
required: true
|
||||
type: choice
|
||||
options:
|
||||
- canary
|
||||
- stable
|
||||
default: canary
|
||||
build_version:
|
||||
description: Explicit Fluxer CalVer build version (YYYY.MDD.MICRO, UTC HHMMSS without leading zeroes) to use instead of automatic UTC clock allocation.
|
||||
required: false
|
||||
default: ""
|
||||
type: string
|
||||
shell_contract:
|
||||
description: "Did the shell contract change since the oldest shell these modules still reach? unchanged refuses if it did. compatible keeps older shells on these modules because the renderer still works on them. raise stops sending these modules to shells without the new contract: Linux and managed shells keep their current renderer, Windows and macOS update their shell first."
|
||||
required: true
|
||||
type: choice
|
||||
options:
|
||||
- unchanged
|
||||
- compatible
|
||||
- raise
|
||||
default: unchanged
|
||||
permissions:
|
||||
contents: write
|
||||
id-token: write
|
||||
actions: read
|
||||
|
||||
concurrency:
|
||||
group: desktop-${{ inputs.channel }}
|
||||
cancel-in-progress: false
|
||||
|
||||
env:
|
||||
CHANNEL: ${{ inputs.channel }}
|
||||
BUILD_CHANNEL: ${{ inputs.channel == 'canary' && 'canary' || 'stable' }}
|
||||
|
||||
jobs:
|
||||
meta:
|
||||
name: Resolve build metadata
|
||||
runs-on: ubuntu-24.04-arm
|
||||
environment: desktop-releases
|
||||
timeout-minutes: 25
|
||||
permissions:
|
||||
contents: read
|
||||
outputs:
|
||||
version: ${{ steps.meta.outputs.version }}
|
||||
pub_date: ${{ steps.meta.outputs.pub_date }}
|
||||
channel: ${{ steps.meta.outputs.channel }}
|
||||
build_channel: ${{ steps.meta.outputs.build_channel }}
|
||||
source_sha: ${{ steps.meta.outputs.source_sha }}
|
||||
steps:
|
||||
- name: Checkout source
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
|
||||
with:
|
||||
ref: main
|
||||
|
||||
- name: Set up Rust toolchain (CI helpers)
|
||||
uses: dtolnay/rust-toolchain@02cb101ec7c40f2c49e1d9714d64511d8e1b74de
|
||||
with:
|
||||
toolchain: "1.98.1"
|
||||
|
||||
- name: Create token
|
||||
id: create-token
|
||||
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1
|
||||
with:
|
||||
client-id: ${{ vars.FLUXER_CI_APP_ID }}
|
||||
private-key: ${{ secrets.FLUXER_CI_APP_KEY }}
|
||||
owner: fluxerapp
|
||||
repositories: fluxer
|
||||
permission-contents: read
|
||||
- name: Set metadata
|
||||
id: meta
|
||||
env:
|
||||
GH_TOKEN: ${{ steps.create-token.outputs.token }}
|
||||
FLUXER_BUILD_VERSION: ${{ inputs.build_version }}
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- build-desktop
|
||||
--step set_metadata
|
||||
--channel "${{ inputs.channel }}"
|
||||
|
||||
shared_assets:
|
||||
name: Build shared renderer assets
|
||||
needs:
|
||||
- meta
|
||||
runs-on: ubuntu-24.04
|
||||
environment: desktop-releases
|
||||
timeout-minutes: 60
|
||||
permissions:
|
||||
contents: read
|
||||
env:
|
||||
CHANNEL: ${{ needs.meta.outputs.channel }}
|
||||
BUILD_CHANNEL: ${{ needs.meta.outputs.build_channel }}
|
||||
RELEASE_CHANNEL: ${{ needs.meta.outputs.build_channel }}
|
||||
PUBLIC_RELEASE_CHANNEL: ${{ needs.meta.outputs.build_channel }}
|
||||
VERSION: ${{ needs.meta.outputs.version }}
|
||||
BUILD_VERSION: ${{ needs.meta.outputs.version }}
|
||||
PUBLIC_BUILD_VERSION: ${{ needs.meta.outputs.version }}
|
||||
SOURCE_SHA: ${{ needs.meta.outputs.source_sha }}
|
||||
steps:
|
||||
- name: Checkout CI helpers
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
|
||||
with:
|
||||
ref: ${{ needs.meta.outputs.source_sha }}
|
||||
path: _ci
|
||||
|
||||
- name: Checkout source
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
|
||||
with:
|
||||
ref: ${{ needs.meta.outputs.source_sha }}
|
||||
path: source
|
||||
|
||||
- name: Set up Rust toolchain (renderer wasm)
|
||||
uses: dtolnay/rust-toolchain@02cb101ec7c40f2c49e1d9714d64511d8e1b74de
|
||||
with:
|
||||
toolchain: "1.98.1"
|
||||
targets: wasm32-unknown-unknown
|
||||
|
||||
- name: Set workdir (Unix)
|
||||
env:
|
||||
SUBST_TARGET: ${{ github.workspace }}/source
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path ${{ github.workspace }}/_ci/tools/ci/Cargo.toml -- build-desktop
|
||||
--step set_workdir_unix
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020
|
||||
with:
|
||||
node-version: 26
|
||||
|
||||
- name: Set up pnpm
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path ${{ github.workspace }}/_ci/tools/ci/Cargo.toml -- build-desktop
|
||||
--step setup_pnpm
|
||||
|
||||
- name: Resolve pnpm store path (Unix)
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path ${{ github.workspace }}/_ci/tools/ci/Cargo.toml -- build-desktop
|
||||
--step resolve_pnpm_store_unix
|
||||
|
||||
- name: Cache pnpm store
|
||||
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9
|
||||
with:
|
||||
path: ${{ env.PNPM_STORE_PATH }}
|
||||
key: ${{ runner.os }}-shared-renderer-pnpm-store-${{ hashFiles('source/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-shared-renderer-pnpm-store-
|
||||
|
||||
- name: Cache cargo registry
|
||||
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry
|
||||
~/.cargo/git
|
||||
key: ${{ runner.os }}-shared-renderer-cargo-registry-${{ hashFiles('source/Cargo.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-shared-renderer-cargo-registry-
|
||||
|
||||
- name: Install dependencies
|
||||
working-directory: ${{ env.WORKDIR }}/fluxer_desktop
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path ${{ github.workspace }}/_ci/tools/ci/Cargo.toml -- build-desktop
|
||||
--step install_dependencies
|
||||
|
||||
- name: Update version
|
||||
working-directory: ${{ env.WORKDIR }}/fluxer_desktop
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path ${{ github.workspace }}/_ci/tools/ci/Cargo.toml -- build-desktop
|
||||
--step update_version
|
||||
|
||||
- name: Set build channel
|
||||
working-directory: ${{ env.WORKDIR }}/fluxer_desktop
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path ${{ github.workspace }}/_ci/tools/ci/Cargo.toml -- build-desktop
|
||||
--step set_build_channel
|
||||
|
||||
- name: Build shared renderer assets
|
||||
working-directory: ${{ env.WORKDIR }}/fluxer_desktop
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path ${{ github.workspace }}/_ci/tools/ci/Cargo.toml -- build-desktop
|
||||
--step build_shared_assets
|
||||
|
||||
- name: Prepare shared renderer artifact
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path ${{ github.workspace }}/_ci/tools/ci/Cargo.toml -- build-desktop
|
||||
--step prepare_shared_assets
|
||||
|
||||
- name: Upload shared renderer artifact
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
|
||||
with:
|
||||
name: desktop-shared-${{ needs.meta.outputs.build_channel }}-${{ needs.meta.outputs.version }}-${{ needs.meta.outputs.source_sha }}
|
||||
path: source/desktop-shared-assets
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
compression-level: 0
|
||||
|
||||
- name: Split renderer into desktop modules
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path ${{ github.workspace }}/_ci/tools/ci/Cargo.toml -- build-desktop
|
||||
--step split_modules
|
||||
|
||||
- name: Pack desktop modules
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path ${{ github.workspace }}/_ci/tools/ci/Cargo.toml -- build-desktop
|
||||
--step pack_modules
|
||||
|
||||
- name: Upload desktop module packages
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
|
||||
with:
|
||||
name: desktop-modules-${{ needs.meta.outputs.build_channel }}-${{ needs.meta.outputs.version }}-${{ needs.meta.outputs.source_sha }}
|
||||
path: |
|
||||
source/desktop-modules/classification.json
|
||||
source/desktop-modules/*/module.json
|
||||
source/desktop-modules/*/package.br
|
||||
source/desktop-modules/*/package.br.sha256
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
compression-level: 0
|
||||
|
||||
assemble:
|
||||
name: Assemble the modules-only release
|
||||
if: ${{ !cancelled() && needs.shared_assets.result == 'success' }}
|
||||
needs:
|
||||
- meta
|
||||
- shared_assets
|
||||
runs-on: ubuntu-24.04-arm
|
||||
environment: desktop-releases
|
||||
timeout-minutes: 60
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
env:
|
||||
CHANNEL: ${{ needs.meta.outputs.build_channel }}
|
||||
VERSION: ${{ needs.meta.outputs.version }}
|
||||
PUB_DATE: ${{ needs.meta.outputs.pub_date }}
|
||||
SOURCE_SHA: ${{ needs.meta.outputs.source_sha }}
|
||||
steps:
|
||||
- name: Checkout source
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
|
||||
with:
|
||||
ref: ${{ needs.meta.outputs.source_sha }}
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Rust toolchain (CI helpers)
|
||||
uses: dtolnay/rust-toolchain@02cb101ec7c40f2c49e1d9714d64511d8e1b74de
|
||||
with:
|
||||
toolchain: "1.98.1"
|
||||
|
||||
- name: Download desktop module packages
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
|
||||
with:
|
||||
name: desktop-modules-${{ needs.meta.outputs.build_channel }}-${{ needs.meta.outputs.version }}-${{ needs.meta.outputs.source_sha }}
|
||||
path: desktop-modules
|
||||
|
||||
- name: Create token
|
||||
id: create-token
|
||||
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1
|
||||
with:
|
||||
client-id: ${{ vars.FLUXER_CI_APP_ID }}
|
||||
private-key: ${{ secrets.FLUXER_CI_APP_KEY }}
|
||||
owner: fluxerapp
|
||||
repositories: fluxer
|
||||
permission-contents: read
|
||||
- name: Check which shells run these modules
|
||||
env:
|
||||
GH_TOKEN: ${{ steps.create-token.outputs.token }}
|
||||
SHELL_CONTRACT: ${{ inputs.shell_contract }}
|
||||
DESKTOP_MODULES_ONLY_RELEASE: true
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- build-desktop
|
||||
--step check_shell_contract
|
||||
|
||||
- name: Build the modules-only manifests
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- build-desktop
|
||||
--step build_modules_only_manifest
|
||||
|
||||
- name: Prepare GitHub release assets
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- build-desktop
|
||||
--step prepare_modules_release_assets
|
||||
|
||||
- name: Upload GitHub release assets
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
|
||||
with:
|
||||
name: fluxer-desktop-modules-release-assets
|
||||
path: release_assets
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
compression-level: 0
|
||||
|
||||
publish_release:
|
||||
name: Publish GitHub modules-only release
|
||||
if: ${{ !cancelled() && needs.assemble.result == 'success' }}
|
||||
needs:
|
||||
- meta
|
||||
- assemble
|
||||
runs-on: ubuntu-24.04-arm
|
||||
environment: desktop-releases
|
||||
timeout-minutes: 60
|
||||
permissions:
|
||||
contents: write
|
||||
env:
|
||||
CHANNEL: ${{ needs.meta.outputs.build_channel }}
|
||||
VERSION: ${{ needs.meta.outputs.version }}
|
||||
steps:
|
||||
- name: Checkout source
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
|
||||
with:
|
||||
ref: ${{ needs.meta.outputs.source_sha }}
|
||||
|
||||
- name: Set up Rust toolchain (CI helpers)
|
||||
uses: dtolnay/rust-toolchain@02cb101ec7c40f2c49e1d9714d64511d8e1b74de
|
||||
with:
|
||||
toolchain: "1.98.1"
|
||||
|
||||
- name: Download GitHub release assets
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
|
||||
with:
|
||||
name: fluxer-desktop-modules-release-assets
|
||||
path: release_assets
|
||||
|
||||
- name: Create token
|
||||
id: create-token
|
||||
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1
|
||||
with:
|
||||
client-id: ${{ vars.FLUXER_CI_APP_ID }}
|
||||
private-key: ${{ secrets.FLUXER_CI_APP_KEY }}
|
||||
owner: fluxerapp
|
||||
repositories: fluxer
|
||||
permission-contents: write
|
||||
- name: Publish GitHub modules-only release
|
||||
env:
|
||||
GH_TOKEN: ${{ steps.create-token.outputs.token }}
|
||||
CHANNEL: ${{ needs.meta.outputs.build_channel }}
|
||||
VERSION: ${{ needs.meta.outputs.version }}
|
||||
SOURCE_SHA: ${{ needs.meta.outputs.source_sha }}
|
||||
RELEASE_BASELINE_SHA: ${{ vars.RELEASE_BASELINE_SHA }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
release_args=(
|
||||
release publish
|
||||
--component "fluxer-desktop-${CHANNEL}"
|
||||
--build-version "${VERSION}"
|
||||
--source-sha "${SOURCE_SHA}"
|
||||
--previous-sha "${RELEASE_BASELINE_SHA}"
|
||||
--asset-dir release_assets
|
||||
)
|
||||
if [[ "${CHANNEL}" == "canary" ]]; then
|
||||
release_args+=(--prerelease)
|
||||
fi
|
||||
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- "${release_args[@]}"
|
||||
@@ -11,11 +11,6 @@ on:
|
||||
- stable
|
||||
- canary
|
||||
default: stable
|
||||
test_build:
|
||||
description: Stash artifacts under desktop-test/ instead of desktop/ (API will not pick these up as a release).
|
||||
required: false
|
||||
default: false
|
||||
type: boolean
|
||||
build_version:
|
||||
description: Explicit Fluxer CalVer build version (YYYY.MDD.MICRO, UTC HHMMSS without leading zeroes) to use instead of automatic UTC clock allocation.
|
||||
required: false
|
||||
@@ -26,19 +21,27 @@ on:
|
||||
required: false
|
||||
default: ""
|
||||
type: string
|
||||
shell_contract:
|
||||
description: "Did the shell contract change since the oldest shell these modules still reach? unchanged refuses if it did. compatible keeps older shells on these modules because the renderer still works on them. raise stops sending these modules to shells without the new contract: Linux and managed shells keep their current renderer, Windows and macOS update their shell first."
|
||||
required: true
|
||||
type: choice
|
||||
options:
|
||||
- unchanged
|
||||
- compatible
|
||||
- raise
|
||||
default: unchanged
|
||||
permissions:
|
||||
contents: write
|
||||
id-token: write
|
||||
actions: read
|
||||
|
||||
concurrency:
|
||||
group: desktop-${{ inputs.channel }}-${{ inputs.test_build && 'test' || 'release' }}
|
||||
cancel-in-progress: true
|
||||
group: desktop-${{ inputs.channel }}
|
||||
cancel-in-progress: false
|
||||
|
||||
env:
|
||||
CHANNEL: ${{ inputs.channel }}
|
||||
BUILD_CHANNEL: ${{ inputs.channel == 'canary' && 'canary' || 'stable' }}
|
||||
TEST_BUILD: ${{ inputs.test_build && 'true' || 'false' }}
|
||||
|
||||
jobs:
|
||||
meta:
|
||||
@@ -53,19 +56,18 @@ jobs:
|
||||
pub_date: ${{ steps.meta.outputs.pub_date }}
|
||||
channel: ${{ steps.meta.outputs.channel }}
|
||||
build_channel: ${{ steps.meta.outputs.build_channel }}
|
||||
test_build: ${{ steps.meta.outputs.test_build }}
|
||||
s3_prefix: ${{ steps.meta.outputs.s3_prefix }}
|
||||
source_sha: ${{ steps.meta.outputs.source_sha }}
|
||||
steps:
|
||||
- name: Checkout source
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
|
||||
with:
|
||||
ref: main
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Rust toolchain (CI helpers)
|
||||
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9
|
||||
uses: dtolnay/rust-toolchain@02cb101ec7c40f2c49e1d9714d64511d8e1b74de
|
||||
with:
|
||||
toolchain: "1.93.0"
|
||||
toolchain: "1.98.1"
|
||||
|
||||
- name: Create token
|
||||
id: create-token
|
||||
@@ -85,7 +87,18 @@ jobs:
|
||||
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- build-desktop
|
||||
--step set_metadata
|
||||
--channel "${{ inputs.channel }}"
|
||||
--test-build "${{ inputs.test_build }}"
|
||||
|
||||
- name: Check which shells run these modules
|
||||
env:
|
||||
GH_TOKEN: ${{ steps.create-token.outputs.token }}
|
||||
CHANNEL: ${{ steps.meta.outputs.build_channel }}
|
||||
SOURCE_SHA: ${{ steps.meta.outputs.source_sha }}
|
||||
VERSION: ${{ steps.meta.outputs.version }}
|
||||
SHELL_CONTRACT: ${{ inputs.shell_contract }}
|
||||
DESKTOP_MODULES_ONLY_RELEASE: false
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- build-desktop
|
||||
--step check_shell_contract
|
||||
|
||||
matrix:
|
||||
name: Resolve build matrix
|
||||
@@ -98,12 +111,12 @@ jobs:
|
||||
matrix: ${{ steps.set-matrix.outputs.matrix }}
|
||||
steps:
|
||||
- name: Checkout source
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
|
||||
|
||||
- name: Set up Rust toolchain (CI helpers)
|
||||
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9
|
||||
uses: dtolnay/rust-toolchain@02cb101ec7c40f2c49e1d9714d64511d8e1b74de
|
||||
with:
|
||||
toolchain: "1.93.0"
|
||||
toolchain: "1.98.1"
|
||||
|
||||
- name: Build platform matrix
|
||||
id: set-matrix
|
||||
@@ -112,14 +125,153 @@ jobs:
|
||||
--step set_matrix
|
||||
--skip-targets "${{ inputs.skip_targets }}"
|
||||
|
||||
shared_assets:
|
||||
name: Build shared renderer assets
|
||||
needs:
|
||||
- meta
|
||||
runs-on: ubuntu-24.04
|
||||
environment: desktop-releases
|
||||
timeout-minutes: 60
|
||||
permissions:
|
||||
contents: read
|
||||
env:
|
||||
CHANNEL: ${{ needs.meta.outputs.channel }}
|
||||
BUILD_CHANNEL: ${{ needs.meta.outputs.build_channel }}
|
||||
RELEASE_CHANNEL: ${{ needs.meta.outputs.build_channel }}
|
||||
PUBLIC_RELEASE_CHANNEL: ${{ needs.meta.outputs.build_channel }}
|
||||
VERSION: ${{ needs.meta.outputs.version }}
|
||||
BUILD_VERSION: ${{ needs.meta.outputs.version }}
|
||||
PUBLIC_BUILD_VERSION: ${{ needs.meta.outputs.version }}
|
||||
SOURCE_SHA: ${{ needs.meta.outputs.source_sha }}
|
||||
steps:
|
||||
- name: Checkout CI helpers
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
|
||||
with:
|
||||
ref: ${{ needs.meta.outputs.source_sha }}
|
||||
path: _ci
|
||||
|
||||
- name: Checkout source
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
|
||||
with:
|
||||
ref: ${{ needs.meta.outputs.source_sha }}
|
||||
path: source
|
||||
|
||||
- name: Set up Rust toolchain (renderer wasm)
|
||||
uses: dtolnay/rust-toolchain@02cb101ec7c40f2c49e1d9714d64511d8e1b74de
|
||||
with:
|
||||
toolchain: "1.98.1"
|
||||
targets: wasm32-unknown-unknown
|
||||
|
||||
- name: Set workdir (Unix)
|
||||
env:
|
||||
SUBST_TARGET: ${{ github.workspace }}/source
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path ${{ github.workspace }}/_ci/tools/ci/Cargo.toml -- build-desktop
|
||||
--step set_workdir_unix
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020
|
||||
with:
|
||||
node-version: 26
|
||||
|
||||
- name: Set up pnpm
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path ${{ github.workspace }}/_ci/tools/ci/Cargo.toml -- build-desktop
|
||||
--step setup_pnpm
|
||||
|
||||
- name: Resolve pnpm store path (Unix)
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path ${{ github.workspace }}/_ci/tools/ci/Cargo.toml -- build-desktop
|
||||
--step resolve_pnpm_store_unix
|
||||
|
||||
- name: Cache pnpm store
|
||||
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9
|
||||
with:
|
||||
path: ${{ env.PNPM_STORE_PATH }}
|
||||
key: ${{ runner.os }}-shared-renderer-pnpm-store-${{ hashFiles('source/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-shared-renderer-pnpm-store-
|
||||
|
||||
- name: Cache cargo registry
|
||||
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry
|
||||
~/.cargo/git
|
||||
key: ${{ runner.os }}-shared-renderer-cargo-registry-${{ hashFiles('source/Cargo.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-shared-renderer-cargo-registry-
|
||||
|
||||
- name: Install dependencies
|
||||
working-directory: ${{ env.WORKDIR }}/fluxer_desktop
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path ${{ github.workspace }}/_ci/tools/ci/Cargo.toml -- build-desktop
|
||||
--step install_dependencies
|
||||
|
||||
- name: Update version
|
||||
working-directory: ${{ env.WORKDIR }}/fluxer_desktop
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path ${{ github.workspace }}/_ci/tools/ci/Cargo.toml -- build-desktop
|
||||
--step update_version
|
||||
|
||||
- name: Set build channel
|
||||
working-directory: ${{ env.WORKDIR }}/fluxer_desktop
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path ${{ github.workspace }}/_ci/tools/ci/Cargo.toml -- build-desktop
|
||||
--step set_build_channel
|
||||
|
||||
- name: Build shared renderer assets
|
||||
working-directory: ${{ env.WORKDIR }}/fluxer_desktop
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path ${{ github.workspace }}/_ci/tools/ci/Cargo.toml -- build-desktop
|
||||
--step build_shared_assets
|
||||
|
||||
- name: Prepare shared renderer artifact
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path ${{ github.workspace }}/_ci/tools/ci/Cargo.toml -- build-desktop
|
||||
--step prepare_shared_assets
|
||||
|
||||
- name: Upload shared renderer artifact
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
|
||||
with:
|
||||
name: desktop-shared-${{ needs.meta.outputs.build_channel }}-${{ needs.meta.outputs.version }}-${{ needs.meta.outputs.source_sha }}
|
||||
path: source/desktop-shared-assets
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
compression-level: 0
|
||||
|
||||
- name: Split renderer into desktop modules
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path ${{ github.workspace }}/_ci/tools/ci/Cargo.toml -- build-desktop
|
||||
--step split_modules
|
||||
|
||||
- name: Pack desktop modules
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path ${{ github.workspace }}/_ci/tools/ci/Cargo.toml -- build-desktop
|
||||
--step pack_modules
|
||||
|
||||
- name: Upload desktop module packages
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
|
||||
with:
|
||||
name: desktop-modules-${{ needs.meta.outputs.build_channel }}-${{ needs.meta.outputs.version }}-${{ needs.meta.outputs.source_sha }}
|
||||
path: |
|
||||
source/desktop-modules/classification.json
|
||||
source/desktop-modules/*/module.json
|
||||
source/desktop-modules/*/package.br
|
||||
source/desktop-modules/*/package.br.sha256
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
compression-level: 0
|
||||
|
||||
build:
|
||||
name: Build ${{ matrix.platform }} (${{ matrix.arch }}, ${{ matrix.desktop_variant }})
|
||||
name: Build ${{ matrix.platform }} (${{ matrix.arch }})
|
||||
needs:
|
||||
- meta
|
||||
- matrix
|
||||
- shared_assets
|
||||
runs-on: ${{ matrix.os }}
|
||||
environment: desktop-releases
|
||||
timeout-minutes: 60
|
||||
timeout-minutes: 180
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
@@ -137,41 +289,35 @@ jobs:
|
||||
PUBLIC_BUILD_VERSION: ${{ needs.meta.outputs.version }}
|
||||
PUB_DATE: ${{ needs.meta.outputs.pub_date }}
|
||||
SOURCE_SHA: ${{ needs.meta.outputs.source_sha }}
|
||||
S3_DESKTOP_PREFIX: ${{ needs.meta.outputs.s3_prefix }}
|
||||
DESKTOP_HANDOFF_PREFIX: _handoff/desktop/${{ needs.meta.outputs.build_channel }}/${{ needs.meta.outputs.version }}/${{ needs.meta.outputs.source_sha }}
|
||||
S3_ENDPOINT: https://ewr1.vultrobjects.com
|
||||
S3_BUCKET: fluxer-downloads
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
DESKTOP_PLATFORM: ${{ matrix.platform }}
|
||||
DESKTOP_ARCH: ${{ matrix.arch }}
|
||||
DESKTOP_VARIANT: ${{ matrix.desktop_variant }}
|
||||
FLUXER_MODULES: "1"
|
||||
PLATFORM: ${{ matrix.platform }}
|
||||
ARCH: ${{ matrix.arch }}
|
||||
ELECTRON_ARCH: ${{ matrix.electron_arch }}
|
||||
steps:
|
||||
- name: Checkout CI helpers
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
|
||||
with:
|
||||
ref: ${{ needs.meta.outputs.source_sha }}
|
||||
path: _ci
|
||||
|
||||
- name: Checkout source
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
|
||||
with:
|
||||
ref: ${{ needs.meta.outputs.source_sha }}
|
||||
path: source
|
||||
|
||||
- name: Set up Rust toolchain (CI helpers)
|
||||
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9
|
||||
uses: dtolnay/rust-toolchain@02cb101ec7c40f2c49e1d9714d64511d8e1b74de
|
||||
with:
|
||||
toolchain: "1.93.0"
|
||||
toolchain: "1.98.1"
|
||||
|
||||
- name: Set up Python (Windows)
|
||||
if: runner.os == 'Windows'
|
||||
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1
|
||||
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97
|
||||
with:
|
||||
python-version: "3.13"
|
||||
python-version: "3.14"
|
||||
|
||||
- name: Ensure python3 command (Windows)
|
||||
if: runner.os == 'Windows'
|
||||
@@ -196,14 +342,14 @@ jobs:
|
||||
--step set_workdir_unix
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e
|
||||
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020
|
||||
with:
|
||||
node-version: 24
|
||||
node-version: 26
|
||||
|
||||
- name: Set up pnpm via corepack
|
||||
- name: Set up pnpm
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path ${{ github.workspace }}/_ci/tools/ci/Cargo.toml -- build-desktop
|
||||
--step setup_pnpm_corepack
|
||||
--step setup_pnpm
|
||||
|
||||
- name: Resolve pnpm store path (Windows)
|
||||
if: runner.os == 'Windows'
|
||||
@@ -247,9 +393,9 @@ jobs:
|
||||
|
||||
- name: Set up Rust toolchain (Unix)
|
||||
if: matrix.platform != 'windows'
|
||||
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9
|
||||
uses: dtolnay/rust-toolchain@02cb101ec7c40f2c49e1d9714d64511d8e1b74de
|
||||
with:
|
||||
toolchain: "1.93.0"
|
||||
toolchain: "1.98.1"
|
||||
targets: ${{ matrix.platform == 'macos' && 'aarch64-apple-darwin,x86_64-apple-darwin' || (matrix.arch == 'arm64' && 'aarch64-unknown-linux-gnu' || 'x86_64-unknown-linux-gnu') }}
|
||||
|
||||
- name: Install MSVC ARM64 build tools
|
||||
@@ -260,7 +406,7 @@ jobs:
|
||||
|
||||
- name: Set up MSVC env (Windows)
|
||||
if: matrix.platform == 'windows'
|
||||
uses: TheMrMilchmann/setup-msvc-dev@79dac248aac9d0059f86eae9d8b5bfab4e95e97c
|
||||
uses: TheMrMilchmann/setup-msvc-dev@368ef7d1ee4d1171b31d4a7f67f4d954f903f5a9
|
||||
with:
|
||||
arch: ${{ matrix.arch == 'arm64' && 'amd64_arm64' || 'amd64' }}
|
||||
|
||||
@@ -292,6 +438,17 @@ jobs:
|
||||
cargo run --locked --quiet --manifest-path ${{ github.workspace }}/_ci/tools/ci/Cargo.toml -- build-desktop
|
||||
--step set_build_channel
|
||||
|
||||
- name: Download shared renderer artifact
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
|
||||
with:
|
||||
name: desktop-shared-${{ needs.meta.outputs.build_channel }}-${{ needs.meta.outputs.version }}-${{ needs.meta.outputs.source_sha }}
|
||||
path: source/desktop-shared-assets
|
||||
|
||||
- name: Restore shared renderer assets
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path ${{ github.workspace }}/_ci/tools/ci/Cargo.toml -- build-desktop
|
||||
--step restore_shared_assets
|
||||
|
||||
- name: Build Electron main process
|
||||
working-directory: ${{ env.WORKDIR }}/fluxer_desktop
|
||||
env:
|
||||
@@ -302,9 +459,9 @@ jobs:
|
||||
|
||||
- name: Set up .NET SDK (Windows)
|
||||
if: matrix.platform == 'windows'
|
||||
uses: actions/setup-dotnet@26b0ec14cb23fa6904739307f278c14f94c95bf1
|
||||
uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68
|
||||
with:
|
||||
dotnet-version: "8.0.x"
|
||||
dotnet-version: "10.0.x"
|
||||
|
||||
- name: Install Velopack CLI
|
||||
if: matrix.platform == 'windows'
|
||||
@@ -363,7 +520,7 @@ jobs:
|
||||
|
||||
- name: Azure login for Artifact Signing
|
||||
if: matrix.platform == 'windows'
|
||||
uses: azure/login@532459ea530d8321f2fb9bb10d1e0bcf23869a43
|
||||
uses: azure/login@a641126d1b8aa4d1fa005f4f92df94a3a4c4c906
|
||||
with:
|
||||
client-id: ${{ secrets.AZURE_CLIENT_ID }}
|
||||
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
|
||||
@@ -416,6 +573,16 @@ jobs:
|
||||
cargo run --locked --quiet --manifest-path ${{ github.workspace }}/_ci/tools/ci/Cargo.toml -- build-desktop
|
||||
--step verify_windows_unpacked_signatures
|
||||
|
||||
- name: Verify the packaged shell starts and boots its bundled renderer (Windows)
|
||||
if: matrix.platform == 'windows' && matrix.arch == 'x64'
|
||||
working-directory: ${{ env.WORKDIR }}/fluxer_desktop
|
||||
env:
|
||||
BUILD_CHANNEL: ${{ env.BUILD_CHANNEL }}
|
||||
BUILD_VERSION: ${{ env.VERSION }}
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path ${{ github.workspace }}/_ci/tools/ci/Cargo.toml -- build-desktop
|
||||
--step verify_bundled_renderer_windows
|
||||
|
||||
- name: Create portable ZIP (Windows)
|
||||
if: matrix.platform == 'windows'
|
||||
working-directory: ${{ env.WORKDIR }}/fluxer_desktop
|
||||
@@ -456,6 +623,16 @@ jobs:
|
||||
cargo run --locked --quiet --manifest-path ${{ github.workspace }}/_ci/tools/ci/Cargo.toml -- build-desktop
|
||||
--step build_app_linux
|
||||
|
||||
- name: Verify the packaged shell boots its bundled renderer (Linux)
|
||||
if: matrix.platform == 'linux' && matrix.arch == 'x64'
|
||||
working-directory: ${{ env.WORKDIR }}/fluxer_desktop
|
||||
env:
|
||||
BUILD_CHANNEL: ${{ env.BUILD_CHANNEL }}
|
||||
BUILD_VERSION: ${{ env.VERSION }}
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path ${{ github.workspace }}/_ci/tools/ci/Cargo.toml -- build-desktop
|
||||
--step verify_bundled_renderer_linux
|
||||
|
||||
- name: Verify signed Windows artifacts
|
||||
if: matrix.platform == 'windows'
|
||||
working-directory: ${{ env.WORKDIR }}/fluxer_desktop
|
||||
@@ -477,6 +654,12 @@ jobs:
|
||||
cargo run --locked --quiet --manifest-path ${{ github.workspace }}/_ci/tools/ci/Cargo.toml -- build-desktop
|
||||
--step prepare_artifacts_unix
|
||||
|
||||
- name: Build AppImage update feed (Linux)
|
||||
if: matrix.platform == 'linux'
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path ${{ github.workspace }}/_ci/tools/ci/Cargo.toml -- build-desktop
|
||||
--step build_appimage_update_feed
|
||||
|
||||
- name: Normalize updater YAML (macOS)
|
||||
if: matrix.platform == 'macos'
|
||||
run: >-
|
||||
@@ -495,21 +678,79 @@ jobs:
|
||||
cargo run --locked --quiet --manifest-path ${{ github.workspace }}/_ci/tools/ci/Cargo.toml -- build-desktop
|
||||
--step generate_checksums_windows
|
||||
|
||||
- name: Upload artifacts to S3 handoff
|
||||
- name: Stage build artifacts
|
||||
id: handoff
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path ${{ github.workspace }}/_ci/tools/ci/Cargo.toml -- build-desktop
|
||||
--step upload_handoff
|
||||
--step stage_handoff
|
||||
|
||||
upload:
|
||||
name: Upload to S3
|
||||
- name: Upload build artifacts
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
|
||||
with:
|
||||
name: ${{ steps.handoff.outputs.artifact_name }}
|
||||
path: upload_staging
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
compression-level: 0
|
||||
|
||||
verify_windows_arm64:
|
||||
name: Verify windows (arm64)
|
||||
if: ${{ !cancelled() && needs.build.result == 'success' }}
|
||||
needs:
|
||||
- meta
|
||||
- build
|
||||
runs-on: windows-11-arm
|
||||
timeout-minutes: 30
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
env:
|
||||
CHANNEL: ${{ needs.meta.outputs.build_channel }}
|
||||
VERSION: ${{ needs.meta.outputs.version }}
|
||||
steps:
|
||||
- name: Checkout source
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
|
||||
with:
|
||||
ref: ${{ needs.meta.outputs.source_sha }}
|
||||
sparse-checkout: fluxer_desktop/scripts
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020
|
||||
with:
|
||||
node-version: 24
|
||||
|
||||
- name: Download windows arm64 build artifacts
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
|
||||
with:
|
||||
path: artifacts
|
||||
pattern: fluxer-desktop-${{ needs.meta.outputs.build_channel }}-windows-arm64*
|
||||
|
||||
- name: Verify the packaged shell starts and boots its bundled renderer
|
||||
shell: pwsh
|
||||
run: |
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$zip = Get-ChildItem -Path artifacts -Recurse -Filter "*-$env:VERSION-portable-win-arm64.zip" | Select-Object -First 1
|
||||
if ($null -eq $zip) { Write-Host 'This build has no windows arm64 portable zip'; exit 0 }
|
||||
$app = Join-Path $env:RUNNER_TEMP 'app'
|
||||
Expand-Archive -Path $zip.FullName -DestinationPath $app
|
||||
$exe = Get-ChildItem -Path $app -Recurse -Filter 'Fluxer*.exe' | Where-Object { $_.Name -notlike '*_ExecutionStub.exe' } | Select-Object -First 1
|
||||
if ($null -eq $exe) { throw "$($zip.Name) holds no Fluxer executable" }
|
||||
node fluxer_desktop/scripts/release-check.mjs --app $exe.DirectoryName --channel $env:CHANNEL --expect-renderer $env:VERSION --expect-source bundled --package-origin http://127.0.0.1:9 --app-arg=--disable-gpu --workdir (Join-Path $env:RUNNER_TEMP 'runs') --timeout-seconds 240
|
||||
if ($LASTEXITCODE -ne 0) { throw "The windows arm64 build fails its release check" }
|
||||
|
||||
upload:
|
||||
name: Assemble desktop release assets
|
||||
if: ${{ !cancelled() && needs.build.result == 'success' && needs.verify_windows_arm64.result == 'success' }}
|
||||
needs:
|
||||
- meta
|
||||
- shared_assets
|
||||
- build
|
||||
- verify_windows_arm64
|
||||
runs-on: ubuntu-24.04-arm
|
||||
environment: desktop-releases
|
||||
timeout-minutes: 60
|
||||
timeout-minutes: 180
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
env:
|
||||
CHANNEL: ${{ needs.meta.outputs.build_channel }}
|
||||
@@ -520,32 +761,26 @@ jobs:
|
||||
BUILD_VERSION: ${{ needs.meta.outputs.version }}
|
||||
PUBLIC_BUILD_VERSION: ${{ needs.meta.outputs.version }}
|
||||
PUB_DATE: ${{ needs.meta.outputs.pub_date }}
|
||||
TEST_BUILD: ${{ needs.meta.outputs.test_build }}
|
||||
SOURCE_SHA: ${{ needs.meta.outputs.source_sha }}
|
||||
S3_DESKTOP_PREFIX: ${{ needs.meta.outputs.s3_prefix }}
|
||||
DESKTOP_HANDOFF_PREFIX: _handoff/desktop/${{ needs.meta.outputs.build_channel }}/${{ needs.meta.outputs.version }}/${{ needs.meta.outputs.source_sha }}
|
||||
S3_ENDPOINT: https://ewr1.vultrobjects.com
|
||||
S3_BUCKET: fluxer-downloads
|
||||
PUBLIC_DL_BASE: https://api.fluxer.app/dl
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
steps:
|
||||
- name: Checkout source
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
|
||||
with:
|
||||
ref: ${{ needs.meta.outputs.source_sha }}
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Rust toolchain (CI helpers)
|
||||
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9
|
||||
uses: dtolnay/rust-toolchain@02cb101ec7c40f2c49e1d9714d64511d8e1b74de
|
||||
with:
|
||||
toolchain: "1.93.0"
|
||||
toolchain: "1.98.1"
|
||||
|
||||
- name: Download S3 handoff artifacts
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- build-desktop
|
||||
--step download_handoff
|
||||
- name: Download build artifacts
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
|
||||
with:
|
||||
path: artifacts
|
||||
pattern: fluxer-desktop-${{ needs.meta.outputs.build_channel }}-*
|
||||
|
||||
- name: Build S3 payload layout (+ manifest.json)
|
||||
- name: Build payload layout (+ manifest.json)
|
||||
env:
|
||||
VERSION: ${{ needs.meta.outputs.version }}
|
||||
PUB_DATE: ${{ needs.meta.outputs.pub_date }}
|
||||
@@ -553,43 +788,85 @@ jobs:
|
||||
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- build-desktop
|
||||
--step build_payload
|
||||
|
||||
- name: Upload payload to S3
|
||||
- name: Download desktop module packages
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
|
||||
with:
|
||||
name: desktop-modules-${{ needs.meta.outputs.build_channel }}-${{ needs.meta.outputs.version }}-${{ needs.meta.outputs.source_sha }}
|
||||
path: desktop-modules
|
||||
|
||||
- name: Create token
|
||||
id: create-token
|
||||
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1
|
||||
with:
|
||||
client-id: ${{ vars.FLUXER_CI_APP_ID }}
|
||||
private-key: ${{ secrets.FLUXER_CI_APP_KEY }}
|
||||
owner: fluxerapp
|
||||
repositories: fluxer
|
||||
permission-contents: read
|
||||
- name: Check which shells run these modules
|
||||
env:
|
||||
GH_TOKEN: ${{ steps.create-token.outputs.token }}
|
||||
SHELL_CONTRACT: ${{ inputs.shell_contract }}
|
||||
DESKTOP_MODULES_ONLY_RELEASE: false
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- build-desktop
|
||||
--step upload_payload
|
||||
--step check_shell_contract
|
||||
|
||||
- name: Build desktop module manifest
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- build-desktop
|
||||
--step build_module_manifest
|
||||
|
||||
- name: Prepare GitHub release assets
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- build-desktop
|
||||
--step prepare_release_assets
|
||||
|
||||
- name: Upload GitHub release assets
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
|
||||
with:
|
||||
name: fluxer-desktop-release-assets
|
||||
path: release_assets
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
compression-level: 0
|
||||
|
||||
- name: Build summary
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- build-desktop
|
||||
--step build_summary
|
||||
|
||||
- name: Cleanup S3 handoff
|
||||
if: ${{ success() }}
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- build-desktop
|
||||
--step cleanup_handoff
|
||||
|
||||
publish_release:
|
||||
name: Publish GitHub desktop release
|
||||
if: ${{ !cancelled() && needs.upload.result == 'success' && needs.meta.outputs.test_build != 'true' }}
|
||||
if: ${{ !cancelled() && needs.upload.result == 'success' }}
|
||||
needs:
|
||||
- meta
|
||||
- upload
|
||||
runs-on: ubuntu-24.04-arm
|
||||
environment: desktop-releases
|
||||
timeout-minutes: 10
|
||||
timeout-minutes: 60
|
||||
permissions:
|
||||
contents: write
|
||||
env:
|
||||
CHANNEL: ${{ needs.meta.outputs.build_channel }}
|
||||
VERSION: ${{ needs.meta.outputs.version }}
|
||||
steps:
|
||||
- name: Checkout source
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
|
||||
with:
|
||||
ref: ${{ needs.meta.outputs.source_sha }}
|
||||
|
||||
- name: Set up Rust toolchain (CI helpers)
|
||||
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9
|
||||
uses: dtolnay/rust-toolchain@02cb101ec7c40f2c49e1d9714d64511d8e1b74de
|
||||
with:
|
||||
toolchain: "1.93.0"
|
||||
toolchain: "1.98.1"
|
||||
|
||||
- name: Download GitHub release assets
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
|
||||
with:
|
||||
name: fluxer-desktop-release-assets
|
||||
path: release_assets
|
||||
|
||||
- name: Create token
|
||||
id: create-token
|
||||
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1
|
||||
@@ -614,6 +891,7 @@ jobs:
|
||||
--build-version "${VERSION}"
|
||||
--source-sha "${SOURCE_SHA}"
|
||||
--previous-sha "${RELEASE_BASELINE_SHA}"
|
||||
--asset-dir release_assets
|
||||
)
|
||||
if [[ "${CHANNEL}" == "canary" ]]; then
|
||||
release_args+=(--prerelease)
|
||||
|
||||
@@ -33,5 +33,4 @@ jobs:
|
||||
with:
|
||||
image: fluxer-docs
|
||||
dockerfile: fluxer_docs/Dockerfile
|
||||
context: fluxer_docs
|
||||
build-version: ${{ inputs['build-version'] }}
|
||||
@@ -0,0 +1,36 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
name: build push
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
build-version:
|
||||
description: "Explicit Fluxer CalVer build version (YYYY.MDD.MICRO, UTC HHMMSS without leading zeroes) to use instead of automatic UTC clock allocation"
|
||||
type: string
|
||||
required: false
|
||||
default: ""
|
||||
|
||||
permissions:
|
||||
actions: read
|
||||
contents: write
|
||||
packages: write
|
||||
|
||||
jobs:
|
||||
approve:
|
||||
name: approve build release
|
||||
permissions: {}
|
||||
runs-on: ubuntu-24.04
|
||||
environment: builds
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- name: approved
|
||||
run: echo "Build release approved."
|
||||
|
||||
image:
|
||||
needs: approve
|
||||
uses: ./.github/workflows/_build-image.yaml
|
||||
secrets: inherit
|
||||
with:
|
||||
image: fluxer-push
|
||||
dockerfile: fluxer_push/Dockerfile
|
||||
build-version: ${{ inputs['build-version'] }}
|
||||
@@ -19,27 +19,27 @@ jobs:
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- name: Checkout fluxer
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set up Rust toolchain (CI helpers)
|
||||
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9
|
||||
uses: dtolnay/rust-toolchain@02cb101ec7c40f2c49e1d9714d64511d8e1b74de
|
||||
with:
|
||||
toolchain: "1.93.0"
|
||||
toolchain: "1.98.1"
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271
|
||||
uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413
|
||||
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e
|
||||
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020
|
||||
with:
|
||||
node-version: '24'
|
||||
node-version: '26'
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Install dependencies
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- ci
|
||||
tools/ci/run.sh ci
|
||||
--step install_dependencies
|
||||
|
||||
- name: Generate OpenAPI schemas
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
name: desktop windows release check
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
channel:
|
||||
description: Release channel
|
||||
type: choice
|
||||
options:
|
||||
- canary
|
||||
- stable
|
||||
default: canary
|
||||
version:
|
||||
description: Published version to check
|
||||
required: true
|
||||
type: string
|
||||
expect_failure:
|
||||
description: Pass only when the published build fails to start
|
||||
type: boolean
|
||||
default: false
|
||||
update_from:
|
||||
description: Comma-separated published versions to install with Setup and update to the version above from the live feed
|
||||
required: false
|
||||
type: string
|
||||
default: ""
|
||||
stale_apply_record:
|
||||
description: Before each update, leave behind an hour-old record of an update that never installed (passes only when the installed versions retry it)
|
||||
type: boolean
|
||||
default: false
|
||||
pull_request:
|
||||
paths:
|
||||
- .github/workflows/desktop-windows-release-check.yaml
|
||||
- fluxer_desktop/scripts/release-check.mjs
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: desktop-windows-release-check-${{ github.ref }}-${{ inputs.version || 'pr' }}
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
check:
|
||||
name: Check windows (${{ matrix.arch }})
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 45
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- arch: x64
|
||||
os: windows-2025
|
||||
- arch: arm64
|
||||
os: windows-11-arm
|
||||
env:
|
||||
CHANNEL: ${{ inputs.channel || 'canary' }}
|
||||
VERSION: ${{ inputs.version || '2026.1009.20411' }}
|
||||
EXPECT_FAILURE: ${{ github.event_name == 'pull_request' && 'true' || inputs.expect_failure }}
|
||||
UPDATE_FROM: ${{ inputs.update_from || '' }}
|
||||
STALE_APPLY_RECORD: ${{ inputs.stale_apply_record && 'true' || 'false' }}
|
||||
ARCH: ${{ matrix.arch }}
|
||||
steps:
|
||||
- name: Checkout source
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
|
||||
with:
|
||||
sparse-checkout: fluxer_desktop/scripts
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020
|
||||
with:
|
||||
node-version: 24
|
||||
|
||||
- name: Check the portable build
|
||||
shell: pwsh
|
||||
run: |
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$work = Join-Path $env:RUNNER_TEMP 'portable'
|
||||
New-Item -ItemType Directory -Force -Path $work | Out-Null
|
||||
$zip = Join-Path $work 'portable.zip'
|
||||
Invoke-WebRequest -Uri "https://pkgs.fluxer.com/desktop/$env:CHANNEL/win32/$env:ARCH/$env:VERSION/portable" -OutFile $zip
|
||||
Expand-Archive -Path $zip -DestinationPath (Join-Path $work 'app')
|
||||
$exe = Get-ChildItem -Path (Join-Path $work 'app') -Recurse -Filter 'Fluxer*.exe' | Where-Object { $_.Name -notlike '*_ExecutionStub.exe' } | Select-Object -First 1
|
||||
if ($null -eq $exe) { throw "The portable build holds no Fluxer executable" }
|
||||
$output = & node fluxer_desktop/scripts/release-check.mjs --app $exe.DirectoryName --channel $env:CHANNEL --expect-renderer $env:VERSION --expect-source bundled --app-arg=--disable-gpu --workdir (Join-Path $work 'runs') --timeout-seconds 240 2>&1
|
||||
$code = $LASTEXITCODE
|
||||
$output | ForEach-Object { Write-Host $_ }
|
||||
if ($env:EXPECT_FAILURE -eq 'true') {
|
||||
if ($code -eq 0) { throw "Expected $env:VERSION to fail its release check, it passed" }
|
||||
Write-Host "$env:VERSION fails its release check on windows $env:ARCH as expected"
|
||||
exit 0
|
||||
}
|
||||
if ($code -ne 0) { throw "The release check failed for $env:VERSION on windows $env:ARCH" }
|
||||
|
||||
- name: Update installed builds from the live feed
|
||||
if: env.UPDATE_FROM != ''
|
||||
shell: pwsh
|
||||
run: |
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$channelDirs = @{ canary = 'fluxer_desktop_canary'; stable = 'fluxer_desktop' }
|
||||
$dataDirs = @{ canary = 'fluxercanary'; stable = 'fluxer' }
|
||||
$installRoot = Join-Path $env:LOCALAPPDATA $channelDirs[$env:CHANNEL]
|
||||
$logPath = Join-Path (Join-Path $env:APPDATA $dataDirs[$env:CHANNEL]) 'logs\main.log'
|
||||
$failures = @()
|
||||
foreach ($from in ($env:UPDATE_FROM -split ',' | ForEach-Object { $_.Trim() } | Where-Object { $_ })) {
|
||||
Write-Host "== install $from, then update to $env:VERSION"
|
||||
Get-Process | Where-Object { $_.Path -like "$installRoot*" } | Stop-Process -Force -ErrorAction SilentlyContinue
|
||||
if (Test-Path $installRoot) { Remove-Item -Recurse -Force $installRoot }
|
||||
Remove-Item -Recurse -Force (Split-Path (Split-Path $logPath -Parent) -Parent) -ErrorAction SilentlyContinue
|
||||
$setup = Join-Path $env:RUNNER_TEMP "setup-$from.exe"
|
||||
Invoke-WebRequest -Uri "https://pkgs.fluxer.com/desktop/$env:CHANNEL/win32/$env:ARCH/$from/setup" -OutFile $setup
|
||||
Start-Process -FilePath $setup -ArgumentList '--silent' -Wait
|
||||
Start-Sleep -Seconds 5
|
||||
Get-Process | Where-Object { $_.Path -like "$installRoot*" } | Stop-Process -Force -ErrorAction SilentlyContinue
|
||||
$exe = Get-ChildItem -Path (Join-Path $installRoot 'current') -Filter 'Fluxer*.exe' | Where-Object { $_.Name -notlike '*_ExecutionStub.exe' } | Select-Object -First 1
|
||||
if ($null -eq $exe) { $failures += "$from did not install"; continue }
|
||||
if ($env:STALE_APPLY_RECORD -eq 'true') {
|
||||
$dataRoot = Split-Path (Split-Path $logPath -Parent) -Parent
|
||||
New-Item -ItemType Directory -Force -Path $dataRoot | Out-Null
|
||||
$attemptedAt = [DateTimeOffset]::UtcNow.AddHours(-1).ToUnixTimeMilliseconds()
|
||||
Set-Content -Path (Join-Path $dataRoot 'update-apply-state.json') -Value "{`"version`":`"$env:VERSION`",`"attemptedAt`":$attemptedAt}" -NoNewline
|
||||
Write-Host "left a stale apply record for $env:VERSION"
|
||||
}
|
||||
Start-Process -FilePath $exe.FullName -ArgumentList '--disable-gpu'
|
||||
$deadline = (Get-Date).AddMinutes(8)
|
||||
$reported = $null
|
||||
while ((Get-Date) -lt $deadline) {
|
||||
Start-Sleep -Seconds 10
|
||||
if (Test-Path $logPath) {
|
||||
$line = Select-String -Path $logPath -Pattern "The renderer reported its build: .*Desktop $([regex]::Escape($env:VERSION)), Web $([regex]::Escape($env:VERSION))" | Select-Object -Last 1
|
||||
if ($null -ne $line) { $reported = $line.Line; break }
|
||||
}
|
||||
}
|
||||
$installed = Get-Content (Join-Path $installRoot 'current\sq.version') -Raw -ErrorAction SilentlyContinue
|
||||
Write-Host "installed package after update: $installed"
|
||||
$logs = Join-Path $env:RUNNER_TEMP "logs\$from"
|
||||
New-Item -ItemType Directory -Force -Path $logs | Out-Null
|
||||
if (Test-Path $logPath) { Copy-Item $logPath $logs }
|
||||
Get-ChildItem -Path $installRoot -Filter '*.log' -ErrorAction SilentlyContinue | Copy-Item -Destination $logs
|
||||
if (Test-Path $logPath) { Get-Content $logPath | Select-String -Pattern 'Bootstrap|ShellSelfUpdate|Velopack|velopack|NativeModulePreflight|reported its build' | Select-Object -Last 40 | ForEach-Object { Write-Host $_.Line } }
|
||||
if ($null -eq $reported) { $failures += "$from did not reach Desktop and Web $env:VERSION" } else { Write-Host "$from updated: $reported" }
|
||||
Get-Process | Where-Object { $_.Path -like "$installRoot*" } | Stop-Process -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
if ($failures.Count -gt 0) { throw ($failures -join "`n") }
|
||||
|
||||
- name: Upload update logs
|
||||
if: always() && env.UPDATE_FROM != ''
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
|
||||
with:
|
||||
name: update-logs-${{ matrix.arch }}
|
||||
path: ${{ runner.temp }}/logs
|
||||
if-no-files-found: ignore
|
||||
retention-days: 7
|
||||
@@ -1,230 +0,0 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
name: Dispatch private marketing build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- fluxer_marketing
|
||||
- Cargo.toml
|
||||
- fluxer_common/**
|
||||
- packages/fonts/manifest.json
|
||||
- packages/fonts/NOTICE.md
|
||||
- packages/fonts/LICENSE-IBM-PLEX.txt
|
||||
- packages/fonts/css/locale-fallbacks.css
|
||||
- packages/fonts/files/FluxerSans/**
|
||||
- packages/fonts/files/FluxerMono/**
|
||||
- packages/fonts/marketing/**
|
||||
- packages/i18n/marketing/**
|
||||
- fluxer_static/marketing/branding/**
|
||||
- .github/workflows/dispatch-private-marketing-build.yaml
|
||||
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: private-marketing-dispatch
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
metadata:
|
||||
name: resolve exact private build metadata
|
||||
if: github.repository == 'fluxerapp/fluxer'
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 5
|
||||
outputs:
|
||||
parent_sha: ${{ steps.inputs.outputs.parent_sha }}
|
||||
gitlink_sha: ${{ steps.inputs.outputs.gitlink_sha }}
|
||||
build_version: ${{ steps.inputs.outputs.build_version }}
|
||||
correlation_id: ${{ steps.inputs.outputs.correlation_id }}
|
||||
steps:
|
||||
- name: Create token
|
||||
id: create-token
|
||||
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1
|
||||
with:
|
||||
client-id: ${{ vars.FLUXER_CI_APP_ID }}
|
||||
private-key: ${{ secrets.FLUXER_CI_APP_KEY }}
|
||||
owner: fluxerapp
|
||||
repositories: fluxer
|
||||
permission-contents: read
|
||||
- name: Resolve trusted build inputs
|
||||
id: inputs
|
||||
env:
|
||||
EVENT_AFTER: ${{ github.event.after }}
|
||||
GH_TOKEN: ${{ steps.create-token.outputs.token }}
|
||||
PARENT_SHA: ${{ github.sha }}
|
||||
PUBLIC_REPOSITORY: ${{ github.repository }}
|
||||
RUN_ID: ${{ github.run_id }}
|
||||
RUN_ATTEMPT: ${{ github.run_attempt }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
[[ "$GITHUB_EVENT_NAME" == "push" ]]
|
||||
[[ "$GITHUB_REF" == "refs/heads/main" ]]
|
||||
[[ "$PUBLIC_REPOSITORY" == "fluxerapp/fluxer" ]]
|
||||
[[ "$PARENT_SHA" =~ ^[0-9a-f]{40}$ ]]
|
||||
[[ "$EVENT_AFTER" == "$PARENT_SHA" ]]
|
||||
[[ "$RUN_ID" =~ ^[1-9][0-9]*$ ]]
|
||||
[[ "$RUN_ATTEMPT" =~ ^[1-9][0-9]*$ ]]
|
||||
(( 10#$RUN_ATTEMPT <= 10 ))
|
||||
|
||||
main_sha="$(gh api "repos/$PUBLIC_REPOSITORY/git/ref/heads/main" --jq .object.sha)"
|
||||
[[ "$main_sha" =~ ^[0-9a-f]{40}$ ]]
|
||||
main_comparison="$(gh api "repos/$PUBLIC_REPOSITORY/compare/$PARENT_SHA...$main_sha")"
|
||||
main_status="$(jq -r .status <<<"$main_comparison")"
|
||||
[[ "$main_status" == "identical" || "$main_status" == "ahead" ]]
|
||||
[[ "$(jq -r .merge_base_commit.sha <<<"$main_comparison")" == "$PARENT_SHA" ]]
|
||||
|
||||
commit="$(gh api "repos/$PUBLIC_REPOSITORY/git/commits/$PARENT_SHA")"
|
||||
[[ "$(jq -r .sha <<<"$commit")" == "$PARENT_SHA" ]]
|
||||
tree_sha="$(jq -r .tree.sha <<<"$commit")"
|
||||
[[ "$tree_sha" =~ ^[0-9a-f]{40}$ ]]
|
||||
entry="$(
|
||||
gh api "repos/$PUBLIC_REPOSITORY/git/trees/$tree_sha" |
|
||||
jq -cer '[.tree[] | select(.path == "fluxer_marketing")] | if length == 1 then .[0] else error("expected exactly one marketing gitlink") end'
|
||||
)"
|
||||
mode="$(jq -r .mode <<<"$entry")"
|
||||
type="$(jq -r .type <<<"$entry")"
|
||||
gitlink_sha="$(jq -r .sha <<<"$entry")"
|
||||
path="$(jq -r .path <<<"$entry")"
|
||||
if [[ "$mode" != "160000" || "$type" != "commit" || "$path" != "fluxer_marketing" || ! "$gitlink_sha" =~ ^[0-9a-f]{40}$ ]]; then
|
||||
echo "::error::Public parent does not contain a valid fluxer_marketing gitlink."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
run="$(gh api "repos/$PUBLIC_REPOSITORY/actions/runs/$RUN_ID")"
|
||||
[[ "$(jq -r .id <<<"$run")" == "$RUN_ID" ]]
|
||||
[[ "$(jq -r .run_attempt <<<"$run")" == "$RUN_ATTEMPT" ]]
|
||||
[[ "$(jq -r .event <<<"$run")" == "push" ]]
|
||||
[[ "$(jq -r .head_sha <<<"$run")" == "$PARENT_SHA" ]]
|
||||
run_created_at="$(jq -r .created_at <<<"$run")"
|
||||
[[ "$run_created_at" =~ ^[1-9][0-9]{3}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$ ]]
|
||||
run_created_epoch="$(date -u -d "$run_created_at" +%s)"
|
||||
[[ "$run_created_epoch" =~ ^[1-9][0-9]*$ ]]
|
||||
build_epoch=$((run_created_epoch + 10#$RUN_ATTEMPT - 1))
|
||||
read -r year month day time_segment <<<"$(date -u -d "@$build_epoch" '+%Y %m %d %H%M%S')"
|
||||
month="$((10#$month))"
|
||||
micro="$((10#$time_segment))"
|
||||
build_version="$year.$month$day.$micro"
|
||||
[[ "$build_version" =~ ^[1-9][0-9]{3}\.[1-9][0-9]{2,3}\.([0-9]|[1-9][0-9]{0,5})$ ]]
|
||||
correlation_id="public-${RUN_ID}-${RUN_ATTEMPT}"
|
||||
[[ "$correlation_id" =~ ^[A-Za-z0-9._:-]{1,64}$ ]]
|
||||
{
|
||||
echo "parent_sha=$PARENT_SHA"
|
||||
echo "gitlink_sha=$gitlink_sha"
|
||||
echo "build_version=$build_version"
|
||||
echo "correlation_id=$correlation_id"
|
||||
} >>"$GITHUB_OUTPUT"
|
||||
|
||||
dispatch:
|
||||
name: dispatch exact private build
|
||||
needs: metadata
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 65
|
||||
environment: private-marketing-dispatch
|
||||
permissions: {}
|
||||
steps:
|
||||
- name: Validate trusted build inputs
|
||||
env:
|
||||
DISPATCH_ENABLED: ${{ vars.MARKETING_DISPATCH_ENABLED }}
|
||||
EXPECTED_PARENT_SHA: ${{ github.sha }}
|
||||
EXPECTED_CORRELATION_ID: public-${{ github.run_id }}-${{ github.run_attempt }}
|
||||
PARENT_SHA: ${{ needs.metadata.outputs.parent_sha }}
|
||||
GITLINK_SHA: ${{ needs.metadata.outputs.gitlink_sha }}
|
||||
BUILD_VERSION: ${{ needs.metadata.outputs.build_version }}
|
||||
CORRELATION_ID: ${{ needs.metadata.outputs.correlation_id }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
[[ "$GITHUB_EVENT_NAME" == "push" ]]
|
||||
[[ "$GITHUB_REF" == "refs/heads/main" ]]
|
||||
[[ "$GITHUB_REPOSITORY" == "fluxerapp/fluxer" ]]
|
||||
[[ "$PARENT_SHA" == "$EXPECTED_PARENT_SHA" ]]
|
||||
[[ "$PARENT_SHA" =~ ^[0-9a-f]{40}$ ]]
|
||||
[[ "$GITLINK_SHA" =~ ^[0-9a-f]{40}$ ]]
|
||||
[[ "$BUILD_VERSION" =~ ^[1-9][0-9]{3}\.[1-9][0-9]{2,3}\.([0-9]|[1-9][0-9]{0,5})$ ]]
|
||||
[[ "$CORRELATION_ID" == "$EXPECTED_CORRELATION_ID" ]]
|
||||
[[ "$CORRELATION_ID" =~ ^[A-Za-z0-9._:-]{1,64}$ ]]
|
||||
if [[ "$DISPATCH_ENABLED" != "true" ]]; then
|
||||
echo "::error::Private marketing dispatch is intentionally disabled until the package cutover guard completes."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Create private dispatch token
|
||||
id: private-token
|
||||
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1
|
||||
with:
|
||||
client-id: ${{ vars.FLUXER_CI_APP_ID }}
|
||||
private-key: ${{ secrets.FLUXER_CI_APP_KEY }}
|
||||
owner: fluxerapp
|
||||
repositories: marketing
|
||||
permission-actions: write
|
||||
|
||||
- name: Dispatch exact private build
|
||||
env:
|
||||
GH_TOKEN: ${{ steps.private-token.outputs.token }}
|
||||
PARENT_SHA: ${{ needs.metadata.outputs.parent_sha }}
|
||||
GITLINK_SHA: ${{ needs.metadata.outputs.gitlink_sha }}
|
||||
BUILD_VERSION: ${{ needs.metadata.outputs.build_version }}
|
||||
CORRELATION_ID: ${{ needs.metadata.outputs.correlation_id }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
gh api --method POST repos/fluxerapp/marketing/actions/workflows/build-marketing.yaml/dispatches \
|
||||
--field ref=main \
|
||||
--field "inputs[parent_sha]=$PARENT_SHA" \
|
||||
--field "inputs[gitlink_sha]=$GITLINK_SHA" \
|
||||
--field "inputs[build_version]=$BUILD_VERSION" \
|
||||
--field "inputs[correlation_id]=$CORRELATION_ID"
|
||||
|
||||
- name: Wait for private build conclusion
|
||||
env:
|
||||
GH_TOKEN: ${{ steps.private-token.outputs.token }}
|
||||
PARENT_SHA: ${{ needs.metadata.outputs.parent_sha }}
|
||||
GITLINK_SHA: ${{ needs.metadata.outputs.gitlink_sha }}
|
||||
BUILD_VERSION: ${{ needs.metadata.outputs.build_version }}
|
||||
CORRELATION_ID: ${{ needs.metadata.outputs.correlation_id }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
expected_title="marketing-build correlation=$CORRELATION_ID parent=$PARENT_SHA gitlink=$GITLINK_SHA version=$BUILD_VERSION"
|
||||
deadline=$((SECONDS + 3600))
|
||||
run_id=""
|
||||
while (( SECONDS < deadline )); do
|
||||
runs="$(gh api "repos/fluxerapp/marketing/actions/workflows/build-marketing.yaml/runs?event=workflow_dispatch&per_page=100" --jq '[.workflow_runs[] | {id, event, display_title, status, conclusion}]')"
|
||||
matches="$(jq --arg title "$expected_title" '[.[] | select(.event == "workflow_dispatch" and .display_title == $title)]' <<<"$runs")"
|
||||
count="$(jq 'length' <<<"$matches")"
|
||||
if [[ "$count" == "1" ]]; then
|
||||
run_id="$(jq -r '.[0].id' <<<"$matches")"
|
||||
break
|
||||
fi
|
||||
if [[ "$count" != "0" ]]; then
|
||||
echo "::error::Private build correlation matched multiple workflow runs."
|
||||
exit 1
|
||||
fi
|
||||
sleep 10
|
||||
done
|
||||
if [[ -z "$run_id" ]]; then
|
||||
echo "::error::Timed out waiting for the private build dispatch to appear."
|
||||
exit 1
|
||||
fi
|
||||
while (( SECONDS < deadline )); do
|
||||
runs="$(gh api "repos/fluxerapp/marketing/actions/workflows/build-marketing.yaml/runs?event=workflow_dispatch&per_page=100" --jq '[.workflow_runs[] | {id, event, display_title, status, conclusion}]')"
|
||||
matches="$(jq --arg title "$expected_title" '[.[] | select(.event == "workflow_dispatch" and .display_title == $title)]' <<<"$runs")"
|
||||
if [[ "$(jq 'length' <<<"$matches")" != "1" || "$(jq -r '.[0].id' <<<"$matches")" != "$run_id" ]]; then
|
||||
echo "::error::Private build correlation is missing or ambiguous."
|
||||
exit 1
|
||||
fi
|
||||
run="$(jq '.[0]' <<<"$matches")"
|
||||
status="$(jq -r '.status' <<<"$run")"
|
||||
conclusion="$(jq -r '.conclusion // empty' <<<"$run")"
|
||||
if [[ "$status" == "completed" ]]; then
|
||||
if [[ "$conclusion" != "success" ]]; then
|
||||
echo "::error::Private marketing build concluded with $conclusion."
|
||||
exit 1
|
||||
fi
|
||||
echo "Private marketing build completed successfully."
|
||||
exit 0
|
||||
fi
|
||||
sleep 15
|
||||
done
|
||||
echo "::error::Timed out waiting for the private marketing build."
|
||||
exit 1
|
||||
@@ -0,0 +1,183 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
name: Helm chart
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- deploy/helm/**
|
||||
- deploy/self-hosting/Caddyfile
|
||||
- .github/workflows/helm.yaml
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- deploy/helm/**
|
||||
- deploy/self-hosting/Caddyfile
|
||||
- .github/workflows/helm.yaml
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
render:
|
||||
name: Lint and render with Helm ${{ matrix.helm }}
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 15
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- helm: v3.19.0
|
||||
sha256: a7f81ce08007091b86d8bd696eb4d86b8d0f2e1b9f6c714be62f82f96a594496
|
||||
- helm: v4.2.4
|
||||
sha256: c306b46f719b0a4da32d0f78ee21bf90ce8d602f15b22ab753f0674d1670a7f3
|
||||
env:
|
||||
CHART: deploy/helm/fluxer
|
||||
KUBECONFORM_VERSION: v0.7.0
|
||||
KUBECONFORM_SHA256: c31518ddd122663b3f3aa874cfe8178cb0988de944f29c74a0b9260920d115d3
|
||||
CRD_CATALOG: https://raw.githubusercontent.com/datreeio/CRDs-catalog/63669a570e231d4f1f8396d229a1de512bcf0a34/{{.Group}}/{{.ResourceKind}}_{{.ResourceAPIVersion}}.json
|
||||
steps:
|
||||
- name: Checkout fluxer
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Install Helm and kubeconform
|
||||
env:
|
||||
HELM_VERSION: ${{ matrix.helm }}
|
||||
HELM_SHA256: ${{ matrix.sha256 }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mkdir -p "$RUNNER_TEMP/bin"
|
||||
cd "$RUNNER_TEMP"
|
||||
curl -fsSLo helm.tgz "https://get.helm.sh/helm-${HELM_VERSION}-linux-amd64.tar.gz"
|
||||
echo "${HELM_SHA256} helm.tgz" | sha256sum -c -
|
||||
tar -xzf helm.tgz linux-amd64/helm
|
||||
mv linux-amd64/helm bin/helm
|
||||
curl -fsSLo kubeconform.tgz "https://github.com/yannh/kubeconform/releases/download/${KUBECONFORM_VERSION}/kubeconform-linux-amd64.tar.gz"
|
||||
echo "${KUBECONFORM_SHA256} kubeconform.tgz" | sha256sum -c -
|
||||
tar -xzf kubeconform.tgz kubeconform
|
||||
mv kubeconform bin/kubeconform
|
||||
echo "$RUNNER_TEMP/bin" >> "$GITHUB_PATH"
|
||||
|
||||
- name: Lint, render and validate every CI values file
|
||||
run: |
|
||||
set -euo pipefail
|
||||
command -v helm kubeconform python3
|
||||
python3 -c 'import yaml'
|
||||
helm version --short
|
||||
shopt -s nullglob
|
||||
files=("$CHART"/ci/*.yaml)
|
||||
if [ "${#files[@]}" -eq 0 ]; then
|
||||
echo "::error::no values files under $CHART/ci"
|
||||
exit 1
|
||||
fi
|
||||
for values in "${files[@]}"; do
|
||||
echo "::group::$values"
|
||||
helm lint --strict "$CHART" -f "$values"
|
||||
helm template fluxer "$CHART" -n fluxer -f "$values" \
|
||||
--api-versions cert-manager.io/v1 --api-versions gateway.networking.k8s.io/v1 > rendered.yaml
|
||||
kubeconform -strict -summary -kubernetes-version 1.29.0 \
|
||||
-schema-location default -schema-location "$CRD_CATALOG" rendered.yaml
|
||||
if grep -qi 'example\.com' rendered.yaml; then
|
||||
echo "::error::$values renders example.com"
|
||||
exit 1
|
||||
fi
|
||||
if grep -Eqi 'change_?me' rendered.yaml; then
|
||||
echo "::error::$values renders a CHANGE_ME placeholder"
|
||||
exit 1
|
||||
fi
|
||||
echo "::endgroup::"
|
||||
done
|
||||
|
||||
- name: Check the guards
|
||||
run: |
|
||||
set -euo pipefail
|
||||
expect_failure() {
|
||||
local message=$1
|
||||
shift
|
||||
if output=$(helm template fluxer "$CHART" "$@" 2>&1); then
|
||||
echo "::error::rendered with $*"
|
||||
exit 1
|
||||
fi
|
||||
if ! grep -qF "$message" <<<"$output"; then
|
||||
echo "::error::expected \"$message\" for $*, got: $output"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
d=domain=chat.example.test
|
||||
expect_failure "domain must be set"
|
||||
expect_failure "is a placeholder" --set $d --set secrets.values.FLUXER_SUDO_MODE_SECRET=CHANGE_ME
|
||||
expect_failure "is a placeholder" --set $d --set-string 'secrets.extra.FLUXER_STRIPE_SECRET_KEY=<change-me>'
|
||||
expect_failure "at least 32 characters" --set $d --set secrets.values.FLUXER_GATEWAY_RPC_AUTH_TOKEN=short
|
||||
expect_failure "letters and digits only" --set $d --set-string 'secrets.values.FLUXER_VALKEY_PASSWORD=0123456789abcdef0123456789abcd:@'
|
||||
expect_failure "worker.replicas must be 1" --set $d --set worker.replicas=2
|
||||
expect_failure "at least 32 bytes" --set $d --set secrets.values.FLUXER_MEDIA_PROXY_UPLOAD_RELAY_SECRET_BASE64=c2hvcnQ=
|
||||
expect_failure "set postgres.external.host" --set $d --set postgres.enabled=false
|
||||
expect_failure "set together" --set $d --set secrets.values.FLUXER_VAPID_PUBLIC_KEY=abc
|
||||
expect_failure "is a secret and would be stored in plain text" --set $d --set env.FLUXER_EMAIL_SMTP_PASSWORD=not-a-real-password
|
||||
expect_failure "is a secret and would be stored in plain text" --set $d --set api.env.FLUXER_STRIPE_SECRET_KEY=not-a-real-key
|
||||
expect_failure "holds a password" --set $d --set-string 'env.FLUXER_SEARCH_URL=https://user:[email protected]'
|
||||
expect_failure "Set livekit.nodeCIDRs" --set $d --set networkPolicy.ingressNamespaceSelector.matchLabels.name=ingress
|
||||
expect_failure "set livekit.external.publicUrl" --set $d --set livekit.enabled=false --set livekit.external.url=http://livekit.voice.svc:7880
|
||||
expect_failure "reserve a public address" --set $d --set livekit.expose=loadBalancer
|
||||
|
||||
- name: Check that a chart version bump restarts nothing
|
||||
run: |
|
||||
set -euo pipefail
|
||||
cp -R "$CHART" "$RUNNER_TEMP/bumped"
|
||||
sed -e 's/^version: .*/version: 99.0.0/' -e 's/^appVersion: .*/appVersion: "bumped"/' "$CHART/Chart.yaml" > "$RUNNER_TEMP/bumped/Chart.yaml"
|
||||
helm template fluxer "$CHART" -n fluxer -f "$CHART/ci/existing-secret-values.yaml" > before.yaml
|
||||
helm template fluxer "$RUNNER_TEMP/bumped" -n fluxer -f "$CHART/ci/existing-secret-values.yaml" > after.yaml
|
||||
python3 - before.yaml after.yaml <<'PY'
|
||||
import sys, yaml
|
||||
def pods(path):
|
||||
out = {}
|
||||
for doc in yaml.safe_load_all(open(path)):
|
||||
if doc and doc.get('kind') in ('Deployment', 'StatefulSet'):
|
||||
spec = doc['spec']
|
||||
out[f"{doc['kind']}/{doc['metadata']['name']}"] = (spec['template'], spec['selector'], spec.get('volumeClaimTemplates'))
|
||||
return out
|
||||
before, after = pods(sys.argv[1]), pods(sys.argv[2])
|
||||
if len(before) < 20:
|
||||
sys.exit(f'only {len(before)} workloads rendered')
|
||||
changed = sorted(name for name in before.keys() | after.keys() if before.get(name) != after.get(name))
|
||||
if changed:
|
||||
sys.exit('a chart version bump changes the pod template of: ' + ', '.join(changed))
|
||||
print(f'{len(before)} workloads keep their pod template across a chart version bump')
|
||||
PY
|
||||
|
||||
- name: Check the default resource requests
|
||||
run: |
|
||||
set -euo pipefail
|
||||
helm template fluxer "$CHART" -n fluxer -f "$CHART/ci/default-values.yaml" > rendered.yaml
|
||||
python3 - rendered.yaml <<'PY'
|
||||
import sys, yaml
|
||||
def cpu(v):
|
||||
v = str(v)
|
||||
return float(v[:-1]) if v.endswith('m') else float(v) * 1000
|
||||
units = {'Ki': 2**10, 'Mi': 2**20, 'Gi': 2**30}
|
||||
def mem(v):
|
||||
v = str(v)
|
||||
for unit, factor in units.items():
|
||||
if v.endswith(unit):
|
||||
return float(v[:-len(unit)]) * factor
|
||||
return float(v)
|
||||
total_cpu = total_mem = 0
|
||||
for doc in yaml.safe_load_all(open(sys.argv[1])):
|
||||
if not doc or doc.get('kind') not in ('Deployment', 'StatefulSet'):
|
||||
continue
|
||||
replicas = doc['spec'].get('replicas', 1)
|
||||
for container in doc['spec']['template']['spec']['containers']:
|
||||
requests = (container.get('resources') or {}).get('requests') or {}
|
||||
if 'cpu' not in requests or 'memory' not in requests:
|
||||
sys.exit(f"{doc['kind']}/{doc['metadata']['name']} has a container without cpu and memory requests")
|
||||
total_cpu += replicas * cpu(requests['cpu'])
|
||||
total_mem += replicas * mem(requests['memory'])
|
||||
print(f"requests: {total_cpu:.0f}m cpu, {total_mem / 2**30:.2f}Gi memory")
|
||||
if total_cpu > 1200 or total_mem > 4.5 * 2**30:
|
||||
sys.exit('the default install requests more than 1200m cpu or 4.5Gi memory')
|
||||
PY
|
||||
@@ -35,32 +35,34 @@ jobs:
|
||||
permission-pull-requests: write
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
|
||||
with:
|
||||
token: ${{ steps.create-token.outputs.token }}
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set up Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9
|
||||
uses: dtolnay/rust-toolchain@02cb101ec7c40f2c49e1d9714d64511d8e1b74de
|
||||
with:
|
||||
toolchain: "1.93.0"
|
||||
toolchain: "1.98.1"
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271
|
||||
uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413
|
||||
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e
|
||||
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020
|
||||
with:
|
||||
node-version: "24"
|
||||
node-version: "26"
|
||||
cache: "pnpm"
|
||||
|
||||
- name: Install dependencies
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- ci
|
||||
tools/ci/run.sh ci
|
||||
--step install_dependencies
|
||||
|
||||
- name: Refresh source catalogs
|
||||
env:
|
||||
OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
|
||||
run: pnpm i18n:source-sync
|
||||
|
||||
- name: Format generated catalogs
|
||||
|
||||
@@ -40,7 +40,7 @@ jobs:
|
||||
permission-pull-requests: write
|
||||
|
||||
- name: Checkout Weblate branch
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
|
||||
with:
|
||||
token: ${{ steps.create-token.outputs.token }}
|
||||
ref: ${{ env.WEBLATE_BRANCH }}
|
||||
@@ -48,26 +48,26 @@ jobs:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set up Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9
|
||||
uses: dtolnay/rust-toolchain@02cb101ec7c40f2c49e1d9714d64511d8e1b74de
|
||||
with:
|
||||
toolchain: "1.93.0"
|
||||
toolchain: "1.98.1"
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271
|
||||
uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413
|
||||
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e
|
||||
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020
|
||||
with:
|
||||
node-version: "24"
|
||||
node-version: "26"
|
||||
cache: "pnpm"
|
||||
|
||||
- name: Install dependencies
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- ci
|
||||
tools/ci/run.sh ci
|
||||
--step install_dependencies
|
||||
|
||||
- name: Compile translated catalogs
|
||||
run: pnpm i18n:weblate-compile
|
||||
run: pnpm i18n:compile
|
||||
|
||||
- name: Format generated catalogs
|
||||
run: pnpm biome format --write package.json packages/i18n/package.json packages/i18n/scripts/SyncStaticI18nCatalogs.ts packages/errors/src/i18n fluxer_api/pkgs/email/src/email_i18n fluxer_api/src/api/content_i18n
|
||||
@@ -77,14 +77,14 @@ jobs:
|
||||
GH_TOKEN: ${{ steps.create-token.outputs.token }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
if [[ -z "$(git status --porcelain -- fluxer_app/src/features/i18n/locales packages/i18n/marketing packages/errors/src/i18n fluxer_api/pkgs/email/src/email_i18n fluxer_api/src/api/content_i18n)" ]]; then
|
||||
if [[ -z "$(git status --porcelain -- fluxer_app/src/features/i18n/locales packages/errors/src/i18n fluxer_api/pkgs/email/src/email_i18n fluxer_api/src/api/content_i18n)" ]]; then
|
||||
echo "No generated catalog changes."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
git config user.name "fluxer-ci[bot]"
|
||||
git config user.email "${{ vars.FLUXER_CI_APP_USER_ID }}+fluxer-ci[bot]@users.noreply.github.com"
|
||||
git add fluxer_app/src/features/i18n/locales packages/i18n/marketing packages/errors/src/i18n fluxer_api/pkgs/email/src/email_i18n fluxer_api/src/api/content_i18n
|
||||
git add fluxer_app/src/features/i18n/locales packages/errors/src/i18n fluxer_api/pkgs/email/src/email_i18n fluxer_api/src/api/content_i18n
|
||||
git commit -m "i18n: compile Weblate catalogs"
|
||||
git remote set-url origin "https://x-access-token:${GH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git"
|
||||
git push origin "HEAD:$WEBLATE_BRANCH"
|
||||
|
||||
@@ -19,7 +19,7 @@ jobs:
|
||||
permission-pull-requests: write
|
||||
|
||||
- name: Label pull request
|
||||
uses: actions/labeler@f27b608878404679385c85cfa523b85ccb86e213
|
||||
uses: actions/labeler@bf12e9b00b37c5c0ca2b87b79b2daf7891dbda13
|
||||
with:
|
||||
repo-token: ${{ steps.create-token.outputs.token }}
|
||||
configuration-path: .github/labeller.yaml
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
name: release image set
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
build-version:
|
||||
description: "Explicit Fluxer CalVer build version (YYYY.MDD.MICRO, UTC HHMMSS without leading zeroes) to use instead of automatic UTC clock allocation"
|
||||
type: string
|
||||
required: false
|
||||
default: ""
|
||||
from-tag:
|
||||
description: "Image tag every component is read from (v1 snapshots today's moving tags, a CalVer pins a coordinated build)"
|
||||
type: string
|
||||
required: false
|
||||
default: "v1"
|
||||
component-versions:
|
||||
description: "Per-component overrides, one <image>=<version> entry per line (for example fluxer-api=2026.830.191141)"
|
||||
type: string
|
||||
required: false
|
||||
default: ""
|
||||
|
||||
permissions:
|
||||
actions: read
|
||||
contents: write
|
||||
packages: read
|
||||
|
||||
concurrency:
|
||||
group: release-image-set
|
||||
cancel-in-progress: false
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
env:
|
||||
GHCR_OWNER: ${{ github.repository_owner }}
|
||||
|
||||
jobs:
|
||||
approve:
|
||||
name: approve image set release
|
||||
permissions: {}
|
||||
runs-on: ubuntu-24.04
|
||||
environment: builds
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- name: approved
|
||||
run: echo "Image set release approved."
|
||||
|
||||
manifest:
|
||||
name: resolve and publish the image set
|
||||
needs: approve
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 20
|
||||
permissions:
|
||||
contents: write
|
||||
packages: read
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
|
||||
env:
|
||||
GIT_CONFIG_GLOBAL: ${{ runner.temp }}/gitconfig
|
||||
- name: Set up Rust toolchain (CI helpers)
|
||||
uses: dtolnay/rust-toolchain@02cb101ec7c40f2c49e1d9714d64511d8e1b74de
|
||||
with:
|
||||
toolchain: "1.98.1"
|
||||
- uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069
|
||||
- uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ github.token }}
|
||||
- name: Create token
|
||||
id: create-token
|
||||
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1
|
||||
with:
|
||||
client-id: ${{ vars.FLUXER_CI_APP_ID }}
|
||||
private-key: ${{ secrets.FLUXER_CI_APP_KEY }}
|
||||
owner: fluxerapp
|
||||
repositories: fluxer
|
||||
permission-contents: write
|
||||
permission-packages: read
|
||||
|
||||
- name: set variables
|
||||
id: vars
|
||||
env:
|
||||
GH_TOKEN: ${{ steps.create-token.outputs.token }}
|
||||
FLUXER_BUILD_VERSION: ${{ inputs['build-version'] }}
|
||||
run: >-
|
||||
tools/ci/run.sh resolve-calver
|
||||
--github-output
|
||||
|
||||
- name: resolve release image set
|
||||
id: resolve
|
||||
env:
|
||||
GH_TOKEN: ${{ steps.create-token.outputs.token }}
|
||||
VERSION: ${{ steps.vars.outputs.build_version }}
|
||||
FROM_TAG: ${{ inputs['from-tag'] }}
|
||||
COMPONENT_VERSIONS: ${{ inputs['component-versions'] }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
args=(
|
||||
image-set resolve
|
||||
--version "${VERSION}"
|
||||
--registry "ghcr.io/${GHCR_OWNER}"
|
||||
--from-tag "${FROM_TAG}"
|
||||
--out-dir release-out
|
||||
--github-output
|
||||
)
|
||||
while IFS= read -r entry; do
|
||||
entry="$(echo "$entry" | xargs)"
|
||||
if [ -n "$entry" ]; then
|
||||
args+=( --component-version "$entry" )
|
||||
fi
|
||||
done <<< "${COMPONENT_VERSIONS}"
|
||||
tools/ci/run.sh "${args[@]}"
|
||||
|
||||
- name: verify release image set
|
||||
env:
|
||||
VERSION: ${{ steps.vars.outputs.build_version }}
|
||||
run: >-
|
||||
tools/ci/run.sh image-set verify
|
||||
--manifest "release-out/fluxer-release-${VERSION}.json"
|
||||
|
||||
- name: Publish GitHub release
|
||||
env:
|
||||
GH_TOKEN: ${{ steps.create-token.outputs.token }}
|
||||
VERSION: ${{ steps.vars.outputs.build_version }}
|
||||
BUNDLE_COMMIT: ${{ steps.resolve.outputs.bundle_commit }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
if [ -z "${BUNDLE_COMMIT}" ]; then
|
||||
echo "image-set resolve reported no bundle commit" >&2
|
||||
exit 1
|
||||
fi
|
||||
gh release create "fluxer-release@${VERSION}" \
|
||||
--repo fluxerapp/fluxer \
|
||||
--target "${BUNDLE_COMMIT}" \
|
||||
--title "fluxer-release ${VERSION}" \
|
||||
--latest=true \
|
||||
--notes "Immutable image set for ${VERSION}. Every image in the set contains ${BUNDLE_COMMIT}, the commit this tag points at, so the bundle here is never newer than the images. Pin with: docker compose -f docker-compose.yml -f fluxer-release-${VERSION}.yml up -d" \
|
||||
"release-out/fluxer-release-${VERSION}.json" \
|
||||
"release-out/fluxer-release-${VERSION}.yml"
|
||||
+280
-227
@@ -3,102 +3,129 @@ name: Tests
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
|
||||
cancel-in-progress: true
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
|
||||
|
||||
env:
|
||||
GHCR_REGISTRY: ghcr.io/${{ github.repository_owner }}
|
||||
CARGO_PROFILE_DEV_DEBUG: none
|
||||
CARGO_PROFILE_TEST_DEBUG: none
|
||||
CARGO_INCREMENTAL: '0'
|
||||
|
||||
jobs:
|
||||
typecheck:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 25
|
||||
env:
|
||||
FLUXER_CI_BIN: ${{ github.workspace }}/target/debug/fluxer-ci
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
|
||||
|
||||
- name: Set up Rust toolchain (CI helpers)
|
||||
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9
|
||||
uses: dtolnay/rust-toolchain@02cb101ec7c40f2c49e1d9714d64511d8e1b74de
|
||||
with:
|
||||
toolchain: "1.93.0"
|
||||
toolchain: "1.98.1"
|
||||
targets: wasm32-unknown-unknown
|
||||
|
||||
- name: Set up ci helper
|
||||
uses: ./.github/actions/ci-helper
|
||||
with:
|
||||
save: 'true'
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271
|
||||
uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413
|
||||
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e
|
||||
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020
|
||||
with:
|
||||
node-version: '24'
|
||||
node-version: '26'
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Install dependencies
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- ci
|
||||
--step install_dependencies
|
||||
run: |
|
||||
"$FLUXER_CI_BIN" ci --step install_dependencies
|
||||
|
||||
- name: Run typecheck
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- ci
|
||||
--step typecheck
|
||||
run: |
|
||||
"$FLUXER_CI_BIN" ci --step typecheck
|
||||
|
||||
test:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 25
|
||||
env:
|
||||
FLUXER_CI_BIN: ${{ github.workspace }}/target/debug/fluxer-ci
|
||||
PNPM_TEST_WORKSPACE_CONCURRENCY: '2'
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
|
||||
|
||||
- name: Set up Rust toolchain (CI helpers)
|
||||
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9
|
||||
uses: dtolnay/rust-toolchain@02cb101ec7c40f2c49e1d9714d64511d8e1b74de
|
||||
with:
|
||||
toolchain: "1.93.0"
|
||||
toolchain: "1.98.1"
|
||||
targets: wasm32-unknown-unknown
|
||||
|
||||
- name: Set up ci helper
|
||||
uses: ./.github/actions/ci-helper
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271
|
||||
uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413
|
||||
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e
|
||||
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020
|
||||
with:
|
||||
node-version: '24'
|
||||
node-version: '26'
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Install dependencies
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- ci
|
||||
--step install_dependencies
|
||||
run: |
|
||||
"$FLUXER_CI_BIN" ci --step install_dependencies
|
||||
|
||||
- name: Restore fluxer_app wasm artifacts
|
||||
id: app-wasm
|
||||
uses: ./.github/actions/app-wasm-cache
|
||||
with:
|
||||
mode: restore
|
||||
|
||||
- name: Run tests
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- ci
|
||||
--step test
|
||||
run: |
|
||||
"$FLUXER_CI_BIN" ci --step test
|
||||
|
||||
- name: Save fluxer_app wasm artifacts
|
||||
if: always() && github.ref == 'refs/heads/main' && steps.app-wasm.outputs.cache-hit != 'true'
|
||||
uses: ./.github/actions/app-wasm-cache
|
||||
with:
|
||||
mode: save
|
||||
|
||||
rust:
|
||||
runs-on: blacksmith-4vcpu-ubuntu-2404
|
||||
timeout-minutes: 30
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9
|
||||
uses: dtolnay/rust-toolchain@02cb101ec7c40f2c49e1d9714d64511d8e1b74de
|
||||
with:
|
||||
toolchain: stable
|
||||
toolchain: "1.98.1"
|
||||
components: clippy, rustfmt
|
||||
targets: x86_64-pc-windows-msvc
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271
|
||||
uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413
|
||||
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e
|
||||
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020
|
||||
with:
|
||||
node-version: '24'
|
||||
node-version: '26'
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Cache cargo
|
||||
@@ -108,21 +135,64 @@ jobs:
|
||||
~/.cargo/registry
|
||||
~/.cargo/git
|
||||
target
|
||||
key: rust-${{ runner.os }}-${{ hashFiles('Cargo.lock') }}
|
||||
key: rust-${{ runner.os }}-${{ hashFiles('fluxer_media_proxy/tools/install-native-deps.sh') }}-${{ hashFiles('Cargo.lock') }}
|
||||
restore-keys: |
|
||||
rust-${{ runner.os }}-
|
||||
rust-${{ runner.os }}-${{ hashFiles('fluxer_media_proxy/tools/install-native-deps.sh') }}-
|
||||
|
||||
- name: Install cargo-deny
|
||||
run: cargo install cargo-deny --version 0.20.2 --locked
|
||||
|
||||
- name: Check Rust dependencies
|
||||
run: cargo deny --locked check -D warnings
|
||||
|
||||
- name: Check libfluxwebp dependencies
|
||||
run: cargo deny --manifest-path fluxer_app/rust/libfluxwebp/Cargo.toml --config deny.toml --locked check licenses bans sources
|
||||
|
||||
- name: Check desktop native dependencies
|
||||
run: tools/ci/check-desktop-native-workspaces.sh dependencies
|
||||
|
||||
- name: Cache native media dependencies
|
||||
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9
|
||||
with:
|
||||
path: /opt/fluxer-native
|
||||
key: media-native-${{ runner.os }}-${{ hashFiles('fluxer_media_proxy/tools/install-native-deps.sh') }}
|
||||
|
||||
- name: Install native dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y --no-install-recommends \
|
||||
pkg-config \
|
||||
build-essential \
|
||||
libcurl4-openssl-dev \
|
||||
libvips-dev \
|
||||
binutils \
|
||||
clang \
|
||||
cmake \
|
||||
curl \
|
||||
libaom-dev \
|
||||
libavfilter-dev \
|
||||
libclang-dev \
|
||||
libcurl4-openssl-dev \
|
||||
libdav1d-dev \
|
||||
libde265-dev \
|
||||
libfido2-dev \
|
||||
libheif-dev \
|
||||
libwebp-dev
|
||||
liblcms2-dev \
|
||||
libpipewire-0.3-dev \
|
||||
libspa-0.2-dev \
|
||||
libssl-dev \
|
||||
libudev-dev \
|
||||
libvips-dev \
|
||||
libwebp-dev \
|
||||
libyuv-dev \
|
||||
meson \
|
||||
nasm \
|
||||
ninja-build \
|
||||
pkg-config \
|
||||
xz-utils \
|
||||
yasm \
|
||||
zlib1g-dev
|
||||
sudo fluxer_media_proxy/tools/install-native-deps.sh /opt/fluxer-native
|
||||
echo "PKG_CONFIG_PATH=/opt/fluxer-native/lib/pkgconfig:/opt/fluxer-native/lib64/pkgconfig" >> "$GITHUB_ENV"
|
||||
echo "LD_LIBRARY_PATH=/opt/fluxer-native/lib:/opt/fluxer-native/lib64" >> "$GITHUB_ENV"
|
||||
echo "/opt/fluxer-native/bin" >> "$GITHUB_PATH"
|
||||
|
||||
- name: Install Node.js dependencies
|
||||
run: pnpm --filter fluxer_admin install
|
||||
@@ -130,278 +200,261 @@ jobs:
|
||||
- name: Check formatting
|
||||
run: cargo fmt --all -- --check
|
||||
|
||||
- name: Check formatting (libfluxwebp)
|
||||
run: cargo fmt --manifest-path fluxer_app/rust/libfluxwebp/Cargo.toml -- --check
|
||||
|
||||
- name: Check formatting (desktop native workspaces)
|
||||
run: tools/ci/check-desktop-native-workspaces.sh fmt
|
||||
|
||||
- name: Clippy (warnings as errors)
|
||||
run: cargo clippy --workspace -- -D warnings
|
||||
run: cargo clippy --workspace --all-targets --all-features --locked -- -D warnings
|
||||
|
||||
- name: Clippy (desktop native workspaces on Linux and Windows backends, warnings as errors)
|
||||
run: tools/ci/check-desktop-native-workspaces.sh clippy
|
||||
|
||||
- name: Verify the source-built ffmpeg CLI is on PATH
|
||||
run: |
|
||||
set -euo pipefail
|
||||
command -v ffmpeg
|
||||
test "$(command -v ffmpeg)" = /opt/fluxer-native/bin/ffmpeg
|
||||
ffmpeg -hide_banner -version
|
||||
|
||||
- name: Run tests
|
||||
run: cargo test --workspace
|
||||
env:
|
||||
FLUXER_REQUIRE_MEDIA_FIXTURES: "1"
|
||||
run: cargo test --workspace --all-features --locked
|
||||
|
||||
- name: Run tests (libfluxcore)
|
||||
run: cargo test --locked --manifest-path fluxer_app/rust/libfluxcore/Cargo.toml
|
||||
|
||||
- name: Run desktop native workspace tests on Linux
|
||||
run: tools/ci/check-desktop-native-workspaces.sh test
|
||||
|
||||
gateway:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 25
|
||||
env:
|
||||
FLUXER_CI_BIN: ${{ github.workspace }}/target/debug/fluxer-ci
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
|
||||
|
||||
- name: Set up Rust toolchain (CI helpers)
|
||||
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9
|
||||
uses: dtolnay/rust-toolchain@02cb101ec7c40f2c49e1d9714d64511d8e1b74de
|
||||
with:
|
||||
toolchain: "1.93.0"
|
||||
toolchain: "1.98.1"
|
||||
|
||||
- name: Cache cargo (gateway NIFs)
|
||||
uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6
|
||||
with:
|
||||
workspaces: |
|
||||
fluxer_gateway/native/guild_member_list_oset_nif -> target
|
||||
fluxer_gateway/native/push_markdown_plaintext_nif -> target
|
||||
save-if: ${{ github.ref == 'refs/heads/main' }}
|
||||
|
||||
- name: Set up ci helper
|
||||
uses: ./.github/actions/ci-helper
|
||||
|
||||
- name: Set up Erlang
|
||||
uses: erlef/setup-beam@54075bcc5e249e4758d363f27d099f55d843f124
|
||||
with:
|
||||
otp-version: '28'
|
||||
rebar3-version: '3.24.0'
|
||||
rebar3-version: '3.27.0'
|
||||
|
||||
- name: Cache rebar3 dependencies
|
||||
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9
|
||||
- name: Restore rebar3 dependencies
|
||||
id: rebar3-cache
|
||||
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9
|
||||
with:
|
||||
path: |
|
||||
fluxer_gateway/_build
|
||||
~/.cache/rebar3
|
||||
key: rebar3-${{ runner.os }}-${{ hashFiles('fluxer_gateway/rebar.lock') }}
|
||||
fluxer_gateway/_build
|
||||
!fluxer_gateway/_build/default/lib/fluxer_gateway/**
|
||||
!fluxer_gateway/_build/test/lib/fluxer_gateway/**
|
||||
key: >-
|
||||
rebar3-${{ runner.os }}-otp28-rebar3.27.0-${{ hashFiles('fluxer_gateway/rebar.lock',
|
||||
'fluxer_gateway/rebar.config') }}
|
||||
restore-keys: |
|
||||
rebar3-${{ runner.os }}-
|
||||
rebar3-${{ runner.os }}-otp28-rebar3.27.0-
|
||||
|
||||
- name: Drop restored gateway build output
|
||||
run: rm -rf fluxer_gateway/_build/default/lib/fluxer_gateway fluxer_gateway/_build/test/lib/fluxer_gateway
|
||||
|
||||
- name: Check formatting
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- ci
|
||||
--step gateway_fmt
|
||||
run: |
|
||||
"$FLUXER_CI_BIN" ci --step gateway_fmt
|
||||
|
||||
- name: Compile
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- ci
|
||||
--step gateway_compile
|
||||
run: |
|
||||
"$FLUXER_CI_BIN" ci --step gateway_compile
|
||||
|
||||
- name: Run dialyzer
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- ci
|
||||
--step gateway_dialyzer
|
||||
run: |
|
||||
"$FLUXER_CI_BIN" ci --step gateway_dialyzer
|
||||
|
||||
- name: Run eunit tests
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- ci
|
||||
--step gateway_eunit
|
||||
run: |
|
||||
"$FLUXER_CI_BIN" ci --step gateway_eunit
|
||||
|
||||
- name: Save rebar3 dependencies
|
||||
if: always() && github.ref == 'refs/heads/main' && steps.rebar3-cache.outputs.cache-hit != 'true'
|
||||
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9
|
||||
with:
|
||||
path: |
|
||||
~/.cache/rebar3
|
||||
fluxer_gateway/_build
|
||||
!fluxer_gateway/_build/default/lib/fluxer_gateway/**
|
||||
!fluxer_gateway/_build/test/lib/fluxer_gateway/**
|
||||
key: >-
|
||||
rebar3-${{ runner.os }}-otp28-rebar3.27.0-${{ hashFiles('fluxer_gateway/rebar.lock',
|
||||
'fluxer_gateway/rebar.config') }}
|
||||
|
||||
knip:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 25
|
||||
env:
|
||||
FLUXER_CI_BIN: ${{ github.workspace }}/target/debug/fluxer-ci
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
|
||||
|
||||
- name: Set up Rust toolchain (CI helpers)
|
||||
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9
|
||||
uses: dtolnay/rust-toolchain@02cb101ec7c40f2c49e1d9714d64511d8e1b74de
|
||||
with:
|
||||
toolchain: "1.93.0"
|
||||
toolchain: "1.98.1"
|
||||
targets: wasm32-unknown-unknown
|
||||
|
||||
- name: Set up ci helper
|
||||
uses: ./.github/actions/ci-helper
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271
|
||||
uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413
|
||||
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e
|
||||
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020
|
||||
with:
|
||||
node-version: '24'
|
||||
node-version: '26'
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Install dependencies
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- ci
|
||||
--step install_dependencies
|
||||
run: |
|
||||
"$FLUXER_CI_BIN" ci --step install_dependencies
|
||||
|
||||
- name: Restore fluxer_app wasm artifacts
|
||||
id: app-wasm
|
||||
uses: ./.github/actions/app-wasm-cache
|
||||
with:
|
||||
mode: restore
|
||||
|
||||
- name: Run knip
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- ci
|
||||
--step knip
|
||||
run: |
|
||||
"$FLUXER_CI_BIN" ci --step knip
|
||||
|
||||
- name: Save fluxer_app wasm artifacts
|
||||
if: always() && github.ref == 'refs/heads/main' && steps.app-wasm.outputs.cache-hit != 'true'
|
||||
uses: ./.github/actions/app-wasm-cache
|
||||
with:
|
||||
mode: save
|
||||
|
||||
lint:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413
|
||||
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020
|
||||
with:
|
||||
node-version: '26'
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Check formatting and lint
|
||||
run: pnpm exec biome ci .
|
||||
|
||||
- name: Lint JSX for browser-translation safety
|
||||
run: pnpm exec eslint . --max-warnings 0
|
||||
|
||||
- name: Check data-flx attributes
|
||||
run: pnpm --filter fluxer_app theming:data-flx:check
|
||||
|
||||
i18n:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 25
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
|
||||
|
||||
- name: Set up Rust toolchain (CI helpers)
|
||||
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9
|
||||
with:
|
||||
toolchain: "1.93.0"
|
||||
targets: wasm32-unknown-unknown
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271
|
||||
uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413
|
||||
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e
|
||||
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020
|
||||
with:
|
||||
node-version: '24'
|
||||
node-version: '26'
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Install dependencies
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- ci
|
||||
--step install_dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Compile locale catalogs
|
||||
run: pnpm i18n:compile
|
||||
|
||||
- name: Check drift of compiled locale modules
|
||||
- name: Check drift of synced catalogs
|
||||
run: |
|
||||
if ! git diff --exit-code -- \
|
||||
packages/errors/src/i18n/locales \
|
||||
packages/errors/src/i18n/ErrorI18nTypes.generated.ts \
|
||||
fluxer_api/pkgs/email/src/email_i18n/locales \
|
||||
packages/errors/src/i18n/weblate \
|
||||
fluxer_api/pkgs/email/src/email_i18n/weblate \
|
||||
fluxer_api/pkgs/email/src/email_i18n/EmailI18nTypes.generated.ts \
|
||||
fluxer_api/src/api/content_i18n/locales; then
|
||||
echo "::error::Compiled locale modules are outdated. Run 'pnpm i18n:compile' and commit the result. Translations belong in the weblate/ catalogs, not in the generated locales/ modules."
|
||||
fluxer_api/src/api/content_i18n/weblate; then
|
||||
echo "::error::Static catalogs are out of sync with their sources. Run 'pnpm i18n:compile' and commit the result."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
docs:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413
|
||||
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020
|
||||
with:
|
||||
node-version: '26'
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile --filter fluxer_docs...
|
||||
|
||||
- name: Verify documentation matches the live API
|
||||
run: pnpm --filter fluxer_docs verify
|
||||
|
||||
- name: Build documentation
|
||||
run: pnpm --filter fluxer_docs build
|
||||
|
||||
fonts:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1
|
||||
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97
|
||||
with:
|
||||
python-version: "3.13"
|
||||
python-version: "3.14"
|
||||
|
||||
- name: Install font tooling
|
||||
run: python3 -m pip install -r tools/fonts/requirements.txt
|
||||
|
||||
- name: Verify shipped fonts match the lockfile
|
||||
run: python3 tools/fonts/build_fonts.py --verify
|
||||
|
||||
ci-scripts:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 25
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9
|
||||
with:
|
||||
toolchain: stable
|
||||
components: rustfmt
|
||||
|
||||
- name: Sync ci helper dependencies
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- ci-scripts
|
||||
--step sync
|
||||
|
||||
- name: Run ci helper tests
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- ci-scripts
|
||||
--step test
|
||||
|
||||
helm-and-scripts:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
|
||||
|
||||
- name: Set up Rust toolchain (CI helpers)
|
||||
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9
|
||||
with:
|
||||
toolchain: "1.93.0"
|
||||
|
||||
- name: Install helm
|
||||
uses: azure/setup-helm@9bc31f4ebc9c6b171d7bfbaa5d006ae7abdb4310
|
||||
|
||||
- name: Resolve Helm test build version
|
||||
run: >-
|
||||
cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- resolve-calver
|
||||
--github-env
|
||||
--env-name HELM_TEST_BUILD_VERSION
|
||||
|
||||
- name: Helm dependency update (all charts)
|
||||
run: |
|
||||
set -euo pipefail
|
||||
for chart_dir in deploy/helm/*/; do
|
||||
if [[ -f "${chart_dir}Chart.yaml" ]]; then
|
||||
helm dependency update "$chart_dir"
|
||||
fi
|
||||
done
|
||||
|
||||
- name: Helm lint (all charts)
|
||||
run: |
|
||||
set -euo pipefail
|
||||
FAILED=0
|
||||
for chart_dir in deploy/helm/*/; do
|
||||
if [[ -f "${chart_dir}Chart.yaml" ]]; then
|
||||
echo "--- Linting ${chart_dir} ---"
|
||||
VALUES_ARGS=()
|
||||
if [[ -f "${chart_dir}values.yaml" ]]; then
|
||||
VALUES_ARGS=(-f "${chart_dir}values.yaml")
|
||||
fi
|
||||
EXTRA_SETS=(--set-string "global.registry=${GHCR_REGISTRY}")
|
||||
case "${chart_dir}" in
|
||||
*gateway*)
|
||||
EXTRA_SETS+=(--set-string "gateway.tag=${HELM_TEST_BUILD_VERSION}" --set-string "gateway.build.version=${HELM_TEST_BUILD_VERSION}")
|
||||
;;
|
||||
*api*)
|
||||
EXTRA_SETS+=(--set-string app.name=api --set-string "app.tag=${HELM_TEST_BUILD_VERSION}" --set-string app.config=stable --set-string "app.build.version=${HELM_TEST_BUILD_VERSION}")
|
||||
;;
|
||||
*app-proxy*)
|
||||
EXTRA_SETS+=(--set-string app.name=app-proxy --set-string "app.tag=${HELM_TEST_BUILD_VERSION}" --set-string app.config=stable --set-string "app.build.version=${HELM_TEST_BUILD_VERSION}")
|
||||
;;
|
||||
*admin*)
|
||||
EXTRA_SETS+=(--set-string app.name=admin --set-string "app.tag=${HELM_TEST_BUILD_VERSION}" --set-string app.config=stable --set-string "app.build.version=${HELM_TEST_BUILD_VERSION}")
|
||||
;;
|
||||
*marketing*)
|
||||
EXTRA_SETS+=(--set-string app.name=marketing --set-string "app.tag=${HELM_TEST_BUILD_VERSION}" --set-string app.config=stable --set-string "app.build.version=${HELM_TEST_BUILD_VERSION}")
|
||||
;;
|
||||
*docs*)
|
||||
EXTRA_SETS+=(--set-string app.name=docs --set-string "app.tag=${HELM_TEST_BUILD_VERSION}" --set-string app.config=stable --set-string "app.build.version=${HELM_TEST_BUILD_VERSION}")
|
||||
;;
|
||||
*media-proxy*)
|
||||
EXTRA_SETS+=(--set-string "mediaProxy.tag=${HELM_TEST_BUILD_VERSION}" --set-string "staticProxy.tag=${HELM_TEST_BUILD_VERSION}" --set-string "mediaProxy.build.version=${HELM_TEST_BUILD_VERSION}" --set-string "staticProxy.build.version=${HELM_TEST_BUILD_VERSION}")
|
||||
;;
|
||||
*uploads*)
|
||||
EXTRA_SETS+=(--set-string app.name=uploads --set-string "app.tag=${HELM_TEST_BUILD_VERSION}" --set-string app.config=stable --set-string "app.build.version=${HELM_TEST_BUILD_VERSION}")
|
||||
;;
|
||||
*worker*)
|
||||
EXTRA_SETS+=(--set-string "workerRealtime.tag=${HELM_TEST_BUILD_VERSION}" --set-string "workerUnfurl.tag=${HELM_TEST_BUILD_VERSION}" --set-string "workerLifecycle.tag=${HELM_TEST_BUILD_VERSION}" --set-string "workerBatch.tag=${HELM_TEST_BUILD_VERSION}" --set-string "workerRealtime.build.version=${HELM_TEST_BUILD_VERSION}" --set-string "workerUnfurl.build.version=${HELM_TEST_BUILD_VERSION}" --set-string "workerLifecycle.build.version=${HELM_TEST_BUILD_VERSION}" --set-string "workerBatch.build.version=${HELM_TEST_BUILD_VERSION}")
|
||||
;;
|
||||
*gifs*|*messages*|*snowflakes*|*unfurl*|*users*)
|
||||
EXTRA_SETS+=(--set-string "svc.tag=${HELM_TEST_BUILD_VERSION}" --set-string "svc.build.version=${HELM_TEST_BUILD_VERSION}" --set-string svc.build.channel=stable)
|
||||
;;
|
||||
esac
|
||||
if ! helm lint "$chart_dir" "${VALUES_ARGS[@]}" "${EXTRA_SETS[@]}" --strict; then
|
||||
FAILED=1
|
||||
fi
|
||||
fi
|
||||
done
|
||||
if [[ "$FAILED" -ne 0 ]]; then
|
||||
echo "::error::One or more Helm charts failed linting"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Helm template (gateway)
|
||||
run: |
|
||||
set -euo pipefail
|
||||
helm template fluxer-gateway deploy/helm/gateway \
|
||||
-f deploy/helm/gateway/values.yaml \
|
||||
--set-string "global.registry=${GHCR_REGISTRY}" \
|
||||
--set-string "gateway.tag=${HELM_TEST_BUILD_VERSION}" \
|
||||
--set-string "gateway.build.version=${HELM_TEST_BUILD_VERSION}" \
|
||||
-n fluxer > /dev/null
|
||||
echo "Gateway chart templates render successfully."
|
||||
|
||||
- name: Validate gateway manifests with kubeconform
|
||||
run: |
|
||||
set -euo pipefail
|
||||
helm template fluxer-gateway deploy/helm/gateway \
|
||||
-f deploy/helm/gateway/values.yaml \
|
||||
--set-string "global.registry=${GHCR_REGISTRY}" \
|
||||
--set-string "gateway.tag=${HELM_TEST_BUILD_VERSION}" \
|
||||
--set-string "gateway.build.version=${HELM_TEST_BUILD_VERSION}" \
|
||||
-n fluxer \
|
||||
| docker run -i --rm ghcr.io/yannh/kubeconform:v0.6.7 \
|
||||
-strict -summary -kubernetes-version 1.31.0
|
||||
+9
-7
@@ -10,6 +10,7 @@
|
||||
/.direnv/
|
||||
/.fluxer/
|
||||
/.pnpm-store/
|
||||
/.vscode/
|
||||
|
||||
**/*.css.d.ts
|
||||
**/*.tsbuildinfo
|
||||
@@ -25,28 +26,29 @@
|
||||
|
||||
/fluxer_app/.devserver-cache.json
|
||||
/fluxer_app/pkgs/libfluxcore/
|
||||
/fluxer_app/pkgs/libfluxwebp/
|
||||
/fluxer_app/src/features/i18n/locales/*/messages.mjs
|
||||
**/auto-i18n-reviewed-unchanged.json.lock
|
||||
**/weblate/locales/auto-i18n-reviewed-unchanged.json
|
||||
/fluxer_app/src/features/messaging/utils/markdown/parser/MarkdownParserWasmBytes.ts
|
||||
/fluxer_app/src/features/theme/styles/generated/
|
||||
/fluxer_app/src/features/ui/components/SVGMasks.tsx
|
||||
/fluxer_app/src/features/ui/constants/AvatarStatusGeometry.ts
|
||||
/fluxer_gateway/priv/
|
||||
/fluxer_static/desktop/spellcheck/dictionaries/*/*
|
||||
!/fluxer_static/desktop/spellcheck/dictionaries/[email protected]/LICENSE
|
||||
!/fluxer_static/desktop/spellcheck/dictionaries/[email protected]/LICENSE
|
||||
|
||||
/fluxer_desktop/native/rust/fuzz/artifacts/
|
||||
/fluxer_desktop/native/rust/fuzz/corpus/
|
||||
/packages/markdown_parser/rust/fuzz/artifacts/
|
||||
/packages/markdown_parser/rust/fuzz/corpus/
|
||||
|
||||
/fluxer_media_proxy/.benchmark-cache/
|
||||
/fluxer_media_proxy/bench-results/
|
||||
|
||||
/app-dist-output/
|
||||
/artifacts/
|
||||
/desktop-shared-assets/
|
||||
/desktop-modules/
|
||||
/s3_payload/
|
||||
/upload_staging/
|
||||
|
||||
/deploy/helm/**/Chart.lock
|
||||
/deploy/helm/**/charts/
|
||||
|
||||
**/.idea/
|
||||
**/*.iml
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
[submodule "fluxer_marketing"]
|
||||
path = fluxer_marketing
|
||||
url = https://github.com/fluxerapp/marketing.git
|
||||
update = none
|
||||
Generated
+905
-1357
File diff suppressed because it is too large.
Load diff
+6
-2
@@ -7,9 +7,9 @@ members = [
|
||||
"fluxer_gifs",
|
||||
"fluxer_svc",
|
||||
"fluxer_messages",
|
||||
"fluxer_push",
|
||||
"fluxer_snowflakes",
|
||||
"tools/ci",
|
||||
"tools/content/update-frozen-snapshot",
|
||||
"tools/dev",
|
||||
"tools/i18n_auto",
|
||||
"fluxer_users",
|
||||
@@ -17,7 +17,6 @@ members = [
|
||||
"packages/markdown_parser/rust",
|
||||
]
|
||||
exclude = [
|
||||
"fluxer_marketing",
|
||||
"packages/markdown_parser/rust/fuzz",
|
||||
]
|
||||
resolver = "2"
|
||||
@@ -25,3 +24,8 @@ resolver = "2"
|
||||
[workspace.package]
|
||||
edition = "2024"
|
||||
license = "AGPL-3.0-or-later"
|
||||
|
||||
[profile.release]
|
||||
lto = "fat"
|
||||
codegen-units = 1
|
||||
strip = "symbols"
|
||||
@@ -1,15 +1,3 @@
|
||||
> [!CAUTION]
|
||||
> As of this writing (15 June 2026), we are working to finalise the API and self-hosting documentation over the next few days.
|
||||
>
|
||||
> We apologise for the brief delay in open-source releases. We paused after spam waves created safety concerns while we built out Fluxer's trust and safety infrastructure. During that same stretch, we have been fixing hundreds of bugs, adding new features, and preparing a much improved audio and video system.
|
||||
>
|
||||
> You can already try that work in the Fluxer Canary client: [download Canary](https://canary.fluxer.app/download) or [open Canary on the web](https://web.canary.fluxer.app). The latest stable client remains out of date for now, but over the coming weeks we are finalising the remaining work needed to stabilise the current latest code out in the open.
|
||||
|
||||
> [!NOTE]
|
||||
> Learn about the developer behind Fluxer, the goals of the project, the tech stack, and what's coming next.
|
||||
>
|
||||
> [Read the launch blog post](https://blog.fluxer.app/how-i-built-fluxer-a-discord-like-chat-app/) | [View full roadmap](https://blog.fluxer.app/roadmap-2026/)
|
||||
|
||||
<p align="center">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="./fluxer_static/marketing/branding/logo-white.svg">
|
||||
@@ -18,18 +6,175 @@
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://fluxer.app/donate">
|
||||
<img src="https://img.shields.io/badge/Donate-fluxer.app%2Fdonate-brightgreen" alt="Donate" /></a>
|
||||
<a href="https://fluxer.app/download">
|
||||
<img src="https://img.shields.io/badge/Download-fluxer.app-4641D9" alt="Download" /></a>
|
||||
<a href="https://docs.fluxer.app">
|
||||
<img src="https://img.shields.io/badge/Docs-docs.fluxer.app-blue" alt="Documentation" /></a>
|
||||
<a href="https://fluxer.app/donate">
|
||||
<img src="https://img.shields.io/badge/Donate-fluxer.app%2Fdonate-brightgreen" alt="Donate" /></a>
|
||||
<a href="./LICENSE">
|
||||
<img src="https://img.shields.io/badge/License-AGPLv3-purple" alt="AGPLv3 License" /></a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://flathub.org/apps/app.fluxer.Fluxer">
|
||||
<img src="https://dl.flathub.org/assets/badges/flathub-badge-en.svg" alt="Get it on Flathub" height="60" /></a>
|
||||
</p>
|
||||
|
||||
# Fluxer
|
||||
|
||||
> [!IMPORTANT]
|
||||
> Bug reports and feature requests have moved to [feedback.fluxer.com](https://feedback.fluxer.com). Sign in with your Fluxer account to post, vote and follow updates. GitHub Issues and Discussions are closed. Report security vulnerabilities privately through [fluxer.app/security](https://fluxer.app/security).
|
||||
|
||||
Fluxer is a free and open source instant messaging and VoIP chat app built for friends, groups, and communities.
|
||||
|
||||
<p align="center">
|
||||
<img src="./fluxer_static/marketing/screenshots/desktop-readme-1920w.png" alt="Fluxer app showcase" width="900">
|
||||
<img src="https://fluxer.app/static/img/screenshots-desktop-readme-1920w.70cb6ce340007e0a.png" alt="Fluxer running side by side on a desktop monitor and a phone" width="640">
|
||||
</p>
|
||||
|
||||
## Download
|
||||
|
||||
| Windows | macOS | Linux | Android | iOS |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| [Installer (x64)][win-setup-x64] | [Disk image][mac-dmg] | [Flathub][flathub] | [Google Play (beta)][android-play] | [TestFlight][ios-testflight] |
|
||||
| [Installer (ARM64)][win-setup-arm64] | | [deb (x64)][linux-deb-x64] | [APK (beta)][android-apk] | |
|
||||
| [Portable (x64)][win-portable-x64] | | [deb (ARM64)][linux-deb-arm64] | [Obtainium (beta)][obtainium] | |
|
||||
| [Portable (ARM64)][win-portable-arm64] | | [rpm (x64)][linux-rpm-x64] | | |
|
||||
| | | [rpm (ARM64)][linux-rpm-arm64] | | |
|
||||
| | | [AppImage (x64)][linux-appimage-x64] | | |
|
||||
| | | [AppImage (ARM64)][linux-appimage-arm64] | | |
|
||||
| | | [tar.gz (x64)][linux-targz-x64] | | |
|
||||
| | | [tar.gz (ARM64)][linux-targz-arm64] | | |
|
||||
|
||||
The macOS disk image runs on both Apple silicon and Intel. Windows and Linux need the build matching your processor.
|
||||
|
||||
On Linux, prefer a repository over a single file so Fluxer updates with the rest of your system.
|
||||
|
||||
## Linux package repositories
|
||||
|
||||
The package is `fluxer` for stable and `fluxer-canary` for canary. apt and dnf subscribe to one channel per entry file. pacman and Flatpak serve both from one repository.
|
||||
|
||||
### Flatpak
|
||||
|
||||
Stable is on [Flathub][flathub], the easiest route on most desktops:
|
||||
|
||||
```sh
|
||||
flatpak install flathub app.fluxer.Fluxer
|
||||
```
|
||||
|
||||
Flathub has stable only. To use Fluxer's own repository, open [the stable][flatpak-ref] or [the canary][flatpak-canary-ref] reference file and your software manager takes over. Some desktops also accept `flatpak+https://pkgs.fluxer.com/flatpak/fluxer.flatpakref` in the address bar.
|
||||
|
||||
From a terminal:
|
||||
|
||||
```sh
|
||||
flatpak install https://pkgs.fluxer.com/flatpak/fluxer.flatpakref
|
||||
```
|
||||
|
||||
### Debian and Ubuntu
|
||||
|
||||
```sh
|
||||
sudo install -d -m 0755 /etc/apt/keyrings
|
||||
sudo curl -fsSL -o /etc/apt/keyrings/fluxer-archive-keyring.gpg https://pkgs.fluxer.com/keys/fluxer-archive-keyring.gpg
|
||||
sudo curl -fsSL -o /etc/apt/sources.list.d/fluxer.sources https://pkgs.fluxer.com/deb/fluxer.sources
|
||||
sudo apt update && sudo apt install fluxer
|
||||
```
|
||||
|
||||
For canary, use the canary entry file and package.
|
||||
|
||||
```sh
|
||||
sudo curl -fsSL -o /etc/apt/sources.list.d/fluxer-canary.sources https://pkgs.fluxer.com/deb/fluxer-canary.sources
|
||||
sudo apt update && sudo apt install fluxer-canary
|
||||
```
|
||||
|
||||
A `.deb` installed from a download only updates once its channel's entry is added.
|
||||
|
||||
### Fedora and RHEL
|
||||
|
||||
```sh
|
||||
sudo curl -fsSL -o /etc/yum.repos.d/fluxer.repo https://pkgs.fluxer.com/rpm/fluxer.repo
|
||||
sudo dnf install fluxer
|
||||
```
|
||||
|
||||
For canary, use the canary entry file and package.
|
||||
|
||||
```sh
|
||||
sudo curl -fsSL -o /etc/yum.repos.d/fluxer-canary.repo https://pkgs.fluxer.com/rpm/fluxer-canary.repo
|
||||
sudo dnf install fluxer-canary
|
||||
```
|
||||
|
||||
RHEL, Rocky, Alma and CentOS Stream need `sudo dnf install epel-release` first, because their base repositories lack `libXScrnSaver`. Fedora does not.
|
||||
|
||||
### Arch Linux
|
||||
|
||||
The repository is signed, so pacman needs the key once:
|
||||
|
||||
```sh
|
||||
sudo pacman-key --init
|
||||
curl -fsSL -o /tmp/fluxer-archive-keyring.asc https://pkgs.fluxer.com/keys/fluxer-archive-keyring.asc
|
||||
sudo pacman-key --add /tmp/fluxer-archive-keyring.asc
|
||||
sudo pacman-key --lsign-key 09D01339EE128925F75E675C855C5BDE34D205D2
|
||||
```
|
||||
|
||||
`--lsign-key` is what makes pacman trust it. Then add the repository:
|
||||
|
||||
```sh
|
||||
sudo tee -a /etc/pacman.conf >/dev/null <<'REPO'
|
||||
|
||||
[fluxer]
|
||||
SigLevel = Required TrustedOnly
|
||||
Server = https://pkgs.fluxer.com/arch/$repo/os/$arch
|
||||
REPO
|
||||
sudo pacman -Syu fluxer
|
||||
```
|
||||
|
||||
Write `$repo` and `$arch` literally. Both are pacman variables, not shell ones, hence the quoted heredoc.
|
||||
|
||||
Full setup notes, including canary, are in the [Linux repositories documentation][docs-linux].
|
||||
|
||||
## Other ways to run it
|
||||
|
||||
- [Open Fluxer in a browser](https://web.fluxer.app), no install needed.
|
||||
- [Host your own instance][docs-selfhost] from this repository.
|
||||
|
||||
## Documentation
|
||||
|
||||
- [Documentation home][docs]
|
||||
- [Downloads][docs-downloads]
|
||||
- [Self-hosting][docs-selfhost]
|
||||
|
||||
## License
|
||||
|
||||
The source is licensed under the [AGPL-3.0-or-later](./LICENSE) license.
|
||||
|
||||
Fluxer artwork, such as the logo, icons, badges and default avatars, is
|
||||
licensed under [CC BY-SA 4.0](./fluxer_static/LICENSE). Third-party material
|
||||
keeps its own terms, listed in
|
||||
[fluxer_static/THIRD_PARTY_LICENSES.md](./fluxer_static/THIRD_PARTY_LICENSES.md).
|
||||
|
||||
Use of the Fluxer name and logo is covered by the
|
||||
[name and marks policy](./.github/GOVERNANCE.md#name-and-marks).
|
||||
|
||||
[win-setup-x64]: https://pkgs.fluxer.com/desktop/stable/win32/x64/latest/setup
|
||||
[win-setup-arm64]: https://pkgs.fluxer.com/desktop/stable/win32/arm64/latest/setup
|
||||
[win-portable-x64]: https://pkgs.fluxer.com/desktop/stable/win32/x64/latest/portable
|
||||
[win-portable-arm64]: https://pkgs.fluxer.com/desktop/stable/win32/arm64/latest/portable
|
||||
[mac-dmg]: https://pkgs.fluxer.com/desktop/stable/darwin/arm64/latest/dmg
|
||||
[linux-deb-x64]: https://pkgs.fluxer.com/desktop/stable/linux/x64/latest/deb
|
||||
[linux-deb-arm64]: https://pkgs.fluxer.com/desktop/stable/linux/arm64/latest/deb
|
||||
[linux-rpm-x64]: https://pkgs.fluxer.com/desktop/stable/linux/x64/latest/rpm
|
||||
[linux-rpm-arm64]: https://pkgs.fluxer.com/desktop/stable/linux/arm64/latest/rpm
|
||||
[linux-appimage-x64]: https://pkgs.fluxer.com/desktop/stable/linux/x64/latest/appimage
|
||||
[linux-appimage-arm64]: https://pkgs.fluxer.com/desktop/stable/linux/arm64/latest/appimage
|
||||
[linux-targz-x64]: https://pkgs.fluxer.com/desktop/stable/linux/x64/latest/tar_gz
|
||||
[linux-targz-arm64]: https://pkgs.fluxer.com/desktop/stable/linux/arm64/latest/tar_gz
|
||||
[flatpak-ref]: https://pkgs.fluxer.com/flatpak/fluxer.flatpakref
|
||||
[flatpak-canary-ref]: https://pkgs.fluxer.com/flatpak/fluxer-canary.flatpakref
|
||||
[flathub]: https://flathub.org/apps/app.fluxer.Fluxer
|
||||
[android-play]: https://play.google.com/store/apps/details?id=com.fluxer
|
||||
[android-apk]: https://github.com/fluxerapp/flutter_client/releases
|
||||
[obtainium]: https://obtainium.imranr.dev/
|
||||
[ios-testflight]: https://testflight.apple.com/join/PKZR6pK9
|
||||
[docs]: https://docs.fluxer.app
|
||||
[docs-downloads]: https://docs.fluxer.app/downloads/overview/
|
||||
[docs-linux]: https://docs.fluxer.app/downloads/linux-repositories/
|
||||
[docs-selfhost]: https://docs.fluxer.app/operator/get-started/
|
||||
+47
-6
@@ -20,7 +20,7 @@
|
||||
"bracketSpacing": false,
|
||||
"bracketSameLine": false
|
||||
},
|
||||
"globals": ["React"]
|
||||
"globals": ["React", "__webpack_base_uri__"]
|
||||
},
|
||||
"json": {
|
||||
"formatter": {
|
||||
@@ -48,7 +48,7 @@
|
||||
"linter": {
|
||||
"enabled": true,
|
||||
"rules": {
|
||||
"recommended": true,
|
||||
"preset": "recommended",
|
||||
"complexity": {
|
||||
"noForEach": "off",
|
||||
"noImportantStyles": "off",
|
||||
@@ -83,11 +83,23 @@
|
||||
}
|
||||
},
|
||||
"useConst": "error",
|
||||
"noDescendingSpecificity": "off",
|
||||
"noNonNullAssertion": "off",
|
||||
"noParameterAssign": "off"
|
||||
"noParameterAssign": "off",
|
||||
"noRestrictedImports": {
|
||||
"level": "error",
|
||||
"options": {
|
||||
"paths": {
|
||||
"@lingui/react": {
|
||||
"importNames": ["I18nProvider"],
|
||||
"message": "Use AppI18nProvider from @app/features/i18n/components/AppI18nProvider so <Trans> output stays safe under page translation."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"a11y": {
|
||||
"recommended": true,
|
||||
"preset": "recommended",
|
||||
"useAriaPropsForRole": "error",
|
||||
"useValidAriaRole": "error",
|
||||
"useValidAriaValues": "error",
|
||||
@@ -115,6 +127,32 @@
|
||||
}
|
||||
},
|
||||
"assist": {"actions": {"source": {"organizeImports": "on"}}},
|
||||
"overrides": [
|
||||
{
|
||||
"includes": ["fluxer_app/src/**/*.tsx"],
|
||||
"plugins": ["./tools/lint/no-adjacent-jsx-text.grit"]
|
||||
},
|
||||
{
|
||||
"includes": ["fluxer_docs/scripts/VerifyDocsCoverage.ts"],
|
||||
"linter": {"rules": {"suspicious": {"noTemplateCurlyInString": "off"}}}
|
||||
},
|
||||
{
|
||||
"includes": [
|
||||
"fluxer_app/src/features/i18n/components/AppI18nProvider.tsx",
|
||||
"fluxer_app/src/features/i18n/components/AppI18nProvider.test.tsx"
|
||||
],
|
||||
"linter": {"rules": {"style": {"noRestrictedImports": "off"}}}
|
||||
},
|
||||
{
|
||||
"includes": ["fluxer_app/src/**/*.worklet.js"],
|
||||
"javascript": {"globals": ["AudioWorkletProcessor", "registerProcessor", "sampleRate", "currentTime"]}
|
||||
},
|
||||
{
|
||||
"includes": ["**/*.astro"],
|
||||
"linter": {"rules": {"correctness": {"noUnusedImports": "off", "noUnusedVariables": "off"}}},
|
||||
"assist": {"actions": {"source": {"organizeImports": "off"}}}
|
||||
}
|
||||
],
|
||||
"vcs": {
|
||||
"enabled": true,
|
||||
"clientKind": "git",
|
||||
@@ -125,7 +163,6 @@
|
||||
"**",
|
||||
"!**/.git",
|
||||
"!**/app.css",
|
||||
"!fluxer_admin/public/static/app.css",
|
||||
"!**/build",
|
||||
"fluxer_app/scripts/build",
|
||||
"!**/dist",
|
||||
@@ -145,7 +182,11 @@
|
||||
"!fluxer_static",
|
||||
"!packages/fonts",
|
||||
"!fluxer_admin/static/htmx.min.js",
|
||||
"!fluxer_api/src/api/openapi/openapi.json"
|
||||
"!fluxer_api/src/api/openapi/openapi.json",
|
||||
"!fluxer_api/pkgs/email/src/email_i18n/weblate",
|
||||
"!fluxer_api/src/api/content_i18n/weblate",
|
||||
"!packages/errors/src/i18n/weblate",
|
||||
"!**/auto-i18n-reviewed-unchanged.json"
|
||||
],
|
||||
"ignoreUnknown": true
|
||||
}
|
||||
|
||||
Vendored
+7
-30
@@ -30,17 +30,10 @@ FLUXER_POSTGRES_PASSWORD=fluxer
|
||||
FLUXER_POSTGRES_SSL=false
|
||||
FLUXER_POSTGRES_MAX_CONNECTIONS=20
|
||||
FLUXER_POSTGRES_KV_TABLE=fluxer_kv
|
||||
FLUXER_CASSANDRA_HOSTS=cassandra
|
||||
FLUXER_CASSANDRA_PORT=9042
|
||||
FLUXER_CASSANDRA_KEYSPACE=fluxer
|
||||
FLUXER_CASSANDRA_LOCAL_DC=datacenter1
|
||||
FLUXER_CASSANDRA_USERNAME=fluxer
|
||||
FLUXER_CASSANDRA_PASSWORD=fluxer
|
||||
FLUXER_KV_URL=redis://valkey:6379/0
|
||||
FLUXER_NATS_URL=nats://nats:4222
|
||||
FLUXER_NATS_JETSTREAM_URL=nats://nats:4222
|
||||
FLUXER_INTERNAL_API_ENDPOINT=http://127.0.0.1:8080
|
||||
FLUXER_INTERNAL_GATEWAY_ENDPOINT=http://127.0.0.1:8771
|
||||
FLUXER_INTERNAL_MEDIA_PROXY_ENDPOINT=http://127.0.0.1:8082
|
||||
FLUXER_MEDIA_PROXY_ENDPOINT=http://127.0.0.1:8082
|
||||
FLUXER_MEDIA_PROXY_PUBLIC_ENDPOINT=http://localhost:8088/media
|
||||
@@ -48,8 +41,6 @@ FLUXER_MEDIA_PROXY_PUBLIC_ENDPOINT=http://localhost:8088/media
|
||||
FLUXER_SVC_NATS_URL=nats://nats:4222
|
||||
FLUXER_SVC_SHARD_COUNT=1
|
||||
FLUXER_SVC_CACHE_TTL_MS=30000
|
||||
FLUXER_SVC_CACHE_HARD_TTL_MS=600000
|
||||
FLUXER_SVC_MAX_CONCURRENT_REQUESTS=64
|
||||
|
||||
FLUXER_S3_ENDPOINT=http://127.0.0.1:8333
|
||||
FLUXER_S3_PUBLIC_ENDPOINT=http://localhost:8088
|
||||
@@ -59,22 +50,20 @@ FLUXER_S3_SECRET_ACCESS_KEY=fluxer-secret
|
||||
FLUXER_S3_FORCE_PATH_STYLE=true
|
||||
FLUXER_S3_BUCKET_CDN=fluxer
|
||||
FLUXER_S3_BUCKET_UPLOADS=fluxer-uploads
|
||||
FLUXER_S3_BUCKET_DOWNLOADS=fluxer-downloads
|
||||
FLUXER_S3_BUCKET_REPORTS=fluxer-reports
|
||||
FLUXER_S3_BUCKET_HARVESTS=fluxer-harvests
|
||||
FLUXER_S3_BUCKET_STATIC=fluxer-static
|
||||
|
||||
FLUXER_LIVEKIT_ENABLED=true
|
||||
FLUXER_LIVEKIT_URL=ws://localhost:8088/livekit
|
||||
FLUXER_LIVEKIT_INTERNAL_URL=http://localhost:7880
|
||||
FLUXER_LIVEKIT_API_KEY=devkey
|
||||
FLUXER_LIVEKIT_API_SECRET=secret
|
||||
FLUXER_LIVEKIT_WEBHOOK_URL=http://localhost:8088/api/webhooks/livekit
|
||||
FLUXER_LIVEKIT_API_SECRET=fluxer-livekit-development-secret
|
||||
FLUXER_LIVEKIT_DEFAULT_REGION={"id":"local","name":"Local","emoji":"LC","latitude":59.3293,"longitude":18.0686}
|
||||
|
||||
FLUXER_API_PORT=8080
|
||||
FLUXER_API_PRESIGNED_ATTACHMENT_UPLOADS_ENABLED=true
|
||||
FLUXER_API_WORKER_MODE=all_lanes
|
||||
FLUXER_API_WORKER_ENABLE_VOICE_RECONCILIATION=true
|
||||
FLUXER_APP_DEV_PORT=3000
|
||||
FLUXER_APP_PROXY_PORT=8773
|
||||
FLUXER_STATIC_DIR=fluxer_app/dist
|
||||
@@ -95,18 +84,14 @@ FLUXER_GATEWAY_PRESENCE_PUSH_BUFFER_MAX_BYTES=1048576
|
||||
FLUXER_ADMIN_PORT=3020
|
||||
FLUXER_ADMIN_BASE_PATH=/admin
|
||||
FLUXER_ADMIN_SECRET_KEY_BASE=dev-admin-secret-key-base
|
||||
FLUXER_ADMIN_OAUTH_CLIENT_ID=1234567890123456789
|
||||
FLUXER_ADMIN_OAUTH_CLIENT_SECRET=dev-admin-oauth-secret
|
||||
FLUXER_ADMIN_OAUTH_REDIRECT_URI=http://localhost:8088/admin/oauth2_callback
|
||||
FLUXER_MARKETING_PORT=3010
|
||||
FLUXER_MARKETING_HOST=0.0.0.0
|
||||
FLUXER_MARKETING_BASE_PATH=/marketing
|
||||
FLUXER_MARKETING_SECRET_KEY_BASE=dev-marketing-secret-key-base
|
||||
|
||||
FLUXER_SUDO_MODE_SECRET=dev-sudo-secret
|
||||
FLUXER_CONNECTION_INITIATION_SECRET=dev-connection-initiation-secret
|
||||
FLUXER_VAPID_PUBLIC_KEY=dev-vapid-public-key
|
||||
FLUXER_VAPID_PRIVATE_KEY=dev-vapid-private-key
|
||||
FLUXER_PROFILE_PSEUDONYM_SECRET=fluxer-dev-profile-pseudonym-secret
|
||||
FLUXER_VAPID_PUBLIC_KEY=BHIbdKs24FdPkOQS7hbeg3adceLS0IqlKsn71ywEe6kbeopeFFiG3lkvJac7BVqkuk7mxwEa555O2FXV3HLt56w
|
||||
FLUXER_VAPID_PRIVATE_KEY=cs24JvXSxHiqJQgkJNocJFAdzJpPmpfU9xD-fDpn3tw
|
||||
FLUXER_VAPID_EMAIL=dev@localhost
|
||||
FLUXER_PASSKEY_RP_NAME='Fluxer Dev'
|
||||
FLUXER_PASSKEY_RP_ID=localhost
|
||||
@@ -119,10 +104,7 @@ FLUXER_EMAIL_SMTP_HOST=mailpit
|
||||
FLUXER_EMAIL_SMTP_PORT=1025
|
||||
FLUXER_EMAIL_SMTP_USERNAME=dev
|
||||
FLUXER_EMAIL_SMTP_PASSWORD=dev
|
||||
FLUXER_EMAIL_SMTP_SECURE=false
|
||||
FLUXER_SMS_ENABLED=false
|
||||
FLUXER_CAPTCHA_ENABLED=false
|
||||
FLUXER_CAPTCHA_PROVIDER=none
|
||||
FLUXER_EMAIL_SMTP_TLS_MODE=none
|
||||
FLUXER_SEARCH_ENGINE=meilisearch
|
||||
FLUXER_SEARCH_URL=http://meilisearch:7700
|
||||
FLUXER_SEARCH_API_KEY=fluxer-dev-meilisearch
|
||||
@@ -130,7 +112,6 @@ FLUXER_SEARCH_USERNAME=
|
||||
FLUXER_SEARCH_PASSWORD=
|
||||
FLUXER_SEARCH_TLS_REJECT_UNAUTHORIZED=false
|
||||
FLUXER_STRIPE_ENABLED=false
|
||||
FLUXER_NCMEC_ENABLED=false
|
||||
FLUXER_CLAMAV_ENABLED=false
|
||||
FLUXER_DISCOVERY_ENABLED=true
|
||||
FLUXER_SELF_HOSTED=true
|
||||
@@ -139,10 +120,6 @@ FLUXER_TEST_MODE_ENABLED=false
|
||||
|
||||
PUBLIC_BUILD_VERSION=dev
|
||||
PUBLIC_RELEASE_CHANNEL=canary
|
||||
PUBLIC_BOOTSTRAP_API_ENDPOINT=/api
|
||||
PUBLIC_BOOTSTRAP_API_PUBLIC_ENDPOINT=http://localhost:8088/api
|
||||
FLUXER_MEDIA_PROXY_UPLOAD_RELAY_SECRET_BASE64=Zmx1eGVyLWRldi11cGxvYWQtcmVsYXktc2VjcmV0LTAwMDA=
|
||||
FLUXER_MEDIA_PROXY_ATTACHMENT_URL_SECRETS_BASE64=Zmx1eGVyLWRldi1hdHRhY2htZW50LXVybC1zZWNyZXQ=
|
||||
AWS_EC2_METADATA_DISABLED=true
|
||||
AWS_ACCESS_KEY_ID=fluxer
|
||||
AWS_SECRET_ACCESS_KEY=fluxer-secret
|
||||
AWS_DEFAULT_REGION=us-east-1
|
||||
@@ -1,13 +1,9 @@
|
||||
# cargo-deny configuration for the Fluxer workspace.
|
||||
#
|
||||
# Applies to the root workspace (Cargo.toml at the repo root) AND to every
|
||||
# per-addon crate under fluxer_desktop/native/* (each addon has its own
|
||||
# [workspace], so we invoke cargo-deny with --config pointing here).
|
||||
#
|
||||
# Used by the native desktop security gate in CI.
|
||||
# Applies to the root workspace (Cargo.toml at the repo root).
|
||||
|
||||
[graph]
|
||||
all-features = false
|
||||
all-features = true
|
||||
no-default-features = false
|
||||
|
||||
[output]
|
||||
@@ -44,13 +40,11 @@ allow = [
|
||||
"BSD-3-Clause",
|
||||
"ISC",
|
||||
"MPL-2.0",
|
||||
"Unicode-DFS-2016",
|
||||
"Unicode-3.0",
|
||||
"Zlib",
|
||||
"CC0-1.0",
|
||||
"AGPL-3.0-or-later",
|
||||
"BSL-1.0",
|
||||
"OpenSSL",
|
||||
"CDLA-Permissive-2.0",
|
||||
]
|
||||
# Explicitly deny GPL-only / strong-copyleft licenses that don't compose with
|
||||
@@ -72,21 +66,55 @@ license-files = [
|
||||
[bans]
|
||||
multiple-versions = "warn"
|
||||
wildcards = "deny"
|
||||
# Per-addon crates path-depend on ../rust (the shared `fluxer_desktop_native`
|
||||
# crate) without a version. cargo-deny flags that as a wildcard; we allow it
|
||||
# because path deps can't realistically pin a SemVer range, and this only
|
||||
# affects intra-repo workspace links (registry wildcards remain denied).
|
||||
# Internal workspace crates use path dependencies without registry versions.
|
||||
# Registry wildcards remain denied.
|
||||
allow-wildcard-paths = true
|
||||
highlight = "all"
|
||||
workspace-default-features = "allow"
|
||||
external-default-features = "allow"
|
||||
# Keep desktop packaging and native addons away from the obsolete libfuse2 stack.
|
||||
# Keep workspace artifacts away from the obsolete libfuse2 stack.
|
||||
# AppImage packaging must use the static electron-builder runtime instead.
|
||||
deny = [
|
||||
{ crate = "fuse", reason = "libfuse2-based Rust wrapper; use a maintained FUSE3-native crate only if Fluxer ever needs FUSE directly" },
|
||||
{ crate = "fuse-sys", reason = "libfuse2 FFI crate; Fluxer AppImages must not reintroduce libfuse2 through native Rust dependencies" },
|
||||
]
|
||||
skip = []
|
||||
skip = [
|
||||
{ crate = "[email protected]", reason = "transitive dependency requires the older release line" },
|
||||
{ crate = "[email protected]", reason = "transitive dependency requires the older digest API" },
|
||||
{ crate = "[email protected]", reason = "transitive dependency requires the older digest API" },
|
||||
{ crate = "[email protected]", reason = "transitive dependency requires the older crypto API" },
|
||||
{ crate = "[email protected]", reason = "transitive dependency requires the older digest API" },
|
||||
{ crate = "[email protected]", reason = "transitive dependency requires the older release line" },
|
||||
{ crate = "[email protected]", reason = "transitive dependency requires the older digest API" },
|
||||
{ crate = "[email protected]", reason = "transitive dependency requires the older randomness API" },
|
||||
{ crate = "[email protected]", reason = "transitive dependency requires the prior randomness API" },
|
||||
{ crate = "[email protected]", reason = "transitive dependency requires the older hashbrown API" },
|
||||
{ crate = "[email protected]", reason = "transitive dependency requires the older digest API" },
|
||||
{ crate = "[email protected]", reason = "transitive dependency requires the older release line" },
|
||||
{ crate = "[email protected]", reason = "transitive dependency requires the older HTTP API" },
|
||||
{ crate = "[email protected]", reason = "transitive dependency requires the older HTTP body API" },
|
||||
{ crate = "[email protected]", reason = "transitive dependency requires the older release line" },
|
||||
{ crate = "[email protected]", reason = "transitive dependency requires the older release line" },
|
||||
{ crate = "[email protected]", reason = "transitive dependency requires the older release line" },
|
||||
{ crate = "[email protected]", reason = "transitive dependency requires the older release line" },
|
||||
{ crate = "[email protected]", reason = "transitive dependency requires the older release line" },
|
||||
{ crate = "[email protected]", reason = "transitive dependency requires the older WASI API" },
|
||||
{ crate = "[email protected]", reason = "transitive dependency requires the older randomness API" },
|
||||
{ crate = "[email protected]", reason = "transitive dependency requires the prior randomness API" },
|
||||
{ crate = "[email protected]", reason = "transitive dependency requires the older randomness API" },
|
||||
{ crate = "[email protected]", reason = "transitive dependency requires the prior randomness API" },
|
||||
{ crate = "[email protected]", reason = "transitive dependency requires the older randomness API" },
|
||||
{ crate = "[email protected]", reason = "transitive dependency requires the prior randomness API" },
|
||||
{ crate = "[email protected]", reason = "transitive dependency requires the older digest API" },
|
||||
{ crate = "[email protected]", reason = "transitive dependency requires the older digest API" },
|
||||
{ crate = "[email protected]", reason = "transitive dependency requires the older release line" },
|
||||
{ crate = "[email protected]", reason = "transitive dependency requires the older release line" },
|
||||
{ crate = "[email protected]", reason = "transitive dependency requires the older release line" },
|
||||
{ crate = "[email protected]", reason = "transitive dependency requires the older release line" },
|
||||
{ crate = "[email protected]+wasi-snapshot-preview1", reason = "transitive dependency requires the legacy WASI API" },
|
||||
{ crate = "[email protected]", reason = "transitive dependency requires the older release line" },
|
||||
{ crate = "[email protected]", reason = "transitive dependency requires the older Windows API" },
|
||||
]
|
||||
skip-tree = []
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
apiVersion: v2
|
||||
name: admin
|
||||
description: Fluxer admin service
|
||||
type: application
|
||||
version: 0.1.0
|
||||
dependencies:
|
||||
- name: common
|
||||
version: 0.1.0
|
||||
repository: file://../common
|
||||
@@ -1,3 +0,0 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
{{include "fluxer.deployment" (dict "name" .Values.app.name "values" .Values.app "context" .)}}
|
||||
@@ -1,3 +0,0 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
{{include "fluxer.pdb" (dict "name" .Values.app.name "minAvailable" .Values.pdb.minAvailable "context" .)}}
|
||||
@@ -1,3 +0,0 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
{{include "fluxer.service" (dict "name" .Values.app.name "values" .Values.app "context" .)}}
|
||||
@@ -1,41 +0,0 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
#
|
||||
# Live user-supplied values for the fluxer-admin-canary release as of 2026-05-17T20:42:36Z.
|
||||
# Captured via: helm -n fluxer get values fluxer-admin-canary
|
||||
# Apply with: helm upgrade fluxer-admin-canary deploy/helm/admin -f deploy/helm/admin/values.yaml -f deploy/helm/admin/values.canary.prod.yaml
|
||||
|
||||
app:
|
||||
build:
|
||||
channel: canary
|
||||
version: ""
|
||||
image: fluxer-admin
|
||||
name: admin-canary
|
||||
port: 8080
|
||||
replicas: 2
|
||||
minReadySeconds: 10
|
||||
rollingUpdate:
|
||||
maxSurge: 1
|
||||
maxUnavailable: 0
|
||||
terminationGracePeriodSeconds: 60
|
||||
startupProbe:
|
||||
enabled: true
|
||||
path: /_health
|
||||
periodSeconds: 5
|
||||
timeoutSeconds: 2
|
||||
failureThreshold: 24
|
||||
resources:
|
||||
limits:
|
||||
memory: 512Mi
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 256Mi
|
||||
tag: ""
|
||||
global:
|
||||
imagePullSecret: ghcr-pull-secret
|
||||
namespace: fluxer
|
||||
registry: ""
|
||||
envFrom:
|
||||
- secretRef:
|
||||
name: fluxer-runtime-env-canary
|
||||
pdb:
|
||||
minAvailable: 50%
|
||||
@@ -1,41 +0,0 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
#
|
||||
# Live user-supplied values for the fluxer-admin-stable release as of 2026-06-03T19:37:50Z.
|
||||
# Captured via: helm -n fluxer get values fluxer-admin-stable
|
||||
# Apply with: helm upgrade fluxer-admin-stable deploy/helm/admin -f deploy/helm/admin/values.yaml -f deploy/helm/admin/values.stable.prod.yaml
|
||||
|
||||
app:
|
||||
build:
|
||||
channel: stable
|
||||
version: ""
|
||||
image: fluxer-admin
|
||||
name: admin
|
||||
port: 8080
|
||||
replicas: 2
|
||||
minReadySeconds: 10
|
||||
rollingUpdate:
|
||||
maxSurge: 1
|
||||
maxUnavailable: 0
|
||||
terminationGracePeriodSeconds: 60
|
||||
startupProbe:
|
||||
enabled: true
|
||||
path: /_health
|
||||
periodSeconds: 5
|
||||
timeoutSeconds: 2
|
||||
failureThreshold: 24
|
||||
resources:
|
||||
limits:
|
||||
memory: 512Mi
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 256Mi
|
||||
tag: ""
|
||||
global:
|
||||
imagePullSecret: ghcr-pull-secret
|
||||
namespace: fluxer
|
||||
registry: ""
|
||||
envFrom:
|
||||
- secretRef:
|
||||
name: fluxer-runtime-env-stable
|
||||
pdb:
|
||||
minAvailable: 50%
|
||||
@@ -1,34 +0,0 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
global:
|
||||
namespace: fluxer
|
||||
imagePullSecret: ghcr-pull-secret
|
||||
registry: ""
|
||||
|
||||
app:
|
||||
name: ''
|
||||
image: ''
|
||||
tag: ''
|
||||
replicas: 2
|
||||
port: 8080
|
||||
config: ''
|
||||
minReadySeconds: 10
|
||||
rollingUpdate:
|
||||
maxSurge: 1
|
||||
maxUnavailable: 0
|
||||
terminationGracePeriodSeconds: 60
|
||||
startupProbe:
|
||||
enabled: true
|
||||
path: /_health
|
||||
periodSeconds: 5
|
||||
timeoutSeconds: 2
|
||||
failureThreshold: 24
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 256Mi
|
||||
limits:
|
||||
memory: 512Mi
|
||||
|
||||
pdb:
|
||||
minAvailable: '50%'
|
||||
@@ -1,11 +0,0 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
apiVersion: v2
|
||||
name: api
|
||||
description: Fluxer API service
|
||||
type: application
|
||||
version: 0.1.0
|
||||
dependencies:
|
||||
- name: common
|
||||
version: 0.1.0
|
||||
repository: file://../common
|
||||
@@ -1,3 +0,0 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
{{include "fluxer.deployment" (dict "name" .Values.app.name "values" .Values.app "context" .)}}
|
||||
@@ -1,3 +0,0 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
{{include "fluxer.pdb" (dict "name" .Values.app.name "minAvailable" .Values.pdb.minAvailable "context" .)}}
|
||||
@@ -1,3 +0,0 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
{{include "fluxer.service" (dict "name" .Values.app.name "values" .Values.app "context" .)}}
|
||||
@@ -1,105 +0,0 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
#
|
||||
# Live user-supplied values for the fluxer-api-canary release as of 2026-05-23T21:25:52Z.
|
||||
# Captured via: helm -n fluxer get values fluxer-api-canary
|
||||
# Apply with: helm upgrade fluxer-api-canary deploy/helm/api -f deploy/helm/api/values.yaml -f deploy/helm/api/values.canary.prod.yaml
|
||||
|
||||
app:
|
||||
build:
|
||||
channel: canary
|
||||
version: ""
|
||||
env:
|
||||
- name: NODE_TLS_REJECT_UNAUTHORIZED
|
||||
value: "0"
|
||||
- name: FLUXER_SNOWFLAKE_SERVICE_BATCH_SIZE
|
||||
value: "128"
|
||||
- name: FLUXER_SNOWFLAKE_SERVICE_LOW_WATERMARK
|
||||
value: "32"
|
||||
- name: FLUXER_SNOWFLAKE_SERVICE_MAX_BUFFER_AGE_MS
|
||||
value: "5000"
|
||||
- name: FLUXER_MEDIA_PROXY_UPLOAD_RELAY_SECRET_BASE64
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
key: relay_secret_base64
|
||||
name: fluxer-upload-relay
|
||||
image: fluxer-api
|
||||
name: api-canary
|
||||
port: 8080
|
||||
replicas: 4
|
||||
minReadySeconds: 15
|
||||
terminationGracePeriodSeconds: 90
|
||||
preStopDrain:
|
||||
enabled: true
|
||||
path: /_health
|
||||
sleepSeconds: 25
|
||||
timeoutSeconds: 2
|
||||
retryCount: 3
|
||||
retryIntervalSeconds: 1
|
||||
resources:
|
||||
limits:
|
||||
memory: 4Gi
|
||||
requests:
|
||||
cpu: 200m
|
||||
memory: 512Mi
|
||||
startupProbe:
|
||||
enabled: true
|
||||
failureThreshold: 24
|
||||
path: /_health
|
||||
periodSeconds: 5
|
||||
timeoutSeconds: 2
|
||||
rollingUpdate:
|
||||
maxSurge: 0
|
||||
maxUnavailable: 1
|
||||
tag: ""
|
||||
canary:
|
||||
env:
|
||||
- name: NODE_TLS_REJECT_UNAUTHORIZED
|
||||
value: "0"
|
||||
- name: FLUXER_SNOWFLAKE_SERVICE_BATCH_SIZE
|
||||
value: "128"
|
||||
- name: FLUXER_SNOWFLAKE_SERVICE_LOW_WATERMARK
|
||||
value: "32"
|
||||
- name: FLUXER_SNOWFLAKE_SERVICE_MAX_BUFFER_AGE_MS
|
||||
value: "5000"
|
||||
- name: FLUXER_MEDIA_PROXY_UPLOAD_RELAY_SECRET_BASE64
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
key: relay_secret_base64
|
||||
name: fluxer-upload-relay
|
||||
image: fluxer-api
|
||||
port: 8080
|
||||
replicas: 2
|
||||
minReadySeconds: 15
|
||||
terminationGracePeriodSeconds: 90
|
||||
preStopDrain:
|
||||
enabled: true
|
||||
path: /_health
|
||||
sleepSeconds: 25
|
||||
timeoutSeconds: 2
|
||||
retryCount: 3
|
||||
retryIntervalSeconds: 1
|
||||
rollingUpdate:
|
||||
maxSurge: 1
|
||||
maxUnavailable: 0
|
||||
resources:
|
||||
limits:
|
||||
memory: 4Gi
|
||||
requests:
|
||||
cpu: 200m
|
||||
memory: 512Mi
|
||||
startupProbe:
|
||||
enabled: true
|
||||
failureThreshold: 24
|
||||
path: /_health
|
||||
periodSeconds: 5
|
||||
timeoutSeconds: 2
|
||||
tag: ""
|
||||
global:
|
||||
imagePullSecret: ghcr-pull-secret
|
||||
namespace: fluxer
|
||||
registry: ""
|
||||
envFrom:
|
||||
- secretRef:
|
||||
name: fluxer-runtime-env-canary
|
||||
pdb:
|
||||
minAvailable: 75%
|
||||
@@ -1,107 +0,0 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
#
|
||||
# Live user-supplied values for the fluxer-api-stable release as of 2026-06-03T19:37:50Z.
|
||||
# Captured via: helm -n fluxer get values fluxer-api-stable
|
||||
# Apply with: helm upgrade fluxer-api-stable deploy/helm/api -f deploy/helm/api/values.yaml -f deploy/helm/api/values.stable.prod.yaml
|
||||
|
||||
app:
|
||||
build:
|
||||
channel: stable
|
||||
version: ""
|
||||
env:
|
||||
- name: NODE_TLS_REJECT_UNAUTHORIZED
|
||||
value: "0"
|
||||
- name: FLUXER_SNOWFLAKE_SERVICE_BATCH_SIZE
|
||||
value: "128"
|
||||
- name: FLUXER_SNOWFLAKE_SERVICE_LOW_WATERMARK
|
||||
value: "32"
|
||||
- name: FLUXER_SNOWFLAKE_SERVICE_MAX_BUFFER_AGE_MS
|
||||
value: "5000"
|
||||
- name: FLUXER_USERS_SERVICE_TIMEOUT_MS
|
||||
value: "6000"
|
||||
- name: FLUXER_MEDIA_PROXY_UPLOAD_RELAY_SECRET_BASE64
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
key: relay_secret_base64
|
||||
name: fluxer-upload-relay
|
||||
image: fluxer-api
|
||||
name: api
|
||||
port: 8080
|
||||
replicas: 31
|
||||
minReadySeconds: 15
|
||||
terminationGracePeriodSeconds: 90
|
||||
preStopDrain:
|
||||
enabled: true
|
||||
path: /_health
|
||||
sleepSeconds: 25
|
||||
timeoutSeconds: 2
|
||||
retryCount: 3
|
||||
retryIntervalSeconds: 1
|
||||
resources:
|
||||
limits:
|
||||
memory: 4Gi
|
||||
requests:
|
||||
cpu: 200m
|
||||
memory: 512Mi
|
||||
startupProbe:
|
||||
enabled: true
|
||||
failureThreshold: 24
|
||||
path: /_health
|
||||
periodSeconds: 5
|
||||
timeoutSeconds: 2
|
||||
rollingUpdate:
|
||||
maxSurge: 0
|
||||
maxUnavailable: 1
|
||||
tag: ""
|
||||
canary:
|
||||
env:
|
||||
- name: NODE_TLS_REJECT_UNAUTHORIZED
|
||||
value: "0"
|
||||
- name: FLUXER_SNOWFLAKE_SERVICE_BATCH_SIZE
|
||||
value: "128"
|
||||
- name: FLUXER_SNOWFLAKE_SERVICE_LOW_WATERMARK
|
||||
value: "32"
|
||||
- name: FLUXER_SNOWFLAKE_SERVICE_MAX_BUFFER_AGE_MS
|
||||
value: "5000"
|
||||
- name: FLUXER_MEDIA_PROXY_UPLOAD_RELAY_SECRET_BASE64
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
key: relay_secret_base64
|
||||
name: fluxer-upload-relay
|
||||
image: fluxer-api
|
||||
port: 8080
|
||||
replicas: 2
|
||||
minReadySeconds: 15
|
||||
terminationGracePeriodSeconds: 90
|
||||
preStopDrain:
|
||||
enabled: true
|
||||
path: /_health
|
||||
sleepSeconds: 25
|
||||
timeoutSeconds: 2
|
||||
retryCount: 3
|
||||
retryIntervalSeconds: 1
|
||||
rollingUpdate:
|
||||
maxSurge: 1
|
||||
maxUnavailable: 0
|
||||
resources:
|
||||
limits:
|
||||
memory: 4Gi
|
||||
requests:
|
||||
cpu: 200m
|
||||
memory: 512Mi
|
||||
startupProbe:
|
||||
enabled: true
|
||||
failureThreshold: 24
|
||||
path: /_health
|
||||
periodSeconds: 5
|
||||
timeoutSeconds: 2
|
||||
tag: ""
|
||||
global:
|
||||
imagePullSecret: ghcr-pull-secret
|
||||
namespace: fluxer
|
||||
registry: ""
|
||||
envFrom:
|
||||
- secretRef:
|
||||
name: fluxer-runtime-env-stable
|
||||
pdb:
|
||||
minAvailable: 75%
|
||||
@@ -1,98 +0,0 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
global:
|
||||
namespace: fluxer
|
||||
imagePullSecret: ghcr-pull-secret
|
||||
registry: ""
|
||||
|
||||
app:
|
||||
name: ''
|
||||
image: ''
|
||||
tag: ''
|
||||
replicas: 2
|
||||
port: 8080
|
||||
minReadySeconds: 15
|
||||
rollingUpdate:
|
||||
maxSurge: 1
|
||||
maxUnavailable: 0
|
||||
terminationGracePeriodSeconds: 90
|
||||
preStopDrain:
|
||||
enabled: true
|
||||
path: /_health
|
||||
sleepSeconds: 25
|
||||
timeoutSeconds: 2
|
||||
retryCount: 3
|
||||
retryIntervalSeconds: 1
|
||||
startupProbe:
|
||||
enabled: true
|
||||
path: /_health
|
||||
periodSeconds: 5
|
||||
timeoutSeconds: 2
|
||||
failureThreshold: 24
|
||||
env:
|
||||
- name: NODE_TLS_REJECT_UNAUTHORIZED
|
||||
value: '0'
|
||||
- name: FLUXER_SNOWFLAKE_SERVICE_BATCH_SIZE
|
||||
value: '128'
|
||||
- name: FLUXER_SNOWFLAKE_SERVICE_LOW_WATERMARK
|
||||
value: '32'
|
||||
- name: FLUXER_SNOWFLAKE_SERVICE_MAX_BUFFER_AGE_MS
|
||||
value: '5000'
|
||||
- name: FLUXER_MEDIA_PROXY_UPLOAD_RELAY_SECRET_BASE64
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: fluxer-upload-relay
|
||||
key: relay_secret_base64
|
||||
resources:
|
||||
requests:
|
||||
cpu: 200m
|
||||
memory: 512Mi
|
||||
limits:
|
||||
memory: 4Gi
|
||||
|
||||
canary:
|
||||
image: fluxer-api
|
||||
tag: ''
|
||||
replicas: 2
|
||||
port: 8080
|
||||
minReadySeconds: 15
|
||||
rollingUpdate:
|
||||
maxSurge: 1
|
||||
maxUnavailable: 0
|
||||
terminationGracePeriodSeconds: 90
|
||||
preStopDrain:
|
||||
enabled: true
|
||||
path: /_health
|
||||
sleepSeconds: 25
|
||||
timeoutSeconds: 2
|
||||
retryCount: 3
|
||||
retryIntervalSeconds: 1
|
||||
startupProbe:
|
||||
enabled: true
|
||||
path: /_health
|
||||
periodSeconds: 5
|
||||
timeoutSeconds: 2
|
||||
failureThreshold: 24
|
||||
env:
|
||||
- name: NODE_TLS_REJECT_UNAUTHORIZED
|
||||
value: '0'
|
||||
- name: FLUXER_SNOWFLAKE_SERVICE_BATCH_SIZE
|
||||
value: '128'
|
||||
- name: FLUXER_SNOWFLAKE_SERVICE_LOW_WATERMARK
|
||||
value: '32'
|
||||
- name: FLUXER_SNOWFLAKE_SERVICE_MAX_BUFFER_AGE_MS
|
||||
value: '5000'
|
||||
- name: FLUXER_MEDIA_PROXY_UPLOAD_RELAY_SECRET_BASE64
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: fluxer-upload-relay
|
||||
key: relay_secret_base64
|
||||
resources:
|
||||
requests:
|
||||
cpu: 200m
|
||||
memory: 512Mi
|
||||
limits:
|
||||
memory: 4Gi
|
||||
|
||||
pdb:
|
||||
minAvailable: '75%'
|
||||
@@ -1,11 +0,0 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
apiVersion: v2
|
||||
name: app-proxy
|
||||
description: Fluxer app proxy service
|
||||
type: application
|
||||
version: 0.1.0
|
||||
dependencies:
|
||||
- name: common
|
||||
version: 0.1.0
|
||||
repository: file://../common
|
||||
@@ -1,3 +0,0 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
{{include "fluxer.deployment" (dict "name" .Values.app.name "values" .Values.app "context" .)}}
|
||||
@@ -1,3 +0,0 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
{{include "fluxer.pdb" (dict "name" .Values.app.name "minAvailable" .Values.pdb.minAvailable "context" .)}}
|
||||
@@ -1,3 +0,0 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
{{include "fluxer.service" (dict "name" .Values.app.name "values" .Values.app "context" .)}}
|
||||
@@ -1,35 +0,0 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
#
|
||||
# Live user-supplied values for the fluxer-app-proxy-canary release as of 2026-05-17T20:42:38Z.
|
||||
# Captured via: helm -n fluxer get values fluxer-app-proxy-canary
|
||||
# Apply with: helm upgrade fluxer-app-proxy-canary deploy/helm/app-proxy -f deploy/helm/app-proxy/values.yaml -f deploy/helm/app-proxy/values.canary.prod.yaml
|
||||
|
||||
app:
|
||||
build:
|
||||
channel: canary
|
||||
version: ""
|
||||
env:
|
||||
- name: PUBLIC_BOOTSTRAP_API_ENDPOINT
|
||||
value: /api
|
||||
- name: PUBLIC_BOOTSTRAP_API_PUBLIC_ENDPOINT
|
||||
value: https://api.canary.fluxer.app
|
||||
image: fluxer-app-proxy
|
||||
name: app-proxy-canary
|
||||
port: 8080
|
||||
replicas: 2
|
||||
resources:
|
||||
limits:
|
||||
memory: 512Mi
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 256Mi
|
||||
tag: ""
|
||||
global:
|
||||
imagePullSecret: ghcr-pull-secret
|
||||
namespace: fluxer
|
||||
registry: ""
|
||||
envFrom:
|
||||
- secretRef:
|
||||
name: fluxer-runtime-env-canary
|
||||
pdb:
|
||||
minAvailable: 50%
|
||||
@@ -1,35 +0,0 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
#
|
||||
# Live user-supplied values for the fluxer-app-proxy-stable release as of 2026-05-17T20:42:39Z.
|
||||
# Captured via: helm -n fluxer get values fluxer-app-proxy-stable
|
||||
# Apply with: helm upgrade fluxer-app-proxy-stable deploy/helm/app-proxy -f deploy/helm/app-proxy/values.yaml -f deploy/helm/app-proxy/values.stable.prod.yaml
|
||||
|
||||
app:
|
||||
build:
|
||||
channel: stable
|
||||
version: ""
|
||||
env:
|
||||
- name: PUBLIC_BOOTSTRAP_API_ENDPOINT
|
||||
value: /api
|
||||
- name: PUBLIC_BOOTSTRAP_API_PUBLIC_ENDPOINT
|
||||
value: https://api.fluxer.app
|
||||
image: fluxer-app-proxy
|
||||
name: app-proxy
|
||||
port: 8080
|
||||
replicas: 2
|
||||
resources:
|
||||
limits:
|
||||
memory: 512Mi
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 256Mi
|
||||
tag: ""
|
||||
global:
|
||||
imagePullSecret: ghcr-pull-secret
|
||||
namespace: fluxer
|
||||
registry: ""
|
||||
envFrom:
|
||||
- secretRef:
|
||||
name: fluxer-runtime-env-stable
|
||||
pdb:
|
||||
minAvailable: 50%
|
||||
@@ -1,31 +0,0 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
global:
|
||||
namespace: fluxer
|
||||
imagePullSecret: ghcr-pull-secret
|
||||
registry: ""
|
||||
|
||||
app:
|
||||
name: ''
|
||||
image: ''
|
||||
tag: ''
|
||||
replicas: 2
|
||||
port: 8080
|
||||
config: ''
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 256Mi
|
||||
limits:
|
||||
memory: 512Mi
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
env:
|
||||
- name: PUBLIC_BOOTSTRAP_API_ENDPOINT
|
||||
value: '/api'
|
||||
|
||||
pdb:
|
||||
minAvailable: '50%'
|
||||
@@ -1,7 +0,0 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
apiVersion: v2
|
||||
name: common
|
||||
description: Shared Helm templates for Fluxer services
|
||||
type: library
|
||||
version: 0.1.0
|
||||
@@ -1,356 +0,0 @@
|
||||
{{/* SPDX-License-Identifier: AGPL-3.0-or-later */}}
|
||||
{{- define "fluxer.name" -}}
|
||||
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{- define "fluxer.chart" -}}
|
||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{- define "fluxer.labels" -}}
|
||||
helm.sh/chart: {{ include "fluxer.chart" . }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
app.kubernetes.io/part-of: fluxer
|
||||
{{- end }}
|
||||
|
||||
{{- define "fluxer.selectorLabels" -}}
|
||||
app.kubernetes.io/name: {{ .name }}
|
||||
app.kubernetes.io/instance: {{ .context.Release.Name }}
|
||||
{{- end }}
|
||||
|
||||
{{- define "fluxer.imagePullSecrets" -}}
|
||||
imagePullSecrets:
|
||||
- name: {{ .Values.global.imagePullSecret }}
|
||||
{{- end }}
|
||||
|
||||
{{- define "fluxer.image" -}}
|
||||
{{- $tag := required (printf ".tag is required (image: %s)" .image) .tag -}}
|
||||
{{- $registry := required "global.registry is required" .context.Values.global.registry -}}
|
||||
{{ $registry }}/{{ .image }}:{{ $tag }}
|
||||
{{- end }}
|
||||
|
||||
{{- define "fluxer.replicas" -}}
|
||||
{{- $name := .name -}}
|
||||
{{- $v := .values -}}
|
||||
{{- $ctx := .context -}}
|
||||
{{- $desired := int (required (printf ".replicas is required for %s" $name) $v.replicas) -}}
|
||||
{{- $preserveLiveReplicas := dig "preserveLiveReplicas" true $v -}}
|
||||
{{- if not $preserveLiveReplicas -}}
|
||||
{{- $desired -}}
|
||||
{{- else -}}
|
||||
{{- $existing := lookup "apps/v1" "Deployment" $ctx.Values.global.namespace $name -}}
|
||||
{{- if $existing -}}
|
||||
{{- $current := int (dig "spec" "replicas" 0 $existing) -}}
|
||||
{{- if gt $current 0 -}}
|
||||
{{- $current -}}
|
||||
{{- else -}}
|
||||
{{- $desired -}}
|
||||
{{- end -}}
|
||||
{{- else -}}
|
||||
{{- $desired -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end }}
|
||||
|
||||
{{- define "fluxer.deployment" -}}
|
||||
{{- $name := .name -}}
|
||||
{{- $v := .values -}}
|
||||
{{- $ctx := .context -}}
|
||||
{{- $isGateway := eq $name "gateway" -}}
|
||||
{{- $defaultMaxSurge := 1 -}}
|
||||
{{- $defaultMaxUnavailable := 0 -}}
|
||||
{{- $defaultMinReadySeconds := 10 -}}
|
||||
{{- $defaultTerminationGracePeriodSeconds := ternary 90 60 $isGateway -}}
|
||||
{{- $defaultReadinessPath := ternary "/_health/ready" "/_health" $isGateway -}}
|
||||
{{- $defaultReadinessTimeoutSeconds := ternary 5 2 $isGateway -}}
|
||||
{{- $configuredMaxSurge := dig "rollingUpdate" "maxSurge" $defaultMaxSurge $v -}}
|
||||
{{- $configuredMaxUnavailable := dig "rollingUpdate" "maxUnavailable" $defaultMaxUnavailable $v -}}
|
||||
{{- $maxSurge := $configuredMaxSurge -}}
|
||||
{{- $maxUnavailable := $configuredMaxUnavailable -}}
|
||||
{{- $minReadySeconds := int (dig "minReadySeconds" $defaultMinReadySeconds $v) -}}
|
||||
{{- $terminationGracePeriodSeconds := int (dig "terminationGracePeriodSeconds" $defaultTerminationGracePeriodSeconds $v) -}}
|
||||
{{- $readinessPath := dig "readinessProbe" "path" $defaultReadinessPath $v -}}
|
||||
{{- $readinessExecEnabled := dig "readinessProbe" "execEnabled" $isGateway $v -}}
|
||||
{{- $readinessTimeoutSeconds := int (dig "readinessProbe" "timeoutSeconds" $defaultReadinessTimeoutSeconds $v) -}}
|
||||
{{- $readinessExecCommand := printf "curl -fsS --max-time %d http://127.0.0.1:%d%s >/dev/null 2>&1 || exit 1" $readinessTimeoutSeconds (int $v.port) $readinessPath -}}
|
||||
{{- $readinessInitialDelaySeconds := int (dig "readinessProbe" "initialDelaySeconds" 5 $v) -}}
|
||||
{{- $readinessPeriodSeconds := int (dig "readinessProbe" "periodSeconds" 5 $v) -}}
|
||||
{{- $readinessFailureThreshold := int (dig "readinessProbe" "failureThreshold" 2 $v) -}}
|
||||
{{- $livenessPath := dig "livenessProbe" "path" "/_health" $v -}}
|
||||
{{- $livenessInitialDelaySeconds := int (dig "livenessProbe" "initialDelaySeconds" 10 $v) -}}
|
||||
{{- $livenessPeriodSeconds := int (dig "livenessProbe" "periodSeconds" 15 $v) -}}
|
||||
{{- $livenessFailureThreshold := int (dig "livenessProbe" "failureThreshold" 3 $v) -}}
|
||||
{{- $livenessTimeoutSeconds := int (dig "livenessProbe" "timeoutSeconds" 5 $v) -}}
|
||||
{{- $startupProbeEnabled := dig "startupProbe" "enabled" $isGateway $v -}}
|
||||
{{- $startupProbePath := dig "startupProbe" "path" "/_health" $v -}}
|
||||
{{- $startupProbeInitialDelaySeconds := int (dig "startupProbe" "initialDelaySeconds" 0 $v) -}}
|
||||
{{- $startupProbePeriodSeconds := int (dig "startupProbe" "periodSeconds" 5 $v) -}}
|
||||
{{- $startupProbeFailureThreshold := int (dig "startupProbe" "failureThreshold" 30 $v) -}}
|
||||
{{- $startupProbeTimeoutSeconds := int (dig "startupProbe" "timeoutSeconds" 5 $v) -}}
|
||||
{{- $preStopDrainEnabled := dig "preStopDrain" "enabled" $isGateway $v -}}
|
||||
{{- $preStopDrainPath := dig "preStopDrain" "path" "/_health/drain" $v -}}
|
||||
{{- $preStopDrainSleepSeconds := int (dig "preStopDrain" "sleepSeconds" 20 $v) -}}
|
||||
{{- $preStopDrainTimeoutSeconds := int (dig "preStopDrain" "timeoutSeconds" 2 $v) -}}
|
||||
{{- $preStopDrainRetryCount := int (dig "preStopDrain" "retryCount" 6 $v) -}}
|
||||
{{- $preStopDrainRetryIntervalSeconds := int (dig "preStopDrain" "retryIntervalSeconds" 1 $v) -}}
|
||||
{{- $preStopDrainCommand := printf "attempt=0; while [ \"$attempt\" -lt %d ]; do curl -fsS --max-time %d http://127.0.0.1:%d%s >/dev/null 2>&1 && break; attempt=$((attempt+1)); sleep %d; done; sleep %d" $preStopDrainRetryCount $preStopDrainTimeoutSeconds (int $v.port) $preStopDrainPath $preStopDrainRetryIntervalSeconds $preStopDrainSleepSeconds -}}
|
||||
{{- $build := get $v "build" | default (dict) -}}
|
||||
{{- $buildVersion := get $build "version" | default $v.tag -}}
|
||||
{{- $buildSha := get $build "sha" | default "" -}}
|
||||
{{- $buildChannel := get $build "channel" | default "" -}}
|
||||
{{- $nsfwServiceEndpoint := get $v "nsfwServiceEndpoint" | default "" -}}
|
||||
{{- $cluster := get $ctx.Values "cluster" | default (dict) -}}
|
||||
{{- $gatewayClusterEnabled := and $isGateway (eq (get $cluster "enabled" | default false) true) -}}
|
||||
{{- $erlangDistribution := get $cluster "erlangDistribution" | default (dict) -}}
|
||||
{{- $erlangDistPort := int (get $erlangDistribution "port" | default 8081) -}}
|
||||
{{- $erlangEpmdPort := int (get $erlangDistribution "epmdPort" | default 4369) -}}
|
||||
{{- $erlangCookieSecret := get $cluster "erlangCookieSecret" | default (dict) -}}
|
||||
{{- $erlangCookieSecretName := get $erlangCookieSecret "name" | default "fluxer-gateway-erlang-cookie" -}}
|
||||
{{- $erlangCookieSecretKey := get $erlangCookieSecret "key" | default "cookie" -}}
|
||||
{{- $gatewayNodeBasename := get $cluster "discoveryNodeBasename" | default "fluxer_gateway" -}}
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ $name }}
|
||||
namespace: {{ $ctx.Values.global.namespace }}
|
||||
labels:
|
||||
{{- include "fluxer.labels" $ctx | nindent 4 }}
|
||||
{{- include "fluxer.selectorLabels" (dict "name" $name "context" $ctx) | nindent 4 }}
|
||||
spec:
|
||||
replicas: {{ include "fluxer.replicas" (dict "name" $name "values" $v "context" $ctx) }}
|
||||
minReadySeconds: {{ $minReadySeconds }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "fluxer.selectorLabels" (dict "name" $name "context" $ctx) | nindent 6 }}
|
||||
strategy:
|
||||
type: RollingUpdate
|
||||
rollingUpdate:
|
||||
maxSurge: {{ $maxSurge | toJson }}
|
||||
maxUnavailable: {{ $maxUnavailable | toJson }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
{{- include "fluxer.labels" $ctx | nindent 8 }}
|
||||
{{- include "fluxer.selectorLabels" (dict "name" $name "context" $ctx) | nindent 8 }}
|
||||
spec:
|
||||
{{- include "fluxer.imagePullSecrets" $ctx | nindent 6 }}
|
||||
terminationGracePeriodSeconds: {{ $terminationGracePeriodSeconds }}
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
{{- if $v.affinity }}
|
||||
affinity:
|
||||
{{- toYaml $v.affinity | nindent 8 }}
|
||||
{{- else if $isGateway }}
|
||||
affinity:
|
||||
podAntiAffinity:
|
||||
preferredDuringSchedulingIgnoredDuringExecution:
|
||||
- weight: 100
|
||||
podAffinityTerm:
|
||||
labelSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: gateway
|
||||
app.kubernetes.io/instance: {{ $ctx.Release.Name }}
|
||||
topologyKey: kubernetes.io/hostname
|
||||
{{- end }}
|
||||
{{- if $v.topologySpreadConstraints }}
|
||||
topologySpreadConstraints:
|
||||
{{- toYaml $v.topologySpreadConstraints | nindent 8 }}
|
||||
{{- else if $isGateway }}
|
||||
topologySpreadConstraints:
|
||||
- maxSkew: 1
|
||||
topologyKey: kubernetes.io/hostname
|
||||
whenUnsatisfiable: ScheduleAnyway
|
||||
labelSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: gateway
|
||||
app.kubernetes.io/instance: {{ $ctx.Release.Name }}
|
||||
{{- else }}
|
||||
topologySpreadConstraints:
|
||||
- maxSkew: 1
|
||||
topologyKey: kubernetes.io/hostname
|
||||
whenUnsatisfiable: ScheduleAnyway
|
||||
nodeAffinityPolicy: Honor
|
||||
nodeTaintsPolicy: Honor
|
||||
labelSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: {{ $name }}
|
||||
app.kubernetes.io/instance: {{ $ctx.Release.Name }}
|
||||
{{- end }}
|
||||
{{- if $v.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml $v.nodeSelector | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- if $v.tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml $v.tolerations | nindent 8 }}
|
||||
{{- end }}
|
||||
containers:
|
||||
- name: {{ $name }}
|
||||
image: {{ include "fluxer.image" (dict "image" $v.image "tag" $v.tag "context" $ctx) }}
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
readOnlyRootFilesystem: false
|
||||
{{- if $v.command }}
|
||||
command: {{ $v.command | toJson }}
|
||||
{{- end }}
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: {{ $v.port }}
|
||||
protocol: TCP
|
||||
{{- if $gatewayClusterEnabled }}
|
||||
- name: epmd
|
||||
containerPort: {{ $erlangEpmdPort }}
|
||||
protocol: TCP
|
||||
- name: erl-dist
|
||||
containerPort: {{ $erlangDistPort }}
|
||||
protocol: TCP
|
||||
{{- end }}
|
||||
env:
|
||||
- name: NODE_ENV
|
||||
value: production
|
||||
- name: FLUXER_ENV
|
||||
value: production
|
||||
{{- if $gatewayClusterEnabled }}
|
||||
- name: POD_IP
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: status.podIP
|
||||
- name: FLUXER_ERLANG_NODE_NAME
|
||||
value: {{ printf "%s@$(POD_IP)" $gatewayNodeBasename | quote }}
|
||||
- name: FLUXER_ERLANG_DIST_PORT
|
||||
value: {{ printf "%d" $erlangDistPort | quote }}
|
||||
- name: FLUXER_ERLANG_COOKIE
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ $erlangCookieSecretName }}
|
||||
key: {{ $erlangCookieSecretKey }}
|
||||
{{- end }}
|
||||
{{- if $buildVersion }}
|
||||
- name: BUILD_VERSION
|
||||
value: {{ $buildVersion | quote }}
|
||||
{{- end }}
|
||||
{{- if $buildSha }}
|
||||
- name: BUILD_SHA
|
||||
value: {{ $buildSha | quote }}
|
||||
{{- end }}
|
||||
{{- if $buildChannel }}
|
||||
- name: RELEASE_CHANNEL
|
||||
value: {{ $buildChannel | quote }}
|
||||
{{- end }}
|
||||
{{- if $nsfwServiceEndpoint }}
|
||||
- name: FLUXER_NSFW_SERVICE_ENDPOINT
|
||||
value: {{ $nsfwServiceEndpoint | quote }}
|
||||
{{- end }}
|
||||
{{- if $ctx.Values.global.env }}
|
||||
{{- toYaml $ctx.Values.global.env | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- if $v.env }}
|
||||
{{- toYaml $v.env | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- if or $ctx.Values.global.envFrom $v.envFrom }}
|
||||
envFrom:
|
||||
{{- if $ctx.Values.global.envFrom }}
|
||||
{{- toYaml $ctx.Values.global.envFrom | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- if $v.envFrom }}
|
||||
{{- toYaml $v.envFrom | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if $preStopDrainEnabled }}
|
||||
lifecycle:
|
||||
preStop:
|
||||
exec:
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- {{ $preStopDrainCommand | quote }}
|
||||
{{- end }}
|
||||
volumeMounts:
|
||||
- name: keys
|
||||
mountPath: /etc/fluxer/keys
|
||||
readOnly: true
|
||||
{{- if not $v.noHealthCheck }}
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: {{ $livenessPath | quote }}
|
||||
port: http
|
||||
initialDelaySeconds: {{ $livenessInitialDelaySeconds }}
|
||||
periodSeconds: {{ $livenessPeriodSeconds }}
|
||||
timeoutSeconds: {{ $livenessTimeoutSeconds }}
|
||||
failureThreshold: {{ $livenessFailureThreshold }}
|
||||
readinessProbe:
|
||||
{{- if $readinessExecEnabled }}
|
||||
exec:
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- {{ $readinessExecCommand | quote }}
|
||||
{{- else }}
|
||||
httpGet:
|
||||
path: {{ $readinessPath | quote }}
|
||||
port: http
|
||||
{{- end }}
|
||||
initialDelaySeconds: {{ $readinessInitialDelaySeconds }}
|
||||
periodSeconds: {{ $readinessPeriodSeconds }}
|
||||
timeoutSeconds: {{ $readinessTimeoutSeconds }}
|
||||
failureThreshold: {{ $readinessFailureThreshold }}
|
||||
{{- if $startupProbeEnabled }}
|
||||
startupProbe:
|
||||
httpGet:
|
||||
path: {{ $startupProbePath | quote }}
|
||||
port: http
|
||||
initialDelaySeconds: {{ $startupProbeInitialDelaySeconds }}
|
||||
periodSeconds: {{ $startupProbePeriodSeconds }}
|
||||
timeoutSeconds: {{ $startupProbeTimeoutSeconds }}
|
||||
failureThreshold: {{ $startupProbeFailureThreshold }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
resources:
|
||||
{{- toYaml $v.resources | nindent 12 }}
|
||||
volumes:
|
||||
- name: keys
|
||||
secret:
|
||||
secretName: fluxer-keys
|
||||
optional: true
|
||||
{{- end }}
|
||||
|
||||
{{- define "fluxer.service" -}}
|
||||
{{- $name := .name -}}
|
||||
{{- $selectorName := .selectorName | default $name -}}
|
||||
{{- $v := .values -}}
|
||||
{{- $ctx := .context -}}
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ $name }}
|
||||
namespace: {{ $ctx.Values.global.namespace }}
|
||||
labels:
|
||||
{{- include "fluxer.labels" $ctx | nindent 4 }}
|
||||
{{- include "fluxer.selectorLabels" (dict "name" $name "context" $ctx) | nindent 4 }}
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: {{ $v.port }}
|
||||
targetPort: http
|
||||
protocol: TCP
|
||||
name: http
|
||||
selector:
|
||||
{{- include "fluxer.selectorLabels" (dict "name" $selectorName "context" $ctx) | nindent 4 }}
|
||||
{{- end }}
|
||||
|
||||
{{- define "fluxer.pdb" -}}
|
||||
apiVersion: policy/v1
|
||||
kind: PodDisruptionBudget
|
||||
metadata:
|
||||
name: {{ .name }}-pdb
|
||||
namespace: {{ .context.Values.global.namespace }}
|
||||
labels:
|
||||
{{- include "fluxer.labels" .context | nindent 4 }}
|
||||
spec:
|
||||
minAvailable: {{ .minAvailable }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "fluxer.selectorLabels" (dict "name" .name "context" .context) | nindent 6 }}
|
||||
{{- end }}
|
||||
@@ -1,11 +0,0 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
apiVersion: v2
|
||||
name: docs
|
||||
description: Fluxer documentation service
|
||||
type: application
|
||||
version: 0.1.0
|
||||
dependencies:
|
||||
- name: common
|
||||
version: 0.1.0
|
||||
repository: file://../common
|
||||
-3
@@ -1,3 +0,0 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
{{include "fluxer.deployment" (dict "name" .Values.app.name "values" .Values.app "context" .)}}
|
||||
Vendored
-3
@@ -1,3 +0,0 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
{{include "fluxer.pdb" (dict "name" .Values.app.name "minAvailable" .Values.pdb.minAvailable "context" .)}}
|
||||
-3
@@ -1,3 +0,0 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
{{include "fluxer.service" (dict "name" .Values.app.name "values" .Values.app "context" .)}}
|
||||
@@ -1,23 +0,0 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
app:
|
||||
build:
|
||||
channel: stable
|
||||
version: ""
|
||||
image: fluxer-docs
|
||||
name: docs
|
||||
port: 8080
|
||||
replicas: 2
|
||||
resources:
|
||||
limits:
|
||||
memory: 128Mi
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 64Mi
|
||||
tag: ""
|
||||
global:
|
||||
imagePullSecret: ghcr-pull-secret
|
||||
namespace: fluxer
|
||||
registry: ""
|
||||
pdb:
|
||||
minAvailable: 50%
|
||||
@@ -1,22 +0,0 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
global:
|
||||
namespace: fluxer
|
||||
imagePullSecret: ghcr-pull-secret
|
||||
registry: ""
|
||||
|
||||
app:
|
||||
name: ''
|
||||
image: ''
|
||||
tag: ''
|
||||
replicas: 2
|
||||
port: 8080
|
||||
resources:
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 64Mi
|
||||
limits:
|
||||
memory: 128Mi
|
||||
|
||||
pdb:
|
||||
minAvailable: '50%'
|
||||
@@ -0,0 +1,11 @@
|
||||
.DS_Store
|
||||
.git/
|
||||
.gitignore
|
||||
*.swp
|
||||
*.bak
|
||||
*.tmp
|
||||
*.orig
|
||||
*~
|
||||
.idea/
|
||||
.vscode/
|
||||
ci/
|
||||
@@ -0,0 +1,13 @@
|
||||
apiVersion: v2
|
||||
name: fluxer
|
||||
description: A complete Fluxer instance on Kubernetes, at parity with the self-hosted Docker Compose stack.
|
||||
type: application
|
||||
version: 0.1.0
|
||||
appVersion: "v1"
|
||||
kubeVersion: ">=1.29.0-0"
|
||||
home: https://docs.fluxer.app/operator/kubernetes/
|
||||
sources:
|
||||
- https://github.com/fluxerapp/fluxer/tree/main/deploy/helm/fluxer
|
||||
keywords:
|
||||
- fluxer
|
||||
- chat
|
||||
@@ -0,0 +1 @@
|
||||
domain: chat.example.test
|
||||
@@ -0,0 +1,3 @@
|
||||
domain: chat.example.test
|
||||
secrets:
|
||||
existingSecret: fluxer-ci-secret
|
||||
@@ -0,0 +1,38 @@
|
||||
domain: chat.example.test
|
||||
postgres:
|
||||
enabled: false
|
||||
external:
|
||||
host: db.example.test
|
||||
ssl: "true"
|
||||
valkey:
|
||||
enabled: false
|
||||
nats:
|
||||
enabled: false
|
||||
external:
|
||||
url: nats://mq.example.test:4222
|
||||
meilisearch:
|
||||
enabled: false
|
||||
external:
|
||||
url: https://search.example.test
|
||||
seaweedfs:
|
||||
enabled: false
|
||||
s3:
|
||||
endpoint: https://s3.example.test
|
||||
publicEndpoint: https://cdn.example.test
|
||||
region: eu-central-1
|
||||
forcePathStyle: false
|
||||
livekit:
|
||||
enabled: false
|
||||
external:
|
||||
url: http://livekit.voice.svc:7880
|
||||
publicUrl: wss://livekit.example.test
|
||||
secrets:
|
||||
values:
|
||||
FLUXER_POSTGRES_PASSWORD: ci-postgres-password
|
||||
FLUXER_SEARCH_API_KEY: ci-search-key
|
||||
FLUXER_S3_SECRET_ACCESS_KEY: ci-s3-secret
|
||||
FLUXER_NATS_AUTH_TOKEN: ci-nats-token
|
||||
FLUXER_LIVEKIT_API_KEY: ci-livekit-key
|
||||
FLUXER_LIVEKIT_API_SECRET: ci-livekit-secret-of-at-least-32-characters
|
||||
extra:
|
||||
FLUXER_KV_URL: redis://:[email protected]:6379/0
|
||||
@@ -0,0 +1,11 @@
|
||||
domain: chat.example.test
|
||||
edge:
|
||||
expose: gateway
|
||||
gateway:
|
||||
parentRefs:
|
||||
- name: shared
|
||||
namespace: gateway-system
|
||||
timeouts:
|
||||
request: 0s
|
||||
livekit:
|
||||
expose: nodePort
|
||||
@@ -0,0 +1,10 @@
|
||||
domain: chat.example.test
|
||||
email: [email protected]
|
||||
edge:
|
||||
expose: loadBalancer
|
||||
loadBalancer:
|
||||
http3: true
|
||||
livekit:
|
||||
expose: loadBalancer
|
||||
nodeIP: 203.0.113.10
|
||||
loadBalancerIP: 203.0.113.10
|
||||
@@ -0,0 +1,15 @@
|
||||
domain: chat.example.test
|
||||
networkPolicy:
|
||||
enabled: false
|
||||
livekit:
|
||||
enabled: false
|
||||
nats:
|
||||
replicas: 3
|
||||
initImage:
|
||||
repository: registry.example.test/busybox
|
||||
digest: sha256:0000000000000000000000000000000000000000000000000000000000000000
|
||||
postgres:
|
||||
image:
|
||||
repository: registry.example.test/postgres
|
||||
tag: "16"
|
||||
runAsUser: 999
|
||||
@@ -0,0 +1,13 @@
|
||||
domain: chat.example.test
|
||||
networkPolicy:
|
||||
ingressNamespaceSelector:
|
||||
matchLabels:
|
||||
kubernetes.io/metadata.name: ingress-nginx
|
||||
edge:
|
||||
ingress:
|
||||
className: nginx
|
||||
livekit:
|
||||
nodeSelector:
|
||||
kubernetes.io/hostname: voice-1
|
||||
nodeCIDRs:
|
||||
- 10.0.0.12/32
|
||||
@@ -0,0 +1,64 @@
|
||||
{
|
||||
servers {
|
||||
trusted_proxies static {$FLUXER_EDGE_TRUSTED_PROXIES:private_ranges}
|
||||
trusted_proxies_strict
|
||||
}
|
||||
{$FLUXER_EDGE_GLOBAL_OPTIONS}
|
||||
}
|
||||
|
||||
{$FLUXER_EDGE_SITE_ADDRESS} {
|
||||
encode {$FLUXER_EDGE_ENCODE:zstd gzip}
|
||||
|
||||
handle /_health {
|
||||
respond "OK" 200
|
||||
}
|
||||
|
||||
handle_path /api/* {
|
||||
reverse_proxy api:8080
|
||||
}
|
||||
|
||||
handle /gateway {
|
||||
rewrite * /
|
||||
reverse_proxy gateway:8080
|
||||
}
|
||||
|
||||
handle_path /gateway/* {
|
||||
reverse_proxy gateway:8080
|
||||
}
|
||||
|
||||
handle_path /media/* {
|
||||
reverse_proxy media-proxy:8080
|
||||
}
|
||||
|
||||
handle_path /livekit/* {
|
||||
reverse_proxy livekit:7880
|
||||
}
|
||||
|
||||
handle {$FLUXER_ADMIN_BASE_PATH:/admin} {
|
||||
rewrite * /
|
||||
reverse_proxy admin:8080
|
||||
}
|
||||
|
||||
handle_path {$FLUXER_ADMIN_BASE_PATH:/admin}/* {
|
||||
reverse_proxy admin:8080
|
||||
}
|
||||
|
||||
@staticAssets path /web/* /emoji/* /libs/* /avatars/* /badges/* /desktop/*
|
||||
handle @staticAssets {
|
||||
reverse_proxy static-proxy:8080
|
||||
}
|
||||
|
||||
handle /.well-known/fluxer {
|
||||
reverse_proxy api:8080
|
||||
}
|
||||
|
||||
handle {
|
||||
reverse_proxy app-proxy:8080
|
||||
}
|
||||
}
|
||||
|
||||
:8088 {
|
||||
handle /.well-known/fluxer {
|
||||
reverse_proxy api:8080
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
trap 'exit 0' TERM INT
|
||||
buckets="$FLUXER_S3_BUCKET_CDN $FLUXER_S3_BUCKET_UPLOADS $FLUXER_S3_BUCKET_REPORTS $FLUXER_S3_BUCKET_HARVESTS"
|
||||
missing="$buckets"
|
||||
for attempt in $(seq 1 "$FLUXER_SEAWEEDFS_INIT_ATTEMPTS"); do
|
||||
if ! nc -z 127.0.0.1 9333 2>/dev/null; then
|
||||
sleep 2
|
||||
continue
|
||||
fi
|
||||
listed=$(echo "s3.bucket.list" | timeout 10 weed shell -master=127.0.0.1:9333 2>&1)
|
||||
missing=""
|
||||
for b in $buckets; do
|
||||
echo "$listed" | grep -q "^[[:space:]]*$b[[:space:]]" || missing="${missing:+$missing }$b"
|
||||
done
|
||||
if [ -z "$missing" ]; then
|
||||
if ! echo "s3.configure -user=fluxer -access_key=$FLUXER_S3_ACCESS_KEY -secret_key=$FLUXER_S3_SECRET_KEY -actions=Admin,Read,Write,List,Tagging -apply" | timeout 10 weed shell -master=127.0.0.1:9333 >/dev/null 2>&1; then
|
||||
echo "seaweedfs-init could not configure the S3 identity" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "buckets ready"
|
||||
touch /tmp/fluxer-buckets-ready
|
||||
while :; do
|
||||
sleep 86400 &
|
||||
wait $!
|
||||
done
|
||||
fi
|
||||
for b in $missing; do
|
||||
echo "s3.bucket.create -name $b" | timeout 10 weed shell -master=127.0.0.1:9333 >/dev/null 2>&1
|
||||
done
|
||||
sleep 2
|
||||
done
|
||||
echo "seaweedfs-init could not verify buckets: $missing" >&2
|
||||
exit 1
|
||||
@@ -0,0 +1,72 @@
|
||||
{{- include "fluxer.validate" . }}
|
||||
{{- $v := .Values }}
|
||||
{{- $o := include "fluxer.origin" . }}
|
||||
Fluxer is installing in namespace {{ .Release.Namespace }}. Run one release per namespace.
|
||||
|
||||
Open {{ $o }} once every pod is ready:
|
||||
|
||||
kubectl -n {{ .Release.Namespace }} get pods
|
||||
|
||||
The admin panel is at {{ $o }}{{ $v.adminBasePath }}.
|
||||
|
||||
The setup wizard asks for the setup token before it creates the admin account:
|
||||
|
||||
kubectl -n {{ .Release.Namespace }} get secret {{ include "fluxer.secretName" . }} -o jsonpath='{.data.FLUXER_SETUP_TOKEN}' | base64 -d
|
||||
|
||||
A Secret with no FLUXER_SETUP_TOKEN has a token the API wrote to its log once:
|
||||
|
||||
kubectl -n {{ .Release.Namespace }} logs deployment/api | grep -i 'setup token'
|
||||
{{- if eq $v.edge.expose "loadBalancer" }}
|
||||
|
||||
Point DNS for {{ $v.domain }} at the external address of the edge-public Service:
|
||||
|
||||
kubectl -n {{ .Release.Namespace }} get service edge-public
|
||||
{{- else if eq $v.edge.expose "none" }}
|
||||
|
||||
Nothing exposes the instance yet. Send your proxy or tunnel to the Service edge
|
||||
on port 8080, with the Host header {{ $v.domain }}.
|
||||
{{- else }}
|
||||
|
||||
Point DNS for {{ $v.domain }} at your {{ ternary "ingress controller" "gateway" (eq $v.edge.expose "ingress") }}. Its Service needs
|
||||
externalTrafficPolicy Local or the PROXY protocol, or every client shares one IP
|
||||
and registration hits its per-IP limit.
|
||||
{{- end }}
|
||||
{{- if $v.livekit.external.url }}
|
||||
|
||||
Voice uses your LiveKit server at {{ $v.livekit.external.publicUrl }}. Point its webhook at
|
||||
{{ $o }}/api/webhooks/livekit, signed with the key in FLUXER_LIVEKIT_API_KEY.
|
||||
{{- end }}
|
||||
{{- if $v.livekit.enabled }}
|
||||
|
||||
Voice media does not pass through the edge. Open these ports to the internet:
|
||||
{{- if eq $v.livekit.expose "hostNetwork" }}
|
||||
{{ $v.livekit.tcpPort }}/tcp and {{ $v.livekit.udpPort }}/udp on the node that runs the livekit pod.
|
||||
hostNetwork needs a namespace that allows privileged pods. Keep 7880 closed.
|
||||
{{- else if eq $v.livekit.expose "nodePort" }}
|
||||
{{ $v.livekit.nodePorts.tcp }}/tcp and {{ $v.livekit.nodePorts.udp }}/udp on the node that runs the livekit pod.
|
||||
{{- else }}
|
||||
{{ $v.livekit.tcpPort }}/tcp and {{ $v.livekit.udpPort }}/udp on the load balancer of the Service livekit-rtc,
|
||||
whose public IP must be {{ $v.livekit.nodeIP }}.
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
Back up the Secret {{ include "fluxer.secretName" . }}{{ if $v.postgres.enabled }}, the database in postgres-0{{ end }}{{ if $v.seaweedfs.enabled }} and the uploads on the volume data-seaweedfs-0{{ end }}.
|
||||
{{- if $v.secrets.existingSecret }}
|
||||
After editing the Secret {{ $v.secrets.existingSecret }}, restart the release:
|
||||
|
||||
kubectl -n {{ .Release.Namespace }} rollout restart deployment,statefulset -l app.kubernetes.io/instance={{ .Release.Name }}
|
||||
{{- end }}
|
||||
{{- if and $v.secrets.generate (not $v.secrets.existingSecret) }}
|
||||
|
||||
Argo CD and helm template cannot read the existing Secret and would generate
|
||||
new secrets on every render. Under them, set secrets.generate=false and use
|
||||
secrets.existingSecret or give every key in secrets.values.
|
||||
{{- end }}
|
||||
|
||||
To move to the latest v1 images, pull the repository and upgrade with your values file:
|
||||
|
||||
helm upgrade {{ .Release.Name }} <chart> -n {{ .Release.Namespace }} -f <your values file> --set-string image.revision=$(date +%s)
|
||||
|
||||
Leave out --reuse-values, which keeps the defaults of the old chart version.
|
||||
|
||||
Documentation: https://docs.fluxer.app/operator/kubernetes/
|
||||
@@ -0,0 +1,109 @@
|
||||
{{- define "fluxer.s3Endpoint" -}}
|
||||
{{- .Values.s3.endpoint | default (ternary "http://seaweedfs:8333" "" .Values.seaweedfs.enabled) }}
|
||||
{{- end }}
|
||||
|
||||
{{- define "fluxer.configData" -}}
|
||||
{{- $v := .Values }}
|
||||
{{- $o := include "fluxer.origin" . }}
|
||||
{{- $hostOrigin := include "fluxer.hostOrigin" . }}
|
||||
{{- $media := printf "%s/media" $o }}
|
||||
{{- $s3 := include "fluxer.s3Endpoint" . }}
|
||||
{{- $c := dict }}
|
||||
{{- $_ := set $c "FLUXER_ENV" "production" }}
|
||||
{{- $_ := set $c "FLUXER_SELF_HOSTED" "true" }}
|
||||
{{- $_ := set $c "FLUXER_DATABASE_BACKEND" "postgres" }}
|
||||
{{- $_ := set $c "FLUXER_TRUST_CLIENT_IP_HEADER" "true" }}
|
||||
{{- $_ := set $c "FLUXER_BASE_DOMAIN" $v.domain }}
|
||||
{{- $_ := set $c "FLUXER_PUBLIC_SCHEME" $v.scheme }}
|
||||
{{- $_ := set $c "FLUXER_PUBLIC_PORT" (include "fluxer.string" $v.port) }}
|
||||
{{- $_ := set $c "FLUXER_PUBLIC_ORIGIN" (trimSuffix "/" ($v.publicOrigin | default "")) }}
|
||||
{{- $_ := set $c "FLUXER_APP_ENDPOINT" $o }}
|
||||
{{- $_ := set $c "FLUXER_MARKETING_ENDPOINT" $o }}
|
||||
{{- $_ := set $c "FLUXER_MEDIA_ENDPOINT" $media }}
|
||||
{{- $_ := set $c "FLUXER_MEDIA_PROXY_PUBLIC_ENDPOINT" $media }}
|
||||
{{- $_ := set $c "FLUXER_MEDIA_PROXY_UPLOAD_RELAY_ENDPOINT" $media }}
|
||||
{{- $_ := set $c "FLUXER_GATEWAY_MEDIA_PROXY_ENDPOINT" $media }}
|
||||
{{- $_ := set $c "FLUXER_ADMIN_ENDPOINT" (printf "%s%s" $o $v.adminBasePath) }}
|
||||
{{- $_ := set $c "FLUXER_GATEWAY_STATIC_CDN_ENDPOINT" $o }}
|
||||
{{- $_ := set $c "FLUXER_MEDIA_PROXY_CORS_ALLOWED_ORIGINS" $hostOrigin }}
|
||||
{{- $_ := set $c "FLUXER_PASSKEY_RP_ID" $v.domain }}
|
||||
{{- $_ := set $c "FLUXER_PASSKEY_ADDITIONAL_ALLOWED_ORIGINS" $o }}
|
||||
{{- if $v.postgres.enabled }}
|
||||
{{- $_ := set $c "FLUXER_POSTGRES_HOST" "postgres" }}
|
||||
{{- $_ := set $c "FLUXER_POSTGRES_PORT" "5432" }}
|
||||
{{- $_ := set $c "FLUXER_POSTGRES_DATABASE" $v.postgres.database }}
|
||||
{{- $_ := set $c "FLUXER_POSTGRES_USERNAME" $v.postgres.username }}
|
||||
{{- else }}
|
||||
{{- with $v.postgres.external }}
|
||||
{{- $_ := set $c "FLUXER_POSTGRES_HOST" (.host | default "") }}
|
||||
{{- $_ := set $c "FLUXER_POSTGRES_PORT" (include "fluxer.string" (.port | default "")) }}
|
||||
{{- $_ := set $c "FLUXER_POSTGRES_DATABASE" (.database | default "") }}
|
||||
{{- $_ := set $c "FLUXER_POSTGRES_USERNAME" (.username | default "") }}
|
||||
{{- $_ := set $c "FLUXER_POSTGRES_SSL" (include "fluxer.string" (.ssl | default "")) }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if not $v.valkey.enabled }}
|
||||
{{- $_ := set $c "FLUXER_KV_URL" ($v.valkey.external.url | default "") }}
|
||||
{{- end }}
|
||||
{{- $nats := ternary "nats://nats:4222" ($v.nats.external.url | default "") $v.nats.enabled }}
|
||||
{{- $_ := set $c "FLUXER_NATS_URL" $nats }}
|
||||
{{- $_ := set $c "FLUXER_NATS_JETSTREAM_URL" $nats }}
|
||||
{{- $_ := set $c "FLUXER_SVC_NATS_URL" $nats }}
|
||||
{{- $_ := set $c "FLUXER_SEARCH_ENGINE" "meilisearch" }}
|
||||
{{- $_ := set $c "FLUXER_SEARCH_URL" (ternary "http://meilisearch:7700" ($v.meilisearch.external.url | default "") $v.meilisearch.enabled) }}
|
||||
{{- $_ := set $c "FLUXER_S3_ENDPOINT" $s3 }}
|
||||
{{- $_ := set $c "FLUXER_S3_PUBLIC_ENDPOINT" ($v.s3.publicEndpoint | default $s3) }}
|
||||
{{- $_ := set $c "FLUXER_S3_REGION" $v.s3.region }}
|
||||
{{- $_ := set $c "FLUXER_S3_FORCE_PATH_STYLE" (toString $v.s3.forcePathStyle) }}
|
||||
{{- $_ := set $c "FLUXER_S3_BUCKET_CDN" $v.s3.buckets.cdn }}
|
||||
{{- $_ := set $c "FLUXER_S3_BUCKET_UPLOADS" $v.s3.buckets.uploads }}
|
||||
{{- $_ := set $c "FLUXER_S3_BUCKET_REPORTS" $v.s3.buckets.reports }}
|
||||
{{- $_ := set $c "FLUXER_S3_BUCKET_HARVESTS" $v.s3.buckets.harvests }}
|
||||
{{- $livekit := include "fluxer.livekitMode" . }}
|
||||
{{- $_ := set $c "FLUXER_LIVEKIT_ENABLED" (toString (ne $livekit "off")) }}
|
||||
{{- if eq $livekit "bundled" }}
|
||||
{{- $_ := set $c "FLUXER_LIVEKIT_INTERNAL_URL" "http://livekit:7880" }}
|
||||
{{- $_ := set $c "FLUXER_LIVEKIT_DEFAULT_REGION" $v.livekit.defaultRegion }}
|
||||
{{- $_ := set $c "FLUXER_LIVEKIT_URL" (printf "%s/livekit" $hostOrigin) }}
|
||||
{{- else if eq $livekit "external" }}
|
||||
{{- $_ := set $c "FLUXER_LIVEKIT_INTERNAL_URL" $v.livekit.external.url }}
|
||||
{{- $_ := set $c "FLUXER_LIVEKIT_DEFAULT_REGION" $v.livekit.defaultRegion }}
|
||||
{{- $_ := set $c "FLUXER_LIVEKIT_URL" $v.livekit.external.publicUrl }}
|
||||
{{- end }}
|
||||
{{- $_ := set $c "FLUXER_API_PRESIGNED_HARVEST_DOWNLOADS_ENABLED" "false" }}
|
||||
{{- $_ := set $c "FLUXER_EMAIL_FROM_EMAIL" "noreply@localhost" }}
|
||||
{{- $_ := set $c "FLUXER_VAPID_EMAIL" ($v.email | default (printf "admin@%s" $v.domain)) }}
|
||||
{{- $_ := set $c "FLUXER_INTERNAL_API_ENDPOINT" "http://api:8080" }}
|
||||
{{- $_ := set $c "FLUXER_INTERNAL_MEDIA_PROXY_ENDPOINT" "http://media-proxy:8080" }}
|
||||
{{- range $k, $val := $v.env | default dict }}
|
||||
{{- $_ := set $c $k (include "fluxer.string" ($val | default "")) }}
|
||||
{{- end }}
|
||||
{{- $out := dict }}
|
||||
{{- range $k, $val := $c }}
|
||||
{{- if $val }}
|
||||
{{- $_ := set $out $k $val }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- toYaml $out }}
|
||||
{{- end }}
|
||||
|
||||
{{- define "fluxer.appProxyConfigData" -}}
|
||||
{{- $v := .Values }}
|
||||
{{- $s3 := include "fluxer.s3Endpoint" . }}
|
||||
{{- $c := dict }}
|
||||
{{- $_ := set $c "FLUXER_APP_PROXY_PORT" "8080" }}
|
||||
{{- $_ := set $c "DISCOVERY_UPSTREAM_URL" "http://api:8080/.well-known/fluxer" }}
|
||||
{{- $_ := set $c "FLUXER_S3_PUBLIC_ENDPOINT" ($v.s3.publicEndpoint | default $s3) }}
|
||||
{{- $_ := set $c "FLUXER_S3_BUCKET_UPLOADS" $v.s3.buckets.uploads }}
|
||||
{{- $_ := set $c "FLUXER_MEDIA_ENDPOINT" (printf "%s/media" (include "fluxer.origin" .)) }}
|
||||
{{- range $k, $val := $v.appProxy.config | default dict }}
|
||||
{{- $_ := set $c $k (include "fluxer.string" ($val | default "")) }}
|
||||
{{- end }}
|
||||
{{- $out := dict }}
|
||||
{{- range $k, $val := $c }}
|
||||
{{- if $val }}
|
||||
{{- $_ := set $out $k $val }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- toYaml $out }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,375 @@
|
||||
{{- define "fluxer.chart" -}}
|
||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end }}
|
||||
|
||||
{{- define "fluxer.selectorLabels" -}}
|
||||
app.kubernetes.io/name: {{ .name }}
|
||||
app.kubernetes.io/instance: {{ .root.Release.Name }}
|
||||
{{- end }}
|
||||
|
||||
{{- define "fluxer.podLabels" -}}
|
||||
{{ include "fluxer.selectorLabels" . }}
|
||||
{{- with .component }}
|
||||
app.kubernetes.io/component: {{ . }}
|
||||
{{- end }}
|
||||
app.kubernetes.io/part-of: fluxer
|
||||
{{- end }}
|
||||
|
||||
{{- define "fluxer.labels" -}}
|
||||
{{ include "fluxer.podLabels" . }}
|
||||
app.kubernetes.io/managed-by: {{ .root.Release.Service }}
|
||||
app.kubernetes.io/version: {{ .root.Chart.AppVersion | quote }}
|
||||
helm.sh/chart: {{ include "fluxer.chart" .root }}
|
||||
{{- end }}
|
||||
|
||||
{{- define "fluxer.string" -}}
|
||||
{{- if and (kindIs "float64" .) (eq . (float64 (int64 .))) }}
|
||||
{{- int64 . | toString }}
|
||||
{{- else }}
|
||||
{{- toString . }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{- define "fluxer.origin" -}}
|
||||
{{- $v := .Values }}
|
||||
{{- if $v.publicOrigin }}
|
||||
{{- trimSuffix "/" $v.publicOrigin }}
|
||||
{{- else }}
|
||||
{{- $default := ternary 443 80 (eq $v.scheme "https") }}
|
||||
{{- if eq (int $v.port) $default }}
|
||||
{{- printf "%s://%s" $v.scheme $v.domain }}
|
||||
{{- else }}
|
||||
{{- printf "%s://%s:%d" $v.scheme $v.domain (int $v.port) }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{- define "fluxer.hostOrigin" -}}
|
||||
{{- $v := .Values }}
|
||||
{{- if $v.publicOrigin }}
|
||||
{{- trimSuffix "/" $v.publicOrigin }}
|
||||
{{- else }}
|
||||
{{- printf "%s://%s:%d" $v.scheme $v.domain (int $v.port) }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{- define "fluxer.secretName" -}}
|
||||
{{- .Values.secrets.existingSecret | default "fluxer-env" }}
|
||||
{{- end }}
|
||||
|
||||
{{- define "fluxer.thirdPartyImage" -}}
|
||||
{{- $ref := printf "%s:%s" .repository (include "fluxer.string" .tag) }}
|
||||
{{- with .digest }}
|
||||
{{- $ref = printf "%s@%s" $ref . }}
|
||||
{{- end }}
|
||||
{{- $ref | quote }}
|
||||
{{- end }}
|
||||
|
||||
{{- define "fluxer.image" -}}
|
||||
{{- $v := .root.Values.image }}
|
||||
{{- $img := (.w | default dict).image | default dict }}
|
||||
{{- $registry := $img.registry | default $v.registry }}
|
||||
{{- $tag := $img.tag | default (get ($v.tags | default dict) .image) | default $v.tag }}
|
||||
{{- $ref := printf "%s/%s:%s" $registry .image (include "fluxer.string" $tag) }}
|
||||
{{- with $img.digest | default (get ($v.digests | default dict) .image) }}
|
||||
{{- $ref = printf "%s@%s" $ref . }}
|
||||
{{- end }}
|
||||
{{- $ref | quote }}
|
||||
{{- end }}
|
||||
|
||||
{{- define "fluxer.pullPolicy" -}}
|
||||
{{- (((.w | default dict).image | default dict).pullPolicy) | default .root.Values.image.pullPolicy }}
|
||||
{{- end }}
|
||||
|
||||
{{- define "fluxer.pullSecrets" -}}
|
||||
{{- with .Values.image.pullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 2 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{- define "fluxer.podSecurityContext" -}}
|
||||
runAsNonRoot: true
|
||||
{{- with .uid }}
|
||||
runAsUser: {{ . }}
|
||||
runAsGroup: {{ $.gid | default . }}
|
||||
fsGroup: {{ $.gid | default . }}
|
||||
fsGroupChangePolicy: OnRootMismatch
|
||||
{{- end }}
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
{{- end }}
|
||||
|
||||
{{- define "fluxer.containerSecurityContext" -}}
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop:
|
||||
- ALL
|
||||
{{- end }}
|
||||
|
||||
{{- define "fluxer.scheduling" -}}
|
||||
{{- $w := .w | default dict }}
|
||||
{{- with $w.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 2 }}
|
||||
{{- end }}
|
||||
{{- with $w.tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml . | nindent 2 }}
|
||||
{{- end }}
|
||||
{{- with $w.affinity }}
|
||||
affinity:
|
||||
{{- toYaml . | nindent 2 }}
|
||||
{{- end }}
|
||||
{{- $spread := list }}
|
||||
{{- range $w.topologySpreadConstraints }}
|
||||
{{- $c := deepCopy . }}
|
||||
{{- if not (hasKey $c "labelSelector") }}
|
||||
{{- $_ := set $c "labelSelector" (dict "matchLabels" (include "fluxer.selectorLabels" $ | fromYaml)) }}
|
||||
{{- end }}
|
||||
{{- $spread = append $spread $c }}
|
||||
{{- end }}
|
||||
{{- with $spread }}
|
||||
topologySpreadConstraints:
|
||||
{{- toYaml . | nindent 2 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{- define "fluxer.pvc" -}}
|
||||
- metadata:
|
||||
name: data
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
{{- with .storageClassName }}
|
||||
storageClassName: {{ . }}
|
||||
{{- end }}
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .size }}
|
||||
{{- end }}
|
||||
|
||||
{{- define "fluxer.vapidPair" -}}
|
||||
{{- $der := genPrivateKey "ecdsa" | replace "-----BEGIN EC PRIVATE KEY-----" "" | replace "-----END EC PRIVATE KEY-----" "" | nospace | b64dec -}}
|
||||
private: {{ substr 7 39 $der | b64enc | replace "+" "-" | replace "/" "_" | trimAll "=" }}
|
||||
public: {{ substr 56 121 $der | b64enc | replace "+" "-" | replace "/" "_" | trimAll "=" }}
|
||||
{{- end }}
|
||||
|
||||
{{- define "fluxer.livekitMode" -}}
|
||||
{{- if .Values.livekit.enabled }}bundled{{ else if .Values.livekit.external.url }}external{{ else }}off{{ end }}
|
||||
{{- end }}
|
||||
|
||||
{{- define "fluxer.noGenerateKeys" -}}
|
||||
{{- $keys := list }}
|
||||
{{- $extra := .Values.secrets.extra | default dict }}
|
||||
{{- if and (not .Values.postgres.enabled) (not (get $extra "FLUXER_POSTGRES_URL")) }}
|
||||
{{- $keys = append $keys "FLUXER_POSTGRES_PASSWORD" }}
|
||||
{{- end }}
|
||||
{{- if not .Values.meilisearch.enabled }}
|
||||
{{- $keys = append $keys "FLUXER_SEARCH_API_KEY" }}
|
||||
{{- end }}
|
||||
{{- if not .Values.seaweedfs.enabled }}
|
||||
{{- $keys = append $keys "FLUXER_S3_SECRET_ACCESS_KEY" }}
|
||||
{{- end }}
|
||||
{{- if eq (include "fluxer.livekitMode" .) "external" }}
|
||||
{{- $keys = append $keys "FLUXER_LIVEKIT_API_SECRET" }}
|
||||
{{- end }}
|
||||
{{- toJson $keys }}
|
||||
{{- end }}
|
||||
|
||||
{{- define "fluxer.requiredSecretKeys" -}}
|
||||
{{- $keys := list }}
|
||||
{{- $extra := .Values.secrets.extra | default dict }}
|
||||
{{- range $k, $_ := .Values.secrets.values }}
|
||||
{{- if and (eq $k "FLUXER_POSTGRES_PASSWORD") (get $extra "FLUXER_POSTGRES_URL") }}
|
||||
{{- else if and (hasPrefix "FLUXER_LIVEKIT_" $k) (eq (include "fluxer.livekitMode" $) "off") }}
|
||||
{{- else if and (eq $k "FLUXER_VALKEY_PASSWORD") (not $.Values.valkey.enabled) }}
|
||||
{{- else if and (eq $k "FLUXER_NATS_AUTH_TOKEN") (not $.Values.nats.enabled) }}
|
||||
{{- else if and (eq $k "FLUXER_SETUP_TOKEN") (or $.Values.secrets.existingSecret (and (not $.Values.secrets.generate) (not (include "fluxer.string" (get $.Values.secrets.values $k | default ""))))) }}
|
||||
{{- else }}
|
||||
{{- $keys = append $keys $k }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- toJson $keys }}
|
||||
{{- end }}
|
||||
|
||||
{{- define "fluxer.resolveSecrets" -}}
|
||||
{{- $v := .Values }}
|
||||
{{- $existing := dict }}
|
||||
{{- $found := lookup "v1" "Secret" .Release.Namespace (include "fluxer.secretName" .) }}
|
||||
{{- range $k, $val := ($found.data | default dict) }}
|
||||
{{- $_ := set $existing $k (b64dec $val) }}
|
||||
{{- end }}
|
||||
{{- $out := dict }}
|
||||
{{- if $v.secrets.existingSecret }}
|
||||
{{- $out = $existing }}
|
||||
{{- else }}
|
||||
{{- $noGenerate := include "fluxer.noGenerateKeys" . | fromJsonArray }}
|
||||
{{- $explicit := $v.secrets.values | default dict }}
|
||||
{{- $vapidPublic := include "fluxer.string" (get $explicit "FLUXER_VAPID_PUBLIC_KEY" | default "") }}
|
||||
{{- $vapidPrivate := include "fluxer.string" (get $explicit "FLUXER_VAPID_PRIVATE_KEY" | default "") }}
|
||||
{{- if and $vapidPublic $vapidPrivate }}
|
||||
{{- else if or $vapidPublic $vapidPrivate }}
|
||||
{{- fail "secrets.values.FLUXER_VAPID_PUBLIC_KEY and secrets.values.FLUXER_VAPID_PRIVATE_KEY must be set together, or both left empty to generate a pair" }}
|
||||
{{- else if and (get $existing "FLUXER_VAPID_PUBLIC_KEY") (get $existing "FLUXER_VAPID_PRIVATE_KEY") }}
|
||||
{{- $vapidPublic = get $existing "FLUXER_VAPID_PUBLIC_KEY" }}
|
||||
{{- $vapidPrivate = get $existing "FLUXER_VAPID_PRIVATE_KEY" }}
|
||||
{{- else if $v.secrets.generate }}
|
||||
{{- $pair := include "fluxer.vapidPair" . | fromYaml }}
|
||||
{{- $vapidPublic = $pair.public }}
|
||||
{{- $vapidPrivate = $pair.private }}
|
||||
{{- else }}
|
||||
{{- fail "secrets.values.FLUXER_VAPID_PUBLIC_KEY and secrets.values.FLUXER_VAPID_PRIVATE_KEY are empty and secrets.generate is false" }}
|
||||
{{- end }}
|
||||
{{- $_ := set $out "FLUXER_VAPID_PUBLIC_KEY" $vapidPublic }}
|
||||
{{- $_ := set $out "FLUXER_VAPID_PRIVATE_KEY" $vapidPrivate }}
|
||||
{{- $required := include "fluxer.requiredSecretKeys" . | fromJsonArray }}
|
||||
{{- $outsideToken := include "fluxer.string" (get $explicit "FLUXER_NATS_AUTH_TOKEN" | default "") }}
|
||||
{{- if and $outsideToken (not $v.nats.enabled) }}
|
||||
{{- $_ := set $out "FLUXER_NATS_AUTH_TOKEN" $outsideToken }}
|
||||
{{- end }}
|
||||
{{- range $k := $required }}
|
||||
{{- if not (hasPrefix "FLUXER_VAPID_" $k) }}
|
||||
{{- $given := include "fluxer.string" (get $explicit $k | default "") }}
|
||||
{{- if $given }}
|
||||
{{- $_ := set $out $k $given }}
|
||||
{{- else if has $k $noGenerate }}
|
||||
{{- fail (printf "secrets.values.%s is required when the matching service is not bundled" $k) }}
|
||||
{{- else if get $existing $k }}
|
||||
{{- $_ := set $out $k (get $existing $k) }}
|
||||
{{- else if $v.secrets.generate }}
|
||||
{{- if eq $k "FLUXER_MEDIA_PROXY_UPLOAD_RELAY_SECRET_BASE64" }}
|
||||
{{- $_ := set $out $k (randBytes 32) }}
|
||||
{{- else }}
|
||||
{{- $_ := set $out $k (randAlphaNum 64) }}
|
||||
{{- end }}
|
||||
{{- else }}
|
||||
{{- fail (printf "secrets.values.%s is empty and secrets.generate is false" $k) }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- range $k, $val := $v.secrets.extra | default dict }}
|
||||
{{- $s := include "fluxer.string" ($val | default "") }}
|
||||
{{- if $s }}
|
||||
{{- $_ := set $out $k $s }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- toJson $out }}
|
||||
{{- end }}
|
||||
|
||||
{{- define "fluxer.secretData" -}}
|
||||
{{- if not (hasKey .Values "fluxerResolvedSecrets") }}
|
||||
{{- $_ := set .Values "fluxerResolvedSecrets" (include "fluxer.resolveSecrets" . | fromJson) }}
|
||||
{{- end }}
|
||||
{{- toJson (get .Values "fluxerResolvedSecrets") }}
|
||||
{{- end }}
|
||||
|
||||
{{- define "fluxer.secretEnv" -}}
|
||||
- name: {{ .name }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "fluxer.secretName" .root }}
|
||||
key: {{ .key }}
|
||||
{{- end }}
|
||||
|
||||
{{- define "fluxer.instanceChecksum" -}}
|
||||
{{- $parts := list (include "fluxer.configData" .) (include "fluxer.appProxyConfigData" .) (toJson .Values.secrets.values) (toJson (.Values.secrets.extra | default dict)) (include "fluxer.string" .Values.image.revision) (include "fluxer.secretData" .) }}
|
||||
{{- join "\n" $parts | sha256sum }}
|
||||
{{- end }}
|
||||
|
||||
{{- define "fluxer.envList" -}}
|
||||
{{- $w := .w | default dict }}
|
||||
{{- $own := $w.env | default dict }}
|
||||
{{- $base := .env | default list }}
|
||||
{{- $names := list }}
|
||||
{{- range $base }}
|
||||
{{- $names = append $names .name }}
|
||||
{{- end }}
|
||||
{{- $out := list }}
|
||||
{{- range $base }}
|
||||
{{- if hasKey $own .name }}
|
||||
{{- $val := get $own .name }}
|
||||
{{- if not (kindIs "invalid" $val) }}
|
||||
{{- $out = append $out (dict "name" .name "value" (include "fluxer.string" $val)) }}
|
||||
{{- end }}
|
||||
{{- else }}
|
||||
{{- $out = append $out . }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- range $k := keys $own | sortAlpha }}
|
||||
{{- $val := get $own $k }}
|
||||
{{- if and (not (has $k $names)) (not (kindIs "invalid" $val)) }}
|
||||
{{- $out = append $out (dict "name" $k "value" (include "fluxer.string" $val)) }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- $out = concat $out ($w.extraEnv | default list) }}
|
||||
{{- with $out }}
|
||||
{{- toYaml . }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{- define "fluxer.probes" -}}
|
||||
{{- $own := (.w | default dict).probes | default dict }}
|
||||
{{- range $probe := list "startup" "liveness" "readiness" }}
|
||||
{{- $p := get ($.probes | default dict) $probe }}
|
||||
{{- if hasKey $own $probe }}
|
||||
{{- $p = get $own $probe }}
|
||||
{{- end }}
|
||||
{{- with $p }}
|
||||
{{ $probe }}Probe:
|
||||
{{- toYaml . | nindent 2 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{- define "fluxer.waitFor" -}}
|
||||
{{- with .waitFor }}
|
||||
initContainers:
|
||||
- name: wait-for-dependencies
|
||||
image: {{ include "fluxer.thirdPartyImage" $.root.Values.initImage }}
|
||||
imagePullPolicy: {{ $.root.Values.initImage.pullPolicy }}
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- {{ printf "for t in %s; do until nc -z -w 2 ${t%%:*} ${t##*:}; do echo waiting for $t; sleep 2; done; done" (join " " .) | quote }}
|
||||
resources:
|
||||
requests:
|
||||
cpu: 10m
|
||||
memory: 16Mi
|
||||
limits:
|
||||
memory: 32Mi
|
||||
securityContext:
|
||||
runAsUser: 65532
|
||||
runAsGroup: 65532
|
||||
{{- include "fluxer.containerSecurityContext" . | nindent 6 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{- define "fluxer.appWaitFor" -}}
|
||||
{{- $out := list }}
|
||||
{{- if and .usesNats .root.Values.nats.enabled }}
|
||||
{{- $out = append $out "nats:4222" }}
|
||||
{{- end }}
|
||||
{{- if and .usesPostgres .root.Values.postgres.enabled }}
|
||||
{{- $out = append $out "postgres:5432" }}
|
||||
{{- end }}
|
||||
{{- if and .usesS3 .root.Values.seaweedfs.enabled }}
|
||||
{{- $out = append $out "seaweedfs:8333" }}
|
||||
{{- end }}
|
||||
{{- if and .usesKv .root.Values.valkey.enabled }}
|
||||
{{- $out = append $out "valkey:6379" }}
|
||||
{{- end }}
|
||||
{{- if .usesSvc }}
|
||||
{{- range $name := list "gifs" "messages" "snowflakes" "unfurl" "users" }}
|
||||
{{- $svc := get $.root.Values.svc $name | default dict }}
|
||||
{{- if gt (int (include "fluxer.replicas" (dict "w" ($svc.router | default dict)))) 0 }}
|
||||
{{- $out = append $out (printf "%s:8090" $name) }}
|
||||
{{- end }}
|
||||
{{- if gt (int (include "fluxer.replicas" (dict "w" ($svc.shard | default dict)))) 0 }}
|
||||
{{- $out = append $out (printf "%s-shard:8090" $name) }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- toJson $out }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,245 @@
|
||||
{{- define "fluxer.validate" -}}
|
||||
{{- if not (hasKey .Values "fluxerValidated") }}
|
||||
{{- $_ := set .Values "fluxerValidated" true }}
|
||||
{{- $v := .Values }}
|
||||
{{- if not (regexMatch "^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)+$" ($v.domain | default "")) }}
|
||||
{{- fail "domain must be set to the lowercase public hostname of the instance, for example --set domain=chat.example.com" }}
|
||||
{{- end }}
|
||||
{{- if not (has $v.scheme (list "http" "https")) }}
|
||||
{{- fail "scheme must be http or https" }}
|
||||
{{- end }}
|
||||
{{- if and $v.publicOrigin (not (regexMatch "^https?://[^/]+$" (trimSuffix "/" $v.publicOrigin))) }}
|
||||
{{- fail "publicOrigin must be a scheme, host and optional port, for example https://chat.example.com" }}
|
||||
{{- end }}
|
||||
{{- if not (regexMatch "^/[^/].*[^/]$|^/[^/]$" $v.adminBasePath) }}
|
||||
{{- fail "adminBasePath must start with a slash and must not end with one, for example /admin" }}
|
||||
{{- end }}
|
||||
{{- $extra := $v.secrets.extra | default dict }}
|
||||
{{- if and (not $v.postgres.enabled) (not $v.postgres.external.host) (not (get $extra "FLUXER_POSTGRES_URL")) (not $v.secrets.existingSecret) }}
|
||||
{{- fail "postgres.enabled is false, so set postgres.external.host or secrets.extra.FLUXER_POSTGRES_URL" }}
|
||||
{{- end }}
|
||||
{{- if and (not $v.valkey.enabled) (not $v.valkey.external.url) (not (get $extra "FLUXER_KV_URL")) (not $v.secrets.existingSecret) }}
|
||||
{{- fail "valkey.enabled is false, so set valkey.external.url or secrets.extra.FLUXER_KV_URL" }}
|
||||
{{- end }}
|
||||
{{- if and (not $v.nats.enabled) (not $v.nats.external.url) }}
|
||||
{{- fail "nats.enabled is false, so set nats.external.url" }}
|
||||
{{- end }}
|
||||
{{- if and (not $v.meilisearch.enabled) (not $v.meilisearch.external.url) }}
|
||||
{{- fail "meilisearch.enabled is false, so set meilisearch.external.url" }}
|
||||
{{- end }}
|
||||
{{- if and (not $v.seaweedfs.enabled) (not $v.s3.endpoint) }}
|
||||
{{- fail "seaweedfs.enabled is false, so set s3.endpoint to your S3 store" }}
|
||||
{{- end }}
|
||||
{{- if gt (int $v.nats.replicas) 1 }}
|
||||
{{- if lt (int $v.nats.replicas) 3 }}
|
||||
{{- fail "nats.replicas must be 1, or 3 or more for a JetStream cluster" }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if gt (int (include "fluxer.replicas" (dict "w" $v.worker))) 1 }}
|
||||
{{- fail "worker.replicas must be 1, because the worker runs the cron scheduler" }}
|
||||
{{- end }}
|
||||
{{- if not (has $v.livekit.expose (list "hostNetwork" "loadBalancer" "nodePort")) }}
|
||||
{{- fail "livekit.expose must be hostNetwork, loadBalancer or nodePort" }}
|
||||
{{- end }}
|
||||
{{- if and $v.livekit.enabled $v.livekit.external.url }}
|
||||
{{- fail "livekit.external.url names a LiveKit server of your own, so set livekit.enabled to false" }}
|
||||
{{- end }}
|
||||
{{- if and $v.livekit.external.url (not (regexMatch "^(wss?|https?)://[^/]+" ($v.livekit.external.publicUrl | default ""))) }}
|
||||
{{- fail "livekit.external.url is set, so set livekit.external.publicUrl to the address browsers use to reach that LiveKit server, for example wss://livekit.example.com" }}
|
||||
{{- end }}
|
||||
{{- if and $v.livekit.enabled (eq $v.livekit.expose "loadBalancer") (not $v.livekit.nodeIP) }}
|
||||
{{- fail "livekit.expose is loadBalancer, so reserve a public address before installing, set livekit.nodeIP to it, and pin the Service livekit-rtc to it with livekit.loadBalancerIP or livekit.serviceAnnotations. Use hostNetwork or nodePort where a load balancer cannot serve TCP and UDP on one address" }}
|
||||
{{- end }}
|
||||
{{- if not (has $v.edge.expose (list "ingress" "gateway" "loadBalancer" "none")) }}
|
||||
{{- fail "edge.expose must be ingress, gateway, loadBalancer or none" }}
|
||||
{{- end }}
|
||||
{{- if not (has $v.edge.ingress.tls.mode (list "certManager" "existingSecret" "none")) }}
|
||||
{{- fail "edge.ingress.tls.mode must be certManager, existingSecret or none" }}
|
||||
{{- end }}
|
||||
{{- if and (eq $v.edge.expose "gateway") (not $v.edge.gateway.parentRefs) }}
|
||||
{{- fail "edge.expose is gateway, so set edge.gateway.parentRefs to the Gateway the route attaches to" }}
|
||||
{{- end }}
|
||||
{{- if and (eq $v.edge.expose "loadBalancer") (ne $v.scheme "https") }}
|
||||
{{- fail "edge.expose loadBalancer serves HTTPS itself, so scheme must be https" }}
|
||||
{{- end }}
|
||||
{{- if and $v.networkPolicy.enabled $v.networkPolicy.ingressNamespaceSelector $v.livekit.enabled (eq $v.livekit.expose "hostNetwork") (not $v.livekit.nodeCIDRs) }}
|
||||
{{- fail "networkPolicy.ingressNamespaceSelector limits who reaches the edge, and LiveKit on the host network sends its webhook to the edge from a node address. Set livekit.nodeCIDRs to the address of the LiveKit node, for example 10.0.0.12/32" }}
|
||||
{{- end }}
|
||||
|
||||
{{- $placeholder := "(?i)change[_-]?me" }}
|
||||
{{- $secretName := "_(PASSWORD|SECRET|TOKEN|COOKIE|KEY|KEYS|KEY_BASE|SECRETS?_BASE64)$" }}
|
||||
{{- $credentialUrl := "://[^/@ ]*:[^/@ ]*@" }}
|
||||
{{- $plain := dict "env" ($v.env | default dict) "appProxy.config" ($v.appProxy.config | default dict) "edge.env" ($v.edge.env | default dict) }}
|
||||
{{- range $name := list "api" "worker" "gateway" "mediaProxy" "push" "admin" "appProxy" "staticProxy" }}
|
||||
{{- $_ := set $plain (printf "%s.env" $name) ((get $v $name).env | default dict) }}
|
||||
{{- end }}
|
||||
{{- range $name, $svc := $v.svc }}
|
||||
{{- range $part := list "router" "shard" }}
|
||||
{{- $_ := set $plain (printf "svc.%s.%s.env" $name $part) ((get ($svc | default dict) $part | default dict).env | default dict) }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- range $where, $map := $plain }}
|
||||
{{- range $k, $val := $map }}
|
||||
{{- $s := include "fluxer.string" ($val | default "") }}
|
||||
{{- if regexMatch $placeholder $s }}
|
||||
{{- fail (printf "%s.%s is a placeholder. Remove it or set a real value" $where $k) }}
|
||||
{{- end }}
|
||||
{{- if or (hasKey $v.secrets.values $k) (regexMatch $secretName $k) }}
|
||||
{{- fail (printf "%s.%s is a secret and would be stored in plain text. Set it in secrets.extra instead, or reference a Secret of your own from extraEnv" $where $k) }}
|
||||
{{- end }}
|
||||
{{- if regexMatch $credentialUrl $s }}
|
||||
{{- fail (printf "%s.%s is a URL that holds a password and would be stored in plain text. Set it in secrets.extra instead" $where $k) }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- range $k, $val := $v.secrets.values }}
|
||||
{{- if regexMatch $placeholder (include "fluxer.string" ($val | default "")) }}
|
||||
{{- fail (printf "secrets.values.%s is a placeholder. Leave it empty to generate a value, or set a real one" $k) }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- range $k, $val := $extra }}
|
||||
{{- if regexMatch $placeholder (include "fluxer.string" ($val | default "")) }}
|
||||
{{- fail (printf "secrets.extra.%s is a placeholder. Remove it or set a real value" $k) }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{- $connected := false }}
|
||||
{{- if $v.clusterChecks }}
|
||||
{{- $connected = or (lookup "v1" "Namespace" "" .Release.Namespace) (lookup "v1" "Namespace" "" "kube-system") | not | not }}
|
||||
{{- end }}
|
||||
{{- $data := include "fluxer.secretData" . | fromJson }}
|
||||
{{- $secret := include "fluxer.secretName" . }}
|
||||
{{- if $v.secrets.existingSecret }}
|
||||
{{- if and $connected (not $data) }}
|
||||
{{- fail (printf "secrets.existingSecret names the Secret %s, which does not exist in namespace %s. Create it first with every key listed under secrets.values" $secret .Release.Namespace) }}
|
||||
{{- end }}
|
||||
{{- if $data }}
|
||||
{{- $missing := list }}
|
||||
{{- range $k := include "fluxer.requiredSecretKeys" . | fromJsonArray }}
|
||||
{{- if not (get $data $k) }}
|
||||
{{- $missing = append $missing $k }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- with $missing }}
|
||||
{{- fail (printf "Secret %s is missing these keys: %s" $secret (join ", " .)) }}
|
||||
{{- end }}
|
||||
{{- $config := include "fluxer.configData" . | fromYaml }}
|
||||
{{- if $v.valkey.enabled }}
|
||||
{{- $_ := set $config "FLUXER_KV_URL" "the bundled Valkey" }}
|
||||
{{- end }}
|
||||
{{- $shadowed := list }}
|
||||
{{- range $k := keys $config | sortAlpha }}
|
||||
{{- if and (hasKey $data $k) (ne (get $data $k) (get $config $k)) }}
|
||||
{{- $shadowed = append $shadowed $k }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- with $shadowed }}
|
||||
{{- fail (printf "Secret %s holds settings the chart sets itself, and the two disagree: %s. Remove them from the Secret. To keep an outside service, turn the bundled one off, as the External services section of the Kubernetes page describes" $secret (join ", " .)) }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if $data }}
|
||||
{{- range $k, $val := $data }}
|
||||
{{- if regexMatch $placeholder $val }}
|
||||
{{- fail (printf "%s in the Secret %s is a placeholder. Set a real value" $k $secret) }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- with get $data "FLUXER_MEDIA_PROXY_UPLOAD_RELAY_SECRET_BASE64" }}
|
||||
{{- if or (not (regexMatch "^[A-Za-z0-9+/]+={0,2}$" .)) (lt (len (b64dec .)) 32) }}
|
||||
{{- fail "FLUXER_MEDIA_PROXY_UPLOAD_RELAY_SECRET_BASE64 must be standard base64 of at least 32 bytes, for example the output of openssl rand -base64 32" }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- $long := list "FLUXER_SUDO_MODE_SECRET" "FLUXER_CONNECTION_INITIATION_SECRET" "FLUXER_PROFILE_PSEUDONYM_SECRET" "FLUXER_GATEWAY_RPC_AUTH_TOKEN" "FLUXER_ERLANG_COOKIE" "FLUXER_MEDIA_PROXY_SECRET_KEY" "FLUXER_ADMIN_SECRET_KEY_BASE" "FLUXER_ADMIN_OAUTH_CLIENT_SECRET" "FLUXER_SETUP_TOKEN" }}
|
||||
{{- if ne (include "fluxer.livekitMode" .) "off" }}
|
||||
{{- $long = append $long "FLUXER_LIVEKIT_API_SECRET" }}
|
||||
{{- end }}
|
||||
{{- if $v.valkey.enabled }}
|
||||
{{- $long = append $long "FLUXER_VALKEY_PASSWORD" }}
|
||||
{{- end }}
|
||||
{{- if $v.nats.enabled }}
|
||||
{{- $long = append $long "FLUXER_NATS_AUTH_TOKEN" }}
|
||||
{{- end }}
|
||||
{{- range $k := $long }}
|
||||
{{- if and (hasKey $data $k) (lt (len (get $data $k)) 32) }}
|
||||
{{- fail (printf "%s must be at least 32 characters, for example the output of openssl rand -hex 32" $k) }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if and $v.meilisearch.enabled (hasKey $data "FLUXER_SEARCH_API_KEY") (lt (len (get $data "FLUXER_SEARCH_API_KEY")) 16) }}
|
||||
{{- fail "FLUXER_SEARCH_API_KEY must be at least 16 characters, or the bundled Meilisearch refuses to start" }}
|
||||
{{- end }}
|
||||
{{- if eq (get $data "FLUXER_POSTGRES_PASSWORD" | default "") "fluxer" }}
|
||||
{{- fail "FLUXER_POSTGRES_PASSWORD must not be fluxer, which the services refuse in production" }}
|
||||
{{- end }}
|
||||
{{- $plainOnly := list }}
|
||||
{{- if $v.seaweedfs.enabled }}
|
||||
{{- $plainOnly = concat $plainOnly (list "FLUXER_S3_ACCESS_KEY_ID" "FLUXER_S3_SECRET_ACCESS_KEY") }}
|
||||
{{- end }}
|
||||
{{- if $v.valkey.enabled }}
|
||||
{{- $plainOnly = append $plainOnly "FLUXER_VALKEY_PASSWORD" }}
|
||||
{{- end }}
|
||||
{{- if $v.nats.enabled }}
|
||||
{{- $plainOnly = append $plainOnly "FLUXER_NATS_AUTH_TOKEN" }}
|
||||
{{- end }}
|
||||
{{- range $k := $plainOnly }}
|
||||
{{- if and (hasKey $data $k) (not (regexMatch "^[A-Za-z0-9]+$" (get $data $k))) }}
|
||||
{{- fail (printf "%s must contain letters and digits only, because the bundled service takes it on a command line or in a URL" $k) }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- $pub := get $data "FLUXER_VAPID_PUBLIC_KEY" | default "" }}
|
||||
{{- $priv := get $data "FLUXER_VAPID_PRIVATE_KEY" | default "" }}
|
||||
{{- if or $pub $priv }}
|
||||
{{- if or (not (regexMatch "^[A-Za-z0-9_-]{87}$" $pub)) (not (regexMatch "^[A-Za-z0-9_-]{43}$" $priv)) }}
|
||||
{{- fail "FLUXER_VAPID_PUBLIC_KEY and FLUXER_VAPID_PRIVATE_KEY must be an unpadded base64url P-256 pair of 87 and 43 characters" }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{- if $connected }}
|
||||
{{- if and (eq $v.edge.expose "ingress") (eq $v.edge.ingress.tls.mode "certManager") (not (.Capabilities.APIVersions.Has "cert-manager.io/v1")) }}
|
||||
{{- fail "edge.ingress.tls.mode is certManager, but cert-manager is not installed. Install cert-manager, or set edge.ingress.tls.mode to existingSecret or none, or set edge.expose to loadBalancer so the edge obtains its own certificate" }}
|
||||
{{- end }}
|
||||
{{- if and (eq $v.edge.expose "gateway") (not (.Capabilities.APIVersions.Has "gateway.networking.k8s.io/v1")) }}
|
||||
{{- fail "edge.expose is gateway, but the Gateway API is not installed in the cluster" }}
|
||||
{{- end }}
|
||||
{{- $emptyClass := and (eq $v.edge.expose "loadBalancer") (not $v.edge.loadBalancer.persistence.storageClassName) }}
|
||||
{{- range $c := list $v.postgres $v.valkey $v.nats $v.meilisearch $v.seaweedfs }}
|
||||
{{- if and $c.enabled (not $c.persistence.storageClassName) }}
|
||||
{{- $emptyClass = true }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if $emptyClass }}
|
||||
{{- $default := false }}
|
||||
{{- range (lookup "storage.k8s.io/v1" "StorageClass" "" "").items | default list }}
|
||||
{{- if eq (get (.metadata.annotations | default dict) "storageclass.kubernetes.io/is-default-class") "true" }}
|
||||
{{- $default = true }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if not $default }}
|
||||
{{- fail "The cluster has no default StorageClass, so the volumes would never bind. Install a storage provisioner and mark its class as default, or set persistence.storageClassName on postgres, valkey, nats, meilisearch and seaweedfs" }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if and (eq $v.edge.expose "ingress") (not $v.edge.ingress.className) }}
|
||||
{{- $classes := (lookup "networking.k8s.io/v1" "IngressClass" "" "").items | default list }}
|
||||
{{- if not $classes }}
|
||||
{{- fail "The cluster has no IngressClass, so nothing would serve the Ingress. Install an ingress controller, or set edge.expose to loadBalancer, gateway or none. Set clusterChecks to false if your controller serves an Ingress without a class" }}
|
||||
{{- end }}
|
||||
{{- $defaults := list }}
|
||||
{{- range $classes }}
|
||||
{{- if eq (get (.metadata.annotations | default dict) "ingressclass.kubernetes.io/is-default-class") "true" }}
|
||||
{{- $defaults = append $defaults .metadata.name }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if not $defaults }}
|
||||
{{- $names := list }}
|
||||
{{- range $classes }}
|
||||
{{- $names = append $names .metadata.name }}
|
||||
{{- end }}
|
||||
{{- fail (printf "The cluster has no default IngressClass. Set edge.ingress.className to one of: %s" (join ", " $names)) }}
|
||||
{{- end }}
|
||||
{{- if gt (len $defaults) 1 }}
|
||||
{{- fail (printf "The cluster marks more than one IngressClass as default (%s), so the Ingress may land on the wrong controller. Set edge.ingress.className" (join ", " $defaults)) }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,188 @@
|
||||
{{- define "fluxer.replicas" -}}
|
||||
{{- $w := .w | default dict }}
|
||||
{{- if kindIs "invalid" $w.replicas }}1{{ else }}{{ $w.replicas | int }}{{ end }}
|
||||
{{- end }}
|
||||
|
||||
{{- define "fluxer.appPod" -}}
|
||||
{{- $root := .root }}
|
||||
{{- $w := .w | default dict }}
|
||||
{{- $readsSecret := and (not .noEnvFrom) (not .configMapOnly) }}
|
||||
{{- $env := .env | default list }}
|
||||
{{- if and $readsSecret $root.Values.valkey.enabled }}
|
||||
{{- $env = prepend $env (dict "name" "FLUXER_KV_URL" "value" "redis://:$(FLUXER_VALKEY_PASSWORD)@valkey:6379/0") }}
|
||||
{{- end }}
|
||||
metadata:
|
||||
labels:
|
||||
{{- include "fluxer.podLabels" . | nindent 4 }}
|
||||
annotations:
|
||||
checksum/instance: {{ include "fluxer.instanceChecksum" $root }}
|
||||
{{- with $w.podAnnotations }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
automountServiceAccountToken: false
|
||||
enableServiceLinks: false
|
||||
{{- include "fluxer.pullSecrets" $root | nindent 2 }}
|
||||
securityContext:
|
||||
{{- include "fluxer.podSecurityContext" (dict) | nindent 4 }}
|
||||
{{- include "fluxer.scheduling" . | nindent 2 }}
|
||||
{{- with $w.terminationGracePeriodSeconds }}
|
||||
terminationGracePeriodSeconds: {{ . }}
|
||||
{{- end }}
|
||||
{{- include "fluxer.waitFor" . | nindent 2 }}
|
||||
containers:
|
||||
- name: {{ .containerName | default .name }}
|
||||
image: {{ include "fluxer.image" . }}
|
||||
imagePullPolicy: {{ include "fluxer.pullPolicy" . }}
|
||||
{{- with .command }}
|
||||
command:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with include "fluxer.envList" (dict "w" $w "env" $env) }}
|
||||
env:
|
||||
{{- . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- if not .noEnvFrom }}
|
||||
envFrom:
|
||||
{{- if .configMapOnly }}
|
||||
- configMapRef:
|
||||
name: {{ .configMapOnly }}
|
||||
{{- else }}
|
||||
- configMapRef:
|
||||
name: fluxer-config
|
||||
- secretRef:
|
||||
name: {{ include "fluxer.secretName" $root }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: {{ .port }}
|
||||
protocol: TCP
|
||||
{{- range .extraPorts }}
|
||||
- name: {{ .name }}
|
||||
containerPort: {{ .port }}
|
||||
protocol: TCP
|
||||
{{- end }}
|
||||
{{- with include "fluxer.probes" . | trim }}
|
||||
{{- . | nindent 6 }}
|
||||
{{- end }}
|
||||
{{- with .lifecycle }}
|
||||
lifecycle:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with $w.resources }}
|
||||
resources:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
securityContext:
|
||||
{{- include "fluxer.containerSecurityContext" . | nindent 8 }}
|
||||
{{- with concat (.volumeMounts | default list) ($w.extraVolumeMounts | default list) }}
|
||||
volumeMounts:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with concat (.volumes | default list) ($w.extraVolumes | default list) }}
|
||||
volumes:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{- define "fluxer.app" -}}
|
||||
{{- $root := .root }}
|
||||
{{- $w := .w | default dict }}
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: {{ .kind | default "Deployment" }}
|
||||
metadata:
|
||||
name: {{ .name }}
|
||||
namespace: {{ $root.Release.Namespace }}
|
||||
labels:
|
||||
{{- include "fluxer.labels" . | nindent 4 }}
|
||||
spec:
|
||||
{{- if not (and $w.hpa $w.hpa.maxReplicas) }}
|
||||
replicas: {{ include "fluxer.replicas" . }}
|
||||
{{- end }}
|
||||
revisionHistoryLimit: 3
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "fluxer.selectorLabels" . | nindent 6 }}
|
||||
{{- if eq (.kind | default "Deployment") "StatefulSet" }}
|
||||
serviceName: {{ .serviceName }}
|
||||
podManagementPolicy: Parallel
|
||||
{{- else if .strategy }}
|
||||
strategy:
|
||||
{{- toYaml .strategy | nindent 4 }}
|
||||
{{- end }}
|
||||
template:
|
||||
{{- include "fluxer.appPod" . | nindent 4 }}
|
||||
{{- if not .noService }}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ .name }}
|
||||
namespace: {{ $root.Release.Namespace }}
|
||||
labels:
|
||||
{{- include "fluxer.labels" . | nindent 4 }}
|
||||
spec:
|
||||
type: ClusterIP
|
||||
{{- if .headless }}
|
||||
clusterIP: None
|
||||
publishNotReadyAddresses: true
|
||||
{{- end }}
|
||||
selector:
|
||||
{{- include "fluxer.selectorLabels" . | nindent 4 }}
|
||||
ports:
|
||||
- name: http
|
||||
port: {{ .servicePort | default .port }}
|
||||
targetPort: http
|
||||
protocol: TCP
|
||||
{{- end }}
|
||||
{{- with $w.pdb }}
|
||||
{{- if or (not (kindIs "invalid" .minAvailable)) (not (kindIs "invalid" .maxUnavailable)) }}
|
||||
---
|
||||
apiVersion: policy/v1
|
||||
kind: PodDisruptionBudget
|
||||
metadata:
|
||||
name: {{ $.name }}
|
||||
namespace: {{ $root.Release.Namespace }}
|
||||
labels:
|
||||
{{- include "fluxer.labels" $ | nindent 4 }}
|
||||
spec:
|
||||
{{- if not (kindIs "invalid" .minAvailable) }}
|
||||
minAvailable: {{ .minAvailable }}
|
||||
{{- end }}
|
||||
{{- if not (kindIs "invalid" .maxUnavailable) }}
|
||||
maxUnavailable: {{ .maxUnavailable }}
|
||||
{{- end }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "fluxer.selectorLabels" $ | nindent 6 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- with $w.hpa }}
|
||||
{{- if .maxReplicas }}
|
||||
---
|
||||
apiVersion: autoscaling/v2
|
||||
kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
name: {{ $.name }}
|
||||
namespace: {{ $root.Release.Namespace }}
|
||||
labels:
|
||||
{{- include "fluxer.labels" $ | nindent 4 }}
|
||||
spec:
|
||||
scaleTargetRef:
|
||||
apiVersion: apps/v1
|
||||
kind: {{ $.kind | default "Deployment" }}
|
||||
name: {{ $.name }}
|
||||
minReplicas: {{ .minReplicas | default 1 }}
|
||||
maxReplicas: {{ .maxReplicas }}
|
||||
metrics:
|
||||
- type: Resource
|
||||
resource:
|
||||
name: cpu
|
||||
target:
|
||||
type: Utilization
|
||||
averageUtilization: {{ .targetCPUUtilizationPercentage | default 80 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,90 @@
|
||||
{{- include "fluxer.validate" . }}
|
||||
{{- $v := .Values }}
|
||||
{{- $o := include "fluxer.origin" . }}
|
||||
{{- $http := dict "port" "http" }}
|
||||
{{- $start := dict "periodSeconds" 10 "timeoutSeconds" 5 "failureThreshold" 30 }}
|
||||
{{- $check := dict "periodSeconds" 10 "timeoutSeconds" 5 "failureThreshold" 3 }}
|
||||
{{- $health := merge (dict "path" "/_health") $http }}
|
||||
{{- $healthProbes := dict "startup" (merge (dict "httpGet" $health) $start) "liveness" (merge (dict "httpGet" $health) $check) "readiness" (merge (dict "httpGet" $health) $check) }}
|
||||
{{- $nodeEnv := list (dict "name" "NODE_ENV" "value" "production") (dict "name" "NODE_OPTIONS" "value" "--enable-source-maps") (dict "name" "NODE_EXTRA_CA_CERTS" "value" "/etc/ssl/certs/ca-certificates.crt") (dict "name" "FLUXER_POSTGRES_MAX_CONNECTIONS" "value" "25") }}
|
||||
|
||||
{{- include "fluxer.app" (dict "root" . "name" "api" "component" "api" "w" $v.api "image" "fluxer-api" "port" 8080
|
||||
"env" (concat (list (dict "name" "FLUXER_API_PORT" "value" "8080") (dict "name" "FLUXER_API_PRESIGNED_ATTACHMENT_UPLOADS_ENABLED" "value" "true")) $nodeEnv)
|
||||
"probes" $healthProbes
|
||||
"waitFor" (include "fluxer.appWaitFor" (dict "root" . "usesNats" true "usesPostgres" true "usesS3" true "usesKv" true "usesSvc" true) | fromJsonArray)) }}
|
||||
|
||||
{{- $heartbeat := dict "exec" (dict "command" (list "node" "-e" "const age=Date.now()-require('node:fs').statSync('/tmp/fluxer-worker-heartbeat').mtimeMs;if(age>30000){console.error('worker heartbeat is '+Math.round(age)+'ms old');process.exit(1)}")) "initialDelaySeconds" 90 "periodSeconds" 10 "timeoutSeconds" 5 "failureThreshold" 3 }}
|
||||
{{- include "fluxer.app" (dict "root" . "name" "worker" "component" "worker" "w" $v.worker "image" "fluxer-api" "port" 8080 "noService" true
|
||||
"command" (list "node" "dist/WorkerEntrypoint.js")
|
||||
"env" (concat (list (dict "name" "FLUXER_API_WORKER_MODE" "value" "all_lanes") (dict "name" "FLUXER_API_WORKER_ENABLE_CRON_SCHEDULER" "value" "true")) $nodeEnv)
|
||||
"probes" (dict "liveness" $heartbeat)
|
||||
"strategy" (dict "type" "Recreate")
|
||||
"waitFor" (include "fluxer.appWaitFor" (dict "root" . "usesNats" true "usesPostgres" true "usesS3" true "usesKv" true "usesSvc" true) | fromJsonArray)) }}
|
||||
|
||||
{{- $gatewayEnv := list
|
||||
(dict "name" "FLUXER_GATEWAY_PORT" "value" "8080")
|
||||
(dict "name" "FLUXER_GATEWAY_ROLE" "value" "all")
|
||||
(dict "name" "POD_IP" "valueFrom" (dict "fieldRef" (dict "apiVersion" "v1" "fieldPath" "status.podIP")))
|
||||
(dict "name" "FLUXER_ERLANG_NODE_NAME" "value" "fluxer_gateway@$(POD_IP)")
|
||||
(dict "name" "FLUXER_ERLANG_DIST_PORT" "value" "8081")
|
||||
(dict "name" "FLUXER_GATEWAY_CLUSTER_ENABLED" "value" "true")
|
||||
(dict "name" "FLUXER_GATEWAY_CLUSTER_DISCOVERY_DNS_NAME" "value" (printf "gateway-headless.%s.svc.%s" .Release.Namespace $v.clusterDomain))
|
||||
(dict "name" "FLUXER_GATEWAY_CLUSTER_DISCOVERY_NODE_BASENAME" "value" "fluxer_gateway") }}
|
||||
{{- $gatewayReady := dict "exec" (dict "command" (list "curl" "-fsS" "-o" "/dev/null" "--max-time" "4" "http://127.0.0.1:8080/_health/ready")) "periodSeconds" 10 "timeoutSeconds" 5 "failureThreshold" 3 }}
|
||||
{{- $gatewayCtx := dict "root" . "name" "gateway" "component" "gateway" "w" $v.gateway "image" "fluxer-gateway" "port" 8080
|
||||
"extraPorts" (list (dict "name" "epmd" "port" 4369) (dict "name" "erl-dist" "port" 8081))
|
||||
"env" $gatewayEnv
|
||||
"probes" (dict "startup" (merge (dict "httpGet" $health) $start) "liveness" (merge (dict "httpGet" $health) $check) "readiness" $gatewayReady)
|
||||
"waitFor" (include "fluxer.appWaitFor" (dict "root" . "usesNats" true) | fromJsonArray)
|
||||
"lifecycle" (dict "preStop" (dict "exec" (dict "command" (list "/bin/sh" "-c" "curl -fsS -o /dev/null --max-time 2 http://127.0.0.1:8080/_health/drain; sleep 5")))) }}
|
||||
{{- include "fluxer.app" $gatewayCtx }}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: gateway-headless
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "fluxer.labels" $gatewayCtx | nindent 4 }}
|
||||
spec:
|
||||
type: ClusterIP
|
||||
clusterIP: None
|
||||
publishNotReadyAddresses: true
|
||||
selector:
|
||||
{{- include "fluxer.selectorLabels" $gatewayCtx | nindent 4 }}
|
||||
ports:
|
||||
- name: http
|
||||
port: 8080
|
||||
targetPort: http
|
||||
protocol: TCP
|
||||
- name: epmd
|
||||
port: 4369
|
||||
targetPort: epmd
|
||||
protocol: TCP
|
||||
- name: erl-dist
|
||||
port: 8081
|
||||
targetPort: erl-dist
|
||||
protocol: TCP
|
||||
|
||||
{{- include "fluxer.app" (dict "root" . "name" "media-proxy" "component" "media" "w" $v.mediaProxy "image" "fluxer-media-proxy" "port" 8080
|
||||
"env" (list (dict "name" "FLUXER_MEDIA_PROXY_PORT" "value" "8080") (dict "name" "FLUXER_MEDIA_PROXY_MODE" "value" "upload") (dict "name" "FLUXER_MEDIA_PROXY_STORAGE_BACKEND" "value" "s3") (dict "name" "FLUXER_S3_READ_SIGNED" "value" "true"))
|
||||
"probes" $healthProbes
|
||||
"waitFor" (include "fluxer.appWaitFor" (dict "root" . "usesNats" true "usesS3" true) | fromJsonArray)) }}
|
||||
|
||||
{{- $pushCheck := dict "exec" (dict "command" (list "/usr/local/bin/fluxer-push" "healthcheck")) }}
|
||||
{{- include "fluxer.app" (dict "root" . "name" "push" "component" "push" "w" $v.push "image" "fluxer-push" "port" 8126
|
||||
"env" (list (dict "name" "FLUXER_PUSH_SERVICE_PORT" "value" "8126"))
|
||||
"waitFor" (include "fluxer.appWaitFor" (dict "root" . "usesNats" true) | fromJsonArray)
|
||||
"probes" (dict "startup" (merge (deepCopy $pushCheck) (dict "periodSeconds" 10 "timeoutSeconds" 5 "failureThreshold" 12)) "liveness" (merge (deepCopy $pushCheck) $check) "readiness" (merge (deepCopy $pushCheck) $check))) }}
|
||||
|
||||
{{- include "fluxer.app" (dict "root" . "name" "admin" "component" "admin" "w" $v.admin "image" "fluxer-admin" "port" 8080
|
||||
"env" (list (dict "name" "FLUXER_ADMIN_PORT" "value" "8080") (dict "name" "FLUXER_ADMIN_BASE_PATH" "value" $v.adminBasePath) (dict "name" "FLUXER_API_ENDPOINT" "value" "http://api:8080") (dict "name" "FLUXER_STATIC_CDN_ENDPOINT" "value" $o))
|
||||
"probes" $healthProbes) }}
|
||||
|
||||
{{- $ready := merge (dict "path" "/_ready") $http }}
|
||||
{{- include "fluxer.app" (dict "root" . "name" "app-proxy" "component" "web" "w" $v.appProxy "image" "fluxer-app-proxy-self-hosted" "port" 8080 "configMapOnly" "fluxer-app-proxy"
|
||||
"probes" (dict "startup" (merge (dict "httpGet" $health) $start) "liveness" (merge (dict "httpGet" $health) $check) "readiness" (merge (dict "httpGet" $ready) $check))) }}
|
||||
|
||||
{{- $avatar := merge (dict "path" "/avatars/0.png") $http }}
|
||||
{{- include "fluxer.app" (dict "root" . "name" "static-proxy" "component" "web" "w" $v.staticProxy "image" "fluxer-static" "port" 8080 "noEnvFrom" true
|
||||
"probes" (dict "startup" (merge (dict "httpGet" $avatar) $start) "liveness" (merge (dict "httpGet" $avatar) $check) "readiness" (merge (dict "httpGet" $avatar) $check))) }}
|
||||
@@ -0,0 +1,20 @@
|
||||
{{- include "fluxer.validate" . }}
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: fluxer-config
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "fluxer.labels" (dict "root" . "name" "fluxer-config" "component" "config") | nindent 4 }}
|
||||
data:
|
||||
{{- include "fluxer.configData" . | nindent 2 }}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: fluxer-app-proxy
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "fluxer.labels" (dict "root" . "name" "fluxer-app-proxy" "component" "config") | nindent 4 }}
|
||||
data:
|
||||
{{- include "fluxer.appProxyConfigData" . | nindent 2 }}
|
||||
@@ -0,0 +1,296 @@
|
||||
{{- include "fluxer.validate" . }}
|
||||
{{- $v := .Values }}
|
||||
{{- $e := $v.edge }}
|
||||
{{- $ctx := dict "root" . "name" "edge" "component" "edge" "w" $e }}
|
||||
{{- $lb := eq $e.expose "loadBalancer" }}
|
||||
{{- $caddyfile := .Files.Get "files/Caddyfile" }}
|
||||
{{- $globalOptions := ternary (printf "email %s" $v.email) "" (and $lb (ne $v.email "")) }}
|
||||
{{- $siteAddress := ternary (printf "https://%s, :8080" $v.domain) ":8080" $lb }}
|
||||
{{- $trusted := ternary "127.0.0.1/32" "private_ranges" $lb }}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: edge-caddyfile
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "fluxer.labels" $ctx | nindent 4 }}
|
||||
data:
|
||||
Caddyfile: {{ $caddyfile | quote }}
|
||||
{{- if $lb }}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: edge-data
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "fluxer.labels" $ctx | nindent 4 }}
|
||||
annotations:
|
||||
helm.sh/resource-policy: keep
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
{{- with $e.loadBalancer.persistence.storageClassName }}
|
||||
storageClassName: {{ . }}
|
||||
{{- end }}
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ $e.loadBalancer.persistence.size }}
|
||||
{{- end }}
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: edge
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "fluxer.labels" $ctx | nindent 4 }}
|
||||
spec:
|
||||
replicas: {{ ternary 1 ($e.replicas | int) $lb }}
|
||||
revisionHistoryLimit: 3
|
||||
{{- if $lb }}
|
||||
strategy:
|
||||
type: Recreate
|
||||
{{- end }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "fluxer.selectorLabels" $ctx | nindent 6 }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
{{- include "fluxer.podLabels" $ctx | nindent 8 }}
|
||||
annotations:
|
||||
checksum/config: {{ printf "%s\n%s\n%s\n%s" $caddyfile $siteAddress $globalOptions (toJson (list $e.env $e.extraEnv)) | sha256sum }}
|
||||
{{- with $e.podAnnotations }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
automountServiceAccountToken: false
|
||||
enableServiceLinks: false
|
||||
{{- include "fluxer.pullSecrets" . | nindent 6 }}
|
||||
securityContext:
|
||||
{{- include "fluxer.podSecurityContext" (dict "uid" 65532) | nindent 8 }}
|
||||
{{- if $lb }}
|
||||
sysctls:
|
||||
- name: net.ipv4.ip_unprivileged_port_start
|
||||
value: "0"
|
||||
{{- end }}
|
||||
{{- include "fluxer.scheduling" $ctx | nindent 6 }}
|
||||
containers:
|
||||
- name: edge
|
||||
image: {{ include "fluxer.thirdPartyImage" $e.image }}
|
||||
imagePullPolicy: {{ $e.image.pullPolicy }}
|
||||
{{- $edgeEnv := list (dict "name" "FLUXER_EDGE_SITE_ADDRESS" "value" $siteAddress) (dict "name" "FLUXER_EDGE_TRUSTED_PROXIES" "value" $trusted) (dict "name" "FLUXER_EDGE_GLOBAL_OPTIONS" "value" $globalOptions) (dict "name" "FLUXER_ADMIN_BASE_PATH" "value" $v.adminBasePath) }}
|
||||
env:
|
||||
{{- include "fluxer.envList" (dict "w" $e "env" $edgeEnv) | nindent 12 }}
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 8080
|
||||
protocol: TCP
|
||||
{{- if $lb }}
|
||||
- name: public-http
|
||||
containerPort: 80
|
||||
protocol: TCP
|
||||
- name: public-https
|
||||
containerPort: 443
|
||||
protocol: TCP
|
||||
- name: public-quic
|
||||
containerPort: 443
|
||||
protocol: UDP
|
||||
{{- end }}
|
||||
startupProbe:
|
||||
exec:
|
||||
command: ["wget", "-q", "-O", "/dev/null", "http://127.0.0.1:2019/config/"]
|
||||
periodSeconds: 5
|
||||
failureThreshold: 24
|
||||
livenessProbe:
|
||||
exec:
|
||||
command: ["wget", "-q", "-O", "/dev/null", "http://127.0.0.1:2019/config/"]
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 5
|
||||
failureThreshold: 6
|
||||
readinessProbe:
|
||||
exec:
|
||||
command: ["wget", "-q", "-O", "/dev/null", "http://127.0.0.1:2019/config/"]
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 5
|
||||
{{- with $e.resources }}
|
||||
resources:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
readOnlyRootFilesystem: true
|
||||
capabilities:
|
||||
drop:
|
||||
- ALL
|
||||
add:
|
||||
- NET_BIND_SERVICE
|
||||
volumeMounts:
|
||||
- name: caddyfile
|
||||
mountPath: /etc/caddy
|
||||
readOnly: true
|
||||
- name: config
|
||||
mountPath: /config
|
||||
- name: data
|
||||
mountPath: /data
|
||||
volumes:
|
||||
- name: caddyfile
|
||||
configMap:
|
||||
name: edge-caddyfile
|
||||
- name: config
|
||||
emptyDir: {}
|
||||
- name: data
|
||||
{{- if $lb }}
|
||||
persistentVolumeClaim:
|
||||
claimName: edge-data
|
||||
{{- else }}
|
||||
emptyDir: {}
|
||||
{{- end }}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: edge
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "fluxer.labels" $ctx | nindent 4 }}
|
||||
spec:
|
||||
type: ClusterIP
|
||||
selector:
|
||||
{{- include "fluxer.selectorLabels" $ctx | nindent 4 }}
|
||||
ports:
|
||||
- name: http
|
||||
port: 8080
|
||||
targetPort: http
|
||||
protocol: TCP
|
||||
{{- if $lb }}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: edge-public
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "fluxer.labels" $ctx | nindent 4 }}
|
||||
{{- with $e.loadBalancer.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
type: LoadBalancer
|
||||
externalTrafficPolicy: Local
|
||||
selector:
|
||||
{{- include "fluxer.selectorLabels" $ctx | nindent 4 }}
|
||||
ports:
|
||||
- name: http
|
||||
port: 80
|
||||
targetPort: public-http
|
||||
protocol: TCP
|
||||
- name: https
|
||||
port: 443
|
||||
targetPort: public-https
|
||||
protocol: TCP
|
||||
{{- if $e.loadBalancer.http3 }}
|
||||
- name: quic
|
||||
port: 443
|
||||
targetPort: public-quic
|
||||
protocol: UDP
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if eq $e.expose "ingress" }}
|
||||
{{- $tls := $e.ingress.tls }}
|
||||
{{- $annotations := dict
|
||||
"nginx.ingress.kubernetes.io/proxy-body-size" "512m"
|
||||
"nginx.ingress.kubernetes.io/proxy-read-timeout" "3600"
|
||||
"nginx.ingress.kubernetes.io/proxy-send-timeout" "3600" }}
|
||||
{{- if eq $tls.mode "certManager" }}
|
||||
{{- $_ := set $annotations "cert-manager.io/issuer" "fluxer-acme" }}
|
||||
---
|
||||
apiVersion: cert-manager.io/v1
|
||||
kind: Issuer
|
||||
metadata:
|
||||
name: fluxer-acme
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "fluxer.labels" $ctx | nindent 4 }}
|
||||
spec:
|
||||
acme:
|
||||
server: {{ $tls.acmeServer }}
|
||||
{{- with $v.email }}
|
||||
email: {{ . }}
|
||||
{{- end }}
|
||||
privateKeySecretRef:
|
||||
name: fluxer-acme-account
|
||||
solvers:
|
||||
- http01:
|
||||
{{- with $e.ingress.className }}
|
||||
ingress:
|
||||
ingressClassName: {{ . }}
|
||||
{{- else }}
|
||||
ingress: {}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- $annotations = merge (deepCopy ($e.ingress.annotations | default dict)) $annotations }}
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: fluxer
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "fluxer.labels" $ctx | nindent 4 }}
|
||||
{{- with $annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- with $e.ingress.className }}
|
||||
ingressClassName: {{ . }}
|
||||
{{- end }}
|
||||
{{- if ne $tls.mode "none" }}
|
||||
tls:
|
||||
- hosts:
|
||||
- {{ $v.domain }}
|
||||
secretName: {{ $tls.secretName }}
|
||||
{{- end }}
|
||||
rules:
|
||||
- host: {{ $v.domain }}
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: edge
|
||||
port:
|
||||
name: http
|
||||
{{- end }}
|
||||
{{- if eq $e.expose "gateway" }}
|
||||
---
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
kind: HTTPRoute
|
||||
metadata:
|
||||
name: fluxer
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "fluxer.labels" $ctx | nindent 4 }}
|
||||
spec:
|
||||
parentRefs:
|
||||
{{- toYaml $e.gateway.parentRefs | nindent 4 }}
|
||||
hostnames:
|
||||
- {{ $v.domain }}
|
||||
rules:
|
||||
- matches:
|
||||
- path:
|
||||
type: PathPrefix
|
||||
value: /
|
||||
backendRefs:
|
||||
- name: edge
|
||||
port: 8080
|
||||
{{- with $e.gateway.timeouts }}
|
||||
timeouts:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,156 @@
|
||||
{{- include "fluxer.validate" . }}
|
||||
{{- with .Values.livekit }}
|
||||
{{- if .enabled }}
|
||||
{{- $ctx := dict "root" $ "name" "livekit" "component" "voice" "w" . }}
|
||||
{{- $tcp := .tcpPort | int }}
|
||||
{{- $udp := .udpPort | int }}
|
||||
{{- if eq .expose "nodePort" }}
|
||||
{{- $tcp = .nodePorts.tcp | int }}
|
||||
{{- $udp = .nodePorts.udp | int }}
|
||||
{{- end }}
|
||||
{{- $useExternal := and .useExternalIP (ne .expose "loadBalancer") }}
|
||||
{{- $secrets := include "fluxer.secretData" $ | fromJson }}
|
||||
{{- $config := dict
|
||||
"port" 7880
|
||||
"log_level" .logLevel
|
||||
"rtc" (dict "tcp_port" $tcp "udp_port" $udp "use_external_ip" $useExternal "node_ip" (.nodeIP | default "") "stun_servers" .stunServers) }}
|
||||
{{- $config = mergeOverwrite $config (deepCopy (.extraConfig | default dict)) }}
|
||||
{{- $configYaml := toYaml $config }}
|
||||
{{- $root := dict "path" "/" "port" "http" }}
|
||||
{{- $webhook := ternary "http://edge:8080/api/webhooks/livekit" "http://api:8080/webhooks/livekit" (eq .expose "hostNetwork") }}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: livekit
|
||||
namespace: {{ $.Release.Namespace }}
|
||||
labels:
|
||||
{{- include "fluxer.labels" $ctx | nindent 4 }}
|
||||
spec:
|
||||
type: ClusterIP
|
||||
selector:
|
||||
{{- include "fluxer.selectorLabels" $ctx | nindent 4 }}
|
||||
ports:
|
||||
- name: http
|
||||
port: 7880
|
||||
targetPort: 7880
|
||||
protocol: TCP
|
||||
{{- if ne .expose "hostNetwork" }}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: livekit-rtc
|
||||
namespace: {{ $.Release.Namespace }}
|
||||
labels:
|
||||
{{- include "fluxer.labels" $ctx | nindent 4 }}
|
||||
{{- with .serviceAnnotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
type: {{ ternary "LoadBalancer" "NodePort" (eq .expose "loadBalancer") }}
|
||||
externalTrafficPolicy: Local
|
||||
{{- if and (eq .expose "loadBalancer") .loadBalancerIP }}
|
||||
loadBalancerIP: {{ .loadBalancerIP }}
|
||||
{{- end }}
|
||||
selector:
|
||||
{{- include "fluxer.selectorLabels" $ctx | nindent 4 }}
|
||||
ports:
|
||||
- name: rtc-tcp
|
||||
port: {{ $tcp }}
|
||||
targetPort: rtc-tcp
|
||||
protocol: TCP
|
||||
{{- if eq .expose "nodePort" }}
|
||||
nodePort: {{ $tcp }}
|
||||
{{- end }}
|
||||
- name: rtc-udp
|
||||
port: {{ $udp }}
|
||||
targetPort: rtc-udp
|
||||
protocol: UDP
|
||||
{{- if eq .expose "nodePort" }}
|
||||
nodePort: {{ $udp }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: livekit
|
||||
namespace: {{ $.Release.Namespace }}
|
||||
labels:
|
||||
{{- include "fluxer.labels" $ctx | nindent 4 }}
|
||||
spec:
|
||||
replicas: 1
|
||||
revisionHistoryLimit: 3
|
||||
strategy:
|
||||
type: Recreate
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "fluxer.selectorLabels" $ctx | nindent 6 }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
{{- include "fluxer.podLabels" $ctx | nindent 8 }}
|
||||
annotations:
|
||||
checksum/config: {{ list $configYaml $webhook (get $secrets "FLUXER_LIVEKIT_API_KEY" | default "") (get $secrets "FLUXER_LIVEKIT_API_SECRET" | default "") | toJson | sha256sum }}
|
||||
spec:
|
||||
automountServiceAccountToken: false
|
||||
enableServiceLinks: false
|
||||
{{- if eq .expose "hostNetwork" }}
|
||||
hostNetwork: true
|
||||
dnsPolicy: ClusterFirstWithHostNet
|
||||
{{- end }}
|
||||
{{- include "fluxer.pullSecrets" $ | nindent 6 }}
|
||||
securityContext:
|
||||
{{- include "fluxer.podSecurityContext" (dict "uid" 65532) | nindent 8 }}
|
||||
{{- include "fluxer.scheduling" $ctx | nindent 6 }}
|
||||
containers:
|
||||
- name: livekit
|
||||
image: {{ include "fluxer.thirdPartyImage" .image }}
|
||||
imagePullPolicy: {{ .image.pullPolicy }}
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- |
|
||||
export LIVEKIT_KEYS="${LIVEKIT_API_KEY}: ${LIVEKIT_API_SECRET}"
|
||||
export LIVEKIT_CONFIG="$(printf '%s\nwebhook:\n api_key: %s\n urls:\n - %s\n' "$LIVEKIT_CONFIG" "$LIVEKIT_API_KEY" "$LIVEKIT_WEBHOOK_URL")"
|
||||
exec /livekit-server
|
||||
env:
|
||||
- name: LIVEKIT_CONFIG
|
||||
value: {{ $configYaml | quote }}
|
||||
- name: LIVEKIT_WEBHOOK_URL
|
||||
value: {{ $webhook }}
|
||||
{{- include "fluxer.secretEnv" (dict "root" $ "name" "LIVEKIT_API_KEY" "key" "FLUXER_LIVEKIT_API_KEY") | nindent 12 }}
|
||||
{{- include "fluxer.secretEnv" (dict "root" $ "name" "LIVEKIT_API_SECRET" "key" "FLUXER_LIVEKIT_API_SECRET") | nindent 12 }}
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 7880
|
||||
protocol: TCP
|
||||
- name: rtc-tcp
|
||||
containerPort: {{ $tcp }}
|
||||
protocol: TCP
|
||||
- name: rtc-udp
|
||||
containerPort: {{ $udp }}
|
||||
protocol: UDP
|
||||
startupProbe:
|
||||
httpGet: {{ toJson $root }}
|
||||
periodSeconds: 5
|
||||
failureThreshold: 60
|
||||
livenessProbe:
|
||||
httpGet: {{ toJson $root }}
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 5
|
||||
failureThreshold: 6
|
||||
readinessProbe:
|
||||
httpGet: {{ toJson $root }}
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 5
|
||||
{{- with .resources }}
|
||||
resources:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
securityContext:
|
||||
{{- include "fluxer.containerSecurityContext" . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,97 @@
|
||||
{{- include "fluxer.validate" . }}
|
||||
{{- with .Values.meilisearch }}
|
||||
{{- if .enabled }}
|
||||
{{- $ctx := dict "root" $ "name" "meilisearch" "component" "search" "w" . }}
|
||||
{{- $health := dict "path" "/health" "port" "http" }}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: meilisearch
|
||||
namespace: {{ $.Release.Namespace }}
|
||||
labels:
|
||||
{{- include "fluxer.labels" $ctx | nindent 4 }}
|
||||
spec:
|
||||
type: ClusterIP
|
||||
selector:
|
||||
{{- include "fluxer.selectorLabels" $ctx | nindent 4 }}
|
||||
ports:
|
||||
- name: http
|
||||
port: 7700
|
||||
targetPort: http
|
||||
protocol: TCP
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: meilisearch
|
||||
namespace: {{ $.Release.Namespace }}
|
||||
labels:
|
||||
{{- include "fluxer.labels" $ctx | nindent 4 }}
|
||||
spec:
|
||||
replicas: 1
|
||||
serviceName: meilisearch
|
||||
podManagementPolicy: Parallel
|
||||
persistentVolumeClaimRetentionPolicy:
|
||||
whenDeleted: Retain
|
||||
whenScaled: Retain
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "fluxer.selectorLabels" $ctx | nindent 6 }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
{{- include "fluxer.podLabels" $ctx | nindent 8 }}
|
||||
spec:
|
||||
automountServiceAccountToken: false
|
||||
enableServiceLinks: false
|
||||
{{- include "fluxer.pullSecrets" $ | nindent 6 }}
|
||||
securityContext:
|
||||
{{- include "fluxer.podSecurityContext" (dict "uid" 65532) | nindent 8 }}
|
||||
{{- include "fluxer.scheduling" $ctx | nindent 6 }}
|
||||
containers:
|
||||
- name: meilisearch
|
||||
image: {{ include "fluxer.thirdPartyImage" .image }}
|
||||
imagePullPolicy: {{ .image.pullPolicy }}
|
||||
env:
|
||||
- name: MEILI_ENV
|
||||
value: production
|
||||
- name: MEILI_NO_ANALYTICS
|
||||
value: "true"
|
||||
- name: MEILI_UPGRADE_DB
|
||||
value: "true"
|
||||
- name: MEILI_MAX_INDEXING_MEMORY
|
||||
value: {{ .maxIndexingMemory | quote }}
|
||||
- name: MEILI_MAX_INDEXING_THREADS
|
||||
value: {{ include "fluxer.string" .maxIndexingThreads | quote }}
|
||||
{{- include "fluxer.secretEnv" (dict "root" $ "name" "MEILI_MASTER_KEY" "key" "FLUXER_SEARCH_API_KEY") | nindent 12 }}
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 7700
|
||||
protocol: TCP
|
||||
startupProbe:
|
||||
httpGet: {{ toJson $health }}
|
||||
periodSeconds: 5
|
||||
failureThreshold: 120
|
||||
livenessProbe:
|
||||
httpGet: {{ toJson $health }}
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 5
|
||||
failureThreshold: 6
|
||||
readinessProbe:
|
||||
httpGet: {{ toJson $health }}
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 5
|
||||
{{- with .resources }}
|
||||
resources:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
securityContext:
|
||||
{{- include "fluxer.containerSecurityContext" . | nindent 12 }}
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /meili_data
|
||||
volumeClaimTemplates:
|
||||
{{- include "fluxer.pvc" .persistence | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,169 @@
|
||||
{{- include "fluxer.validate" . }}
|
||||
{{- with .Values.nats }}
|
||||
{{- if .enabled }}
|
||||
{{- $ctx := dict "root" $ "name" "nats" "component" "messaging" "w" . }}
|
||||
{{- $replicas := .replicas | int }}
|
||||
{{- $conf := include "fluxer.natsConf" (dict "root" $ "replicas" $replicas) }}
|
||||
{{- $secrets := include "fluxer.secretData" $ | fromJson }}
|
||||
{{- $healthz := dict "exec" (dict "command" (list "wget" "-q" "-O" "/dev/null" "http://127.0.0.1:8222/healthz")) }}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: nats-config
|
||||
namespace: {{ $.Release.Namespace }}
|
||||
labels:
|
||||
{{- include "fluxer.labels" $ctx | nindent 4 }}
|
||||
data:
|
||||
nats.conf: {{ $conf | quote }}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: nats
|
||||
namespace: {{ $.Release.Namespace }}
|
||||
labels:
|
||||
{{- include "fluxer.labels" $ctx | nindent 4 }}
|
||||
spec:
|
||||
type: ClusterIP
|
||||
selector:
|
||||
{{- include "fluxer.selectorLabels" $ctx | nindent 4 }}
|
||||
ports:
|
||||
- name: client
|
||||
port: 4222
|
||||
targetPort: client
|
||||
protocol: TCP
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: nats-headless
|
||||
namespace: {{ $.Release.Namespace }}
|
||||
labels:
|
||||
{{- include "fluxer.labels" $ctx | nindent 4 }}
|
||||
spec:
|
||||
type: ClusterIP
|
||||
clusterIP: None
|
||||
publishNotReadyAddresses: true
|
||||
selector:
|
||||
{{- include "fluxer.selectorLabels" $ctx | nindent 4 }}
|
||||
ports:
|
||||
- name: client
|
||||
port: 4222
|
||||
targetPort: client
|
||||
protocol: TCP
|
||||
- name: cluster
|
||||
port: 6222
|
||||
targetPort: cluster
|
||||
protocol: TCP
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: nats
|
||||
namespace: {{ $.Release.Namespace }}
|
||||
labels:
|
||||
{{- include "fluxer.labels" $ctx | nindent 4 }}
|
||||
spec:
|
||||
replicas: {{ $replicas }}
|
||||
serviceName: nats-headless
|
||||
podManagementPolicy: Parallel
|
||||
persistentVolumeClaimRetentionPolicy:
|
||||
whenDeleted: Retain
|
||||
whenScaled: Retain
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "fluxer.selectorLabels" $ctx | nindent 6 }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
{{- include "fluxer.podLabels" $ctx | nindent 8 }}
|
||||
annotations:
|
||||
checksum/config: {{ printf "%s\n%s" $conf (get $secrets "FLUXER_NATS_AUTH_TOKEN" | default "") | sha256sum }}
|
||||
spec:
|
||||
automountServiceAccountToken: false
|
||||
enableServiceLinks: false
|
||||
{{- include "fluxer.pullSecrets" $ | nindent 6 }}
|
||||
securityContext:
|
||||
{{- include "fluxer.podSecurityContext" (dict "uid" 65534) | nindent 8 }}
|
||||
{{- include "fluxer.scheduling" $ctx | nindent 6 }}
|
||||
containers:
|
||||
- name: nats
|
||||
image: {{ include "fluxer.thirdPartyImage" .image }}
|
||||
imagePullPolicy: {{ .image.pullPolicy }}
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- sed "s/__FLUXER_NATS_AUTH_TOKEN__/$FLUXER_NATS_AUTH_TOKEN/g" /etc/nats/nats.conf > /run/nats/nats.conf && exec nats-server --config /run/nats/nats.conf
|
||||
env:
|
||||
- name: POD_NAME
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
apiVersion: v1
|
||||
fieldPath: metadata.name
|
||||
{{- include "fluxer.secretEnv" (dict "root" $ "name" "FLUXER_NATS_AUTH_TOKEN" "key" "FLUXER_NATS_AUTH_TOKEN") | nindent 12 }}
|
||||
ports:
|
||||
- name: client
|
||||
containerPort: 4222
|
||||
protocol: TCP
|
||||
- name: cluster
|
||||
containerPort: 6222
|
||||
protocol: TCP
|
||||
startupProbe:
|
||||
{{- toYaml (merge (dict "periodSeconds" 5 "timeoutSeconds" 5 "failureThreshold" 60) $healthz) | nindent 12 }}
|
||||
livenessProbe:
|
||||
{{- toYaml (merge (dict "periodSeconds" 10 "timeoutSeconds" 5 "failureThreshold" 6) $healthz) | nindent 12 }}
|
||||
readinessProbe:
|
||||
{{- toYaml (merge (dict "periodSeconds" 10 "timeoutSeconds" 5) $healthz) | nindent 12 }}
|
||||
{{- with .resources }}
|
||||
resources:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
securityContext:
|
||||
{{- include "fluxer.containerSecurityContext" . | nindent 12 }}
|
||||
volumeMounts:
|
||||
- name: config
|
||||
mountPath: /etc/nats
|
||||
readOnly: true
|
||||
- name: rendered
|
||||
mountPath: /run/nats
|
||||
- name: data
|
||||
mountPath: /data
|
||||
volumes:
|
||||
- name: config
|
||||
configMap:
|
||||
name: nats-config
|
||||
- name: rendered
|
||||
emptyDir:
|
||||
medium: Memory
|
||||
volumeClaimTemplates:
|
||||
{{- include "fluxer.pvc" .persistence | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{- define "fluxer.natsConf" -}}
|
||||
server_name: $POD_NAME
|
||||
listen: 0.0.0.0:4222
|
||||
http: 127.0.0.1:8222
|
||||
authorization {
|
||||
token: "__FLUXER_NATS_AUTH_TOKEN__"
|
||||
}
|
||||
jetstream {
|
||||
store_dir: /data
|
||||
}
|
||||
{{- if gt .replicas 1 }}
|
||||
cluster {
|
||||
name: fluxer
|
||||
listen: 0.0.0.0:6222
|
||||
authorization {
|
||||
user: fluxer
|
||||
password: "__FLUXER_NATS_AUTH_TOKEN__"
|
||||
}
|
||||
routes: [
|
||||
{{- range $i := until .replicas }}
|
||||
nats://fluxer:__FLUXER_NATS_AUTH_TOKEN__@nats-{{ $i }}.nats-headless.{{ $.root.Release.Namespace }}.svc.{{ $.root.Values.clusterDomain }}:6222
|
||||
{{- end }}
|
||||
]
|
||||
}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,83 @@
|
||||
{{- include "fluxer.validate" . }}
|
||||
{{- if .Values.networkPolicy.enabled }}
|
||||
{{- $v := .Values }}
|
||||
{{- $release := dict "app.kubernetes.io/instance" .Release.Name }}
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: fluxer
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "fluxer.labels" (dict "root" . "name" "fluxer" "component" "network") | nindent 4 }}
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
{{- toYaml $release | nindent 6 }}
|
||||
policyTypes:
|
||||
- Ingress
|
||||
ingress:
|
||||
- from:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
{{- toYaml $release | nindent 14 }}
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: fluxer-edge
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "fluxer.labels" (dict "root" . "name" "fluxer-edge" "component" "network") | nindent 4 }}
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
{{- include "fluxer.selectorLabels" (dict "root" . "name" "edge") | nindent 6 }}
|
||||
policyTypes:
|
||||
- Ingress
|
||||
ingress:
|
||||
- ports:
|
||||
- port: 8080
|
||||
protocol: TCP
|
||||
{{- with $v.networkPolicy.ingressNamespaceSelector }}
|
||||
from:
|
||||
- namespaceSelector:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- if and $v.livekit.enabled (eq $v.livekit.expose "hostNetwork") }}
|
||||
{{- range $v.livekit.nodeCIDRs }}
|
||||
- ipBlock:
|
||||
cidr: {{ . }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if eq $v.edge.expose "loadBalancer" }}
|
||||
- ports:
|
||||
- port: 80
|
||||
protocol: TCP
|
||||
- port: 443
|
||||
protocol: TCP
|
||||
- port: 443
|
||||
protocol: UDP
|
||||
{{- end }}
|
||||
{{- if and $v.livekit.enabled (ne $v.livekit.expose "hostNetwork") }}
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: fluxer-livekit
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "fluxer.labels" (dict "root" . "name" "fluxer-livekit" "component" "network") | nindent 4 }}
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
{{- include "fluxer.selectorLabels" (dict "root" . "name" "livekit") | nindent 6 }}
|
||||
policyTypes:
|
||||
- Ingress
|
||||
ingress:
|
||||
- ports:
|
||||
- port: {{ ternary $v.livekit.nodePorts.tcp $v.livekit.tcpPort (eq $v.livekit.expose "nodePort") }}
|
||||
protocol: TCP
|
||||
- port: {{ ternary $v.livekit.nodePorts.udp $v.livekit.udpPort (eq $v.livekit.expose "nodePort") }}
|
||||
protocol: UDP
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,147 @@
|
||||
{{- include "fluxer.validate" . }}
|
||||
{{- with .Values.postgres }}
|
||||
{{- if .enabled }}
|
||||
{{- $ctx := dict "root" $ "name" "postgres" "component" "database" "w" . }}
|
||||
{{- $args := list }}
|
||||
{{- range $k := keys .parameters | sortAlpha }}
|
||||
{{- $args = concat $args (list "-c" (printf "%s=%s" $k (include "fluxer.string" (get $.Values.postgres.parameters $k)))) }}
|
||||
{{- end }}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: postgres
|
||||
namespace: {{ $.Release.Namespace }}
|
||||
labels:
|
||||
{{- include "fluxer.labels" $ctx | nindent 4 }}
|
||||
spec:
|
||||
type: ClusterIP
|
||||
selector:
|
||||
{{- include "fluxer.selectorLabels" $ctx | nindent 4 }}
|
||||
ports:
|
||||
- name: postgres
|
||||
port: 5432
|
||||
targetPort: postgres
|
||||
protocol: TCP
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: postgres
|
||||
namespace: {{ $.Release.Namespace }}
|
||||
labels:
|
||||
{{- include "fluxer.labels" $ctx | nindent 4 }}
|
||||
spec:
|
||||
replicas: 1
|
||||
serviceName: postgres
|
||||
podManagementPolicy: Parallel
|
||||
persistentVolumeClaimRetentionPolicy:
|
||||
whenDeleted: Retain
|
||||
whenScaled: Retain
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "fluxer.selectorLabels" $ctx | nindent 6 }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
{{- include "fluxer.podLabels" $ctx | nindent 8 }}
|
||||
annotations:
|
||||
checksum/config: {{ toJson $args | sha256sum }}
|
||||
spec:
|
||||
automountServiceAccountToken: false
|
||||
enableServiceLinks: false
|
||||
terminationGracePeriodSeconds: 60
|
||||
{{- include "fluxer.pullSecrets" $ | nindent 6 }}
|
||||
securityContext:
|
||||
{{- include "fluxer.podSecurityContext" (dict "uid" (.runAsUser | int)) | nindent 8 }}
|
||||
{{- include "fluxer.scheduling" $ctx | nindent 6 }}
|
||||
initContainers:
|
||||
- name: version-guard
|
||||
image: {{ include "fluxer.thirdPartyImage" .image }}
|
||||
imagePullPolicy: {{ .image.pullPolicy }}
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- |
|
||||
want=$(postgres --version | sed -E 's/[^0-9]*([0-9]+).*/\1/')
|
||||
if [ -s "$PGDATA/PG_VERSION" ]; then
|
||||
have=$(cat "$PGDATA/PG_VERSION")
|
||||
if [ "$have" != "$want" ]; then
|
||||
echo "The data directory was created by Postgres $have and this image runs Postgres $want. Set postgres.image.tag back to the $have image, or dump the database and restore it into a fresh volume. See the Kubernetes page of the operator docs." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
env:
|
||||
- name: PGDATA
|
||||
value: /var/lib/postgresql/data/pgdata
|
||||
resources:
|
||||
requests:
|
||||
cpu: 10m
|
||||
memory: 16Mi
|
||||
limits:
|
||||
memory: 64Mi
|
||||
securityContext:
|
||||
{{- include "fluxer.containerSecurityContext" . | nindent 12 }}
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /var/lib/postgresql/data
|
||||
containers:
|
||||
- name: postgres
|
||||
image: {{ include "fluxer.thirdPartyImage" .image }}
|
||||
imagePullPolicy: {{ .image.pullPolicy }}
|
||||
args:
|
||||
{{- toYaml $args | nindent 12 }}
|
||||
env:
|
||||
- name: PGDATA
|
||||
value: /var/lib/postgresql/data/pgdata
|
||||
- name: POSTGRES_DB
|
||||
value: {{ .database | quote }}
|
||||
- name: POSTGRES_USER
|
||||
value: {{ .username | quote }}
|
||||
{{- include "fluxer.secretEnv" (dict "root" $ "name" "POSTGRES_PASSWORD" "key" "FLUXER_POSTGRES_PASSWORD") | nindent 12 }}
|
||||
ports:
|
||||
- name: postgres
|
||||
containerPort: 5432
|
||||
protocol: TCP
|
||||
startupProbe:
|
||||
exec:
|
||||
command: ["sh", "-c", "pg_isready -U \"$POSTGRES_USER\" -d \"$POSTGRES_DB\""]
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 5
|
||||
failureThreshold: 30
|
||||
livenessProbe:
|
||||
exec:
|
||||
command: ["sh", "-c", "pg_isready -U \"$POSTGRES_USER\" -d \"$POSTGRES_DB\""]
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 5
|
||||
failureThreshold: 6
|
||||
readinessProbe:
|
||||
exec:
|
||||
command: ["sh", "-c", "pg_isready -U \"$POSTGRES_USER\" -d \"$POSTGRES_DB\""]
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 5
|
||||
failureThreshold: 3
|
||||
{{- with .resources }}
|
||||
resources:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
securityContext:
|
||||
{{- include "fluxer.containerSecurityContext" . | nindent 12 }}
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /var/lib/postgresql/data
|
||||
- name: shm
|
||||
mountPath: /dev/shm
|
||||
- name: run
|
||||
mountPath: /var/run/postgresql
|
||||
volumes:
|
||||
- name: shm
|
||||
emptyDir:
|
||||
medium: Memory
|
||||
sizeLimit: {{ .shmSize }}
|
||||
- name: run
|
||||
emptyDir: {}
|
||||
volumeClaimTemplates:
|
||||
{{- include "fluxer.pvc" .persistence | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
Loaded 100 of 10395 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user