Compare commits
1399 Commits
dev
...
dependenci
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3271c96531 | ||
|
|
05fa6b9aba | ||
|
|
7edd7f27cb | ||
|
|
4a6b12eda1 | ||
|
|
a354e1a0eb | ||
|
|
c2c419522a | ||
|
|
7a3cc7d242 | ||
|
|
bd6f02f6af | ||
|
|
bd33728fd7 | ||
|
|
8400ee8a3d | ||
|
|
80ee7aef8e | ||
|
|
41762be3a5 | ||
|
|
605dda7b76 | ||
|
|
8d6e3b5a58 | ||
|
|
53920fc368 | ||
|
|
96d10423d9 | ||
|
|
42be9b5b51 | ||
|
|
0add041516 | ||
|
|
dee76cac8d | ||
|
|
9646fab22c | ||
|
|
a54e9cb244 | ||
|
|
f8339c7a9a | ||
|
|
9e2c864117 | ||
|
|
e1ccd71455 | ||
|
|
0e82426ea1 | ||
|
|
6c7afd168a | ||
|
|
e014fdf3da | ||
|
|
2074da05c8 | ||
|
|
84cd87b70a | ||
|
|
75f87044f6 | ||
|
|
f71b51e64a | ||
|
|
9d741cdd63 | ||
|
|
56be17000a | ||
|
|
f6aacbc31d | ||
|
|
ad4b57c327 | ||
|
|
3794b2f0de | ||
|
|
e0e8412728 | ||
|
|
05b8175aad | ||
|
|
339c89dd1c | ||
|
|
402299e9c8 | ||
|
|
d0e8f450fd | ||
|
|
e97b1ccd7a | ||
|
|
68691b91ef | ||
|
|
213d417481 | ||
|
|
2ec841eb61 | ||
|
|
60b5c54be1 | ||
|
|
448412a191 | ||
|
|
e06327936e | ||
|
|
5f044e1aed | ||
|
|
d90fb6fc9b | ||
|
|
1c583d2ea9 | ||
|
|
ddab131102 | ||
|
|
3b06cf8a2a | ||
|
|
c5d7c29f3d | ||
|
|
26af860eac | ||
|
|
ec9852eb98 | ||
|
|
f2b8c6d0ca | ||
|
|
2cf7a048cf | ||
|
|
3dbb71a076 | ||
|
|
ddf6760543 | ||
|
|
a6fa323f33 | ||
|
|
2df8f1acdb | ||
|
|
74a3290abc | ||
|
|
ab306d21f3 | ||
|
|
1bd7795851 | ||
|
|
302c142346 | ||
|
|
7c254c9b45 | ||
|
|
b1c458359d | ||
|
|
2d925c62f5 | ||
|
|
ef4711987f | ||
|
|
8910dfaecf | ||
|
|
e8b2e79c7d | ||
|
|
333ee1e1f7 | ||
|
|
ba013bbe96 | ||
|
|
636e66fe7a | ||
|
|
372a45e667 | ||
|
|
ab6b796ce2 | ||
|
|
71e6c02897 | ||
|
|
3edeaa7038 | ||
|
|
f2f75d4015 | ||
|
|
69adade738 | ||
|
|
1bd88828e4 | ||
|
|
977fcbe6cd | ||
|
|
aa76a5c436 | ||
|
|
ea5fad428d | ||
|
|
0e1e27b35a | ||
|
|
d41f67a156 | ||
|
|
6f10dec808 | ||
|
|
9b79da2cdf | ||
|
|
c11b8519f1 | ||
|
|
b9e23a0b59 | ||
|
|
75d41b6fe5 | ||
|
|
4256590735 | ||
|
|
462fb05ea8 | ||
|
|
812dbfd836 | ||
|
|
cfca837777 | ||
|
|
ac5fb1948a | ||
|
|
22d8b73625 | ||
|
|
edde40c298 | ||
|
|
50ade92238 | ||
|
|
b598d00aef | ||
|
|
97bee17e4e | ||
|
|
6aa5c79332 | ||
|
|
7c5ce756f9 | ||
|
|
43d53a9ffa | ||
|
|
e6589bee5b | ||
|
|
9f94cad615 | ||
|
|
7778d9f773 | ||
|
|
564bd55147 | ||
|
|
a7ff806522 | ||
|
|
ac3b074d66 | ||
|
|
da949c2604 | ||
|
|
20a9775dc6 | ||
|
|
8ec19e058f | ||
|
|
a5c4549722 | ||
|
|
c7d302aa16 | ||
|
|
77ac565ff3 | ||
|
|
2e6f834a50 | ||
|
|
5b044cca9e | ||
|
|
2ab5623809 | ||
|
|
2d07f0d77c | ||
|
|
8ba7f9f702 | ||
|
|
460ac7a86b | ||
|
|
f93a1ab3eb | ||
|
|
6b02696aa8 | ||
|
|
25f20d6a85 | ||
|
|
8387964bae | ||
|
|
926278617f | ||
|
|
1933737a0c | ||
|
|
b3e5288bde | ||
|
|
ed6e966b2f | ||
|
|
9315fe36b6 | ||
|
|
41fbf5ba36 | ||
|
|
40db481453 | ||
|
|
1b5e295744 | ||
|
|
b42a52f7f6 | ||
|
|
8268df84d0 | ||
|
|
eb6fa5f1f1 | ||
|
|
025c8856ed | ||
|
|
ed421445e9 | ||
|
|
0cda07106b | ||
|
|
f335941b62 | ||
|
|
f0719f8bde | ||
|
|
27fe28661c | ||
|
|
bb13b12de6 | ||
|
|
1117e28b2e | ||
|
|
0f48873c25 | ||
|
|
faf61b4af3 | ||
|
|
e29ce93d32 | ||
|
|
38ab68492e | ||
|
|
53b1576e5f | ||
|
|
2835e79973 | ||
|
|
8e4d7e989b | ||
|
|
603c6b826c | ||
|
|
51bcc77cb3 | ||
|
|
a30d07b924 | ||
|
|
11faa5fe39 | ||
|
|
ce8383b26f | ||
|
|
bd8f07c90a | ||
|
|
fee077bebd | ||
|
|
558f4d93ba | ||
|
|
e77d126349 | ||
|
|
cd8667d6de | ||
|
|
8a2d06d010 | ||
|
|
92741fc733 | ||
|
|
1cff162649 | ||
|
|
f59be465ea | ||
|
|
27305317ce | ||
|
|
8378320e50 | ||
|
|
86a69952db | ||
|
|
e212ebfdb9 | ||
|
|
f235125d48 | ||
|
|
8efa815eb9 | ||
|
|
e54d42576b | ||
|
|
1e18539862 | ||
|
|
673fdf4721 | ||
|
|
57d6bfba51 | ||
|
|
8fa23aecda | ||
|
|
f9c10533e8 | ||
|
|
c891c3723e | ||
|
|
a0625ef2e7 | ||
|
|
b2774abb54 | ||
|
|
fa089bbc40 | ||
|
|
8437d1763f | ||
|
|
0532b0f9df | ||
|
|
5f8eb853f0 | ||
|
|
9125a85382 | ||
|
|
5b3dc44c72 | ||
|
|
ee5147f111 | ||
|
|
f67137fd5e | ||
|
|
b67db4a896 | ||
|
|
067018828c | ||
|
|
e990530ada | ||
|
|
45f863a72a | ||
|
|
519febbeb2 | ||
|
|
854b1a4caf | ||
|
|
08eb95e73a | ||
|
|
66f8fbf08c | ||
|
|
86a30bbb29 | ||
|
|
966c453c27 | ||
|
|
c7bcaf0193 | ||
|
|
0ac91e36a0 | ||
|
|
6f1299ce9e | ||
|
|
83ca29d649 | ||
|
|
d0206044dc | ||
|
|
d4623e4175 | ||
|
|
68ef03377d | ||
|
|
d3f9d3d033 | ||
|
|
a6ccd04471 | ||
|
|
0fd8174e77 | ||
|
|
ebc63f479a | ||
|
|
570c39c20a | ||
|
|
1d57257cf5 | ||
|
|
82d7baee0b | ||
|
|
1d91e1f1f7 | ||
|
|
15e8894614 | ||
|
|
0ae96918e9 | ||
|
|
e970880059 | ||
|
|
69ae86aba8 | ||
|
|
8142e1be49 | ||
|
|
cbc7612451 | ||
|
|
09e6a7b7cc | ||
|
|
082e35668a | ||
|
|
c9e78c837b | ||
|
|
2d171db672 | ||
|
|
a8b11abec8 | ||
|
|
b08333dccd | ||
|
|
98bad48971 | ||
|
|
53375bb536 | ||
|
|
88798093e1 | ||
|
|
45a28751af | ||
|
|
1670c44464 | ||
|
|
a286ac85dc | ||
|
|
1606adc0ab | ||
|
|
b4ce557d92 | ||
|
|
2ba7fff8d4 | ||
|
|
98efc93610 | ||
|
|
2680507eae | ||
|
|
df72392ad2 | ||
|
|
a6acb15a00 | ||
|
|
ba7242a815 | ||
|
|
99740c1324 | ||
|
|
c04b20d1fa | ||
|
|
e127067878 | ||
|
|
6f03b72368 | ||
|
|
7bd3ee9340 | ||
|
|
c94db606e5 | ||
|
|
4d2474226b | ||
|
|
1ffc4f538b | ||
|
|
6702ac957b | ||
|
|
ba42b2e77d | ||
|
|
fba18ca40a | ||
|
|
3a2a7a1476 | ||
|
|
3c6d6b90bc | ||
|
|
47dc9ee304 | ||
|
|
0045bf206c | ||
|
|
669a1a6953 | ||
|
|
e28452cc7b | ||
|
|
5ceac03db1 | ||
|
|
96215e5950 | ||
|
|
7a030b9224 | ||
|
|
e743478a4d | ||
|
|
bc29c80d44 | ||
|
|
82b8a474d7 | ||
|
|
99851b297d | ||
|
|
e3a500e12c | ||
|
|
378666e3cc | ||
|
|
b65ad1ebd7 | ||
|
|
933a821b5f | ||
|
|
159337ddbd | ||
|
|
2e25a4333a | ||
|
|
64fafb0795 | ||
|
|
5927e0bb3b | ||
|
|
e21596db83 | ||
|
|
8a608c3c3e | ||
|
|
76f9db8516 | ||
|
|
90f4809b7c | ||
|
|
3ff1af9fd6 | ||
|
|
711dd520f7 | ||
|
|
99503c836a | ||
|
|
2c8bc51862 | ||
|
|
5e7aa15232 | ||
|
|
d0761869b6 | ||
|
|
bb99b89228 | ||
|
|
7b88beb0b5 | ||
|
|
82c630bd0e | ||
|
|
bb4f11e1b8 | ||
|
|
3182d20b7c | ||
|
|
a6f15e2474 | ||
|
|
0c3f03680c | ||
|
|
a66e8dfc9f | ||
|
|
556232aac4 | ||
|
|
7fcfaadd91 | ||
|
|
18d388e1e2 | ||
|
|
7de6622d74 | ||
|
|
9af1f90990 | ||
|
|
15ab43963d | ||
|
|
6b7465a4b0 | ||
|
|
d64bdf02de | ||
|
|
4a2c94993a | ||
|
|
86c318d86b | ||
|
|
bffc1ad41d | ||
|
|
2a685c116f | ||
|
|
0e271d2924 | ||
|
|
7127c4d590 | ||
|
|
a82929996b | ||
|
|
3f01f52c7b | ||
|
|
9c94494622 | ||
|
|
c8a508f35c | ||
|
|
4ec73ef1c3 | ||
|
|
3465b79e5b | ||
|
|
726a0a33ae | ||
|
|
ba05810d80 | ||
|
|
10bb53e7de | ||
|
|
dd8a083546 | ||
|
|
84131a71c9 | ||
|
|
4909a11896 | ||
|
|
4069357b81 | ||
|
|
e6e87bcc40 | ||
|
|
7ba22045e8 | ||
|
|
d4040b61c4 | ||
|
|
7534f8fc37 | ||
|
|
7ced009e92 | ||
|
|
cc13c71e40 | ||
|
|
d2f09209a7 | ||
|
|
a241b04d99 | ||
|
|
4f35d907cb | ||
|
|
9e50d144a3 | ||
|
|
8514bb48c4 | ||
|
|
3ae633a2a1 | ||
|
|
2799cb9118 | ||
|
|
d20346b6ac | ||
|
|
2f00666a68 | ||
|
|
80f4570093 | ||
|
|
3f0a2ba48f | ||
|
|
fc90094e8a | ||
|
|
20d580ade8 | ||
|
|
290a024a9e | ||
|
|
64a283c3a6 | ||
|
|
3e93f0ecbc | ||
|
|
b12bcc1c49 | ||
|
|
05d7313dcc | ||
|
|
c0b6e549f0 | ||
|
|
31f9bf219e | ||
|
|
4906ca7059 | ||
|
|
b963a7a0e5 | ||
|
|
5d6dadda76 | ||
|
|
77f69fd223 | ||
|
|
7f5052bc87 | ||
|
|
3009c1f4f6 | ||
|
|
5425872bba | ||
|
|
0759e17295 | ||
|
|
56a59d25df | ||
|
|
887f92babe | ||
|
|
197f942b3f | ||
|
|
a5be7a35e9 | ||
|
|
e347675265 | ||
|
|
02a084d571 | ||
|
|
7fbcc23d94 | ||
|
|
bda87167a3 | ||
|
|
34f53c287e | ||
|
|
9ab07f37d7 | ||
|
|
36399b39fb | ||
|
|
1e015287a1 | ||
|
|
a590aa8485 | ||
|
|
c0582fde66 | ||
|
|
d8d75b4afa | ||
|
|
9d4942723c | ||
|
|
e5b1ece5c0 | ||
|
|
1b25bfbf5a | ||
|
|
7c64d9f42a | ||
|
|
61f9f4ef58 | ||
|
|
b8eac56213 | ||
|
|
ab5fb5749b | ||
|
|
e0fb9a1b25 | ||
|
|
97e717f646 | ||
|
|
caa82ad1e6 | ||
|
|
7ec251ea6d | ||
|
|
675b0c3cca | ||
|
|
05e54d4b7f | ||
|
|
b4527c90e5 | ||
|
|
dbc626734d | ||
|
|
3f2ce3cb80 | ||
|
|
0820d6d6fb | ||
|
|
a8c74e39c2 | ||
|
|
d58c29907d | ||
|
|
2322733427 | ||
|
|
d76e8fe85a | ||
|
|
0c2e4fe34a | ||
|
|
30b6c87a49 | ||
|
|
540221467a | ||
|
|
d44d331a78 | ||
|
|
595554f18a | ||
|
|
84d3c3f7eb | ||
|
|
890f55c9dc | ||
|
|
575a14e1f3 | ||
|
|
91074bebd6 | ||
|
|
3459a16b48 | ||
|
|
88c9b6849f | ||
|
|
d87bb25baf | ||
|
|
34cb796505 | ||
|
|
1eb34e0662 | ||
|
|
01d631033f | ||
|
|
84b2c07340 | ||
|
|
a86eeb636d | ||
|
|
417a5a8214 | ||
|
|
bcf40dde8c | ||
|
|
cad87484c7 | ||
|
|
b8ad641ed6 | ||
|
|
ae8197be8b | ||
|
|
eafb0274a7 | ||
|
|
71a23a4e02 | ||
|
|
26fd90dfa3 | ||
|
|
e393ebede2 | ||
|
|
2981bb3f19 | ||
|
|
6e9f05abb1 | ||
|
|
9df1115380 | ||
|
|
f22e360cbb | ||
|
|
67769af6f4 | ||
|
|
b1a9a1d6d9 | ||
|
|
cf0606ecb7 | ||
|
|
7287edcd6f | ||
|
|
e0d26203dd | ||
|
|
7e3a85e9da | ||
|
|
5a0fed9c93 | ||
|
|
1f1e743912 | ||
|
|
b4301ed0d5 | ||
|
|
b5391560fc | ||
|
|
718989cbcf | ||
|
|
d0aee76962 | ||
|
|
fb08af96bd | ||
|
|
510a0c5e70 | ||
|
|
89bdc8ec75 | ||
|
|
ae25ade318 | ||
|
|
dd5e46a8a7 | ||
|
|
f7218aaa9e | ||
|
|
ee79bcfc44 | ||
|
|
2c2c174874 | ||
|
|
f57c49ce3a | ||
|
|
06121acfac | ||
|
|
2078ce7446 | ||
|
|
49f41abfdb | ||
|
|
70fcfe6d6c | ||
|
|
b060b4b9bf | ||
|
|
ee2135bfb3 | ||
|
|
7daa322441 | ||
|
|
74252cb66b | ||
|
|
5fe2be031f | ||
|
|
2ba3aaba47 | ||
|
|
ad8903991c | ||
|
|
3e5624c570 | ||
|
|
88d3bba300 | ||
|
|
f5ee6f3537 | ||
|
|
afc77e7adc | ||
|
|
024f42fce6 | ||
|
|
8a5f12b97c | ||
|
|
954b21cf39 | ||
|
|
74d095774d | ||
|
|
17a2722e6d | ||
|
|
c843bddbfe | ||
|
|
3f22a49755 | ||
|
|
7af2ffcebf | ||
|
|
de90c959e0 | ||
|
|
9987dc1eb4 | ||
|
|
3efd575dd2 | ||
|
|
f4c7b17a87 | ||
|
|
16d80718cb | ||
|
|
ad228d53b7 | ||
|
|
15ee1e531b | ||
|
|
1c8fb3392a | ||
|
|
8647866a32 | ||
|
|
23351c4f1c | ||
|
|
1367c304cf | ||
|
|
26d6bcb074 | ||
|
|
b0d651ece1 | ||
|
|
b6d50ba6a4 | ||
|
|
b3ab6a9166 | ||
|
|
f39a5ac9c2 | ||
|
|
38a9a9240d | ||
|
|
241b22a465 | ||
|
|
741abc0366 | ||
|
|
7854775de5 | ||
|
|
e62eaa6b4b | ||
|
|
b4cce23ef4 | ||
|
|
2bcaf90fc8 | ||
|
|
96ffbe2f84 | ||
|
|
6f5acee1c3 | ||
|
|
54e491d8bf | ||
|
|
ab6374e278 | ||
|
|
2fda4c9f67 | ||
|
|
5138a45b0f | ||
|
|
b224d4fa8a | ||
|
|
a552e44483 | ||
|
|
0cf3bba118 | ||
|
|
2c48ea3508 | ||
|
|
b9b6212b75 | ||
|
|
b978aaec21 | ||
|
|
af704681d9 | ||
|
|
1443ddfe6c | ||
|
|
54457a3e1b | ||
|
|
bf180e6a2c | ||
|
|
864a5820c9 | ||
|
|
4d3ca49c3f | ||
|
|
c49c3cf7f0 | ||
|
|
5d5ab57469 | ||
|
|
31978d8de0 | ||
|
|
e8eb68bf24 | ||
|
|
9ea08f4fed | ||
|
|
fe078a5c5b | ||
|
|
61933954f3 | ||
|
|
4c243638cb | ||
|
|
02ba04b5d8 | ||
|
|
4f158a4829 | ||
|
|
177a22df59 | ||
|
|
6b0ca2966e | ||
|
|
aadfaf7150 | ||
|
|
b307b9a66b | ||
|
|
6c1ab6002d | ||
|
|
9638eefc91 | ||
|
|
9e9c4ad587 | ||
|
|
ce231431b9 | ||
|
|
06e1e14e02 | ||
|
|
416e7884f5 | ||
|
|
d579222007 | ||
|
|
30243c84cd | ||
|
|
3557a77645 | ||
|
|
97be28638b | ||
|
|
aba0826c38 | ||
|
|
f032228d0e | ||
|
|
6cf174c5ed | ||
|
|
c2109d245f | ||
|
|
6a9745171e | ||
|
|
f9a68e8b23 | ||
|
|
6e391df5ee | ||
|
|
f5edca94d3 | ||
|
|
60046abec3 | ||
|
|
cafc2060b8 | ||
|
|
b1f45752cf | ||
|
|
ed17551170 | ||
|
|
ef5adab638 | ||
|
|
fb653ff99d | ||
|
|
78fc47a9c4 | ||
|
|
2a124cea61 | ||
|
|
4c7cc563dc | ||
|
|
6114af4f93 | ||
|
|
8c31629655 | ||
|
|
03c8a8edb2 | ||
|
|
3eeaee154f | ||
|
|
8cf8fa7c80 | ||
|
|
6b4f6fc71e | ||
|
|
30c2680b6f | ||
|
|
fb7b1800cc | ||
|
|
ff573bf377 | ||
|
|
0a33bb861e | ||
|
|
728756289b | ||
|
|
56ccd3a0ac | ||
|
|
66f3f0ba07 | ||
|
|
af5e0d589e | ||
|
|
533dc99e7d | ||
|
|
fc5ca965ba | ||
|
|
9c4a46bcdb | ||
|
|
52658886e7 | ||
|
|
8174ab7616 | ||
|
|
2b6acedae1 | ||
|
|
d00fe9c5f4 | ||
|
|
88aa270728 | ||
|
|
4ae409c7f4 | ||
|
|
9a29c9abdd | ||
|
|
66d93ea037 | ||
|
|
6c0066dbfb | ||
|
|
4fde644733 | ||
|
|
e7841c60df | ||
|
|
94f647b24a | ||
|
|
630249d22a | ||
|
|
db99b4cb54 | ||
|
|
c77db23586 | ||
|
|
daf66bcec4 | ||
|
|
8caf36349f | ||
|
|
6934de58e5 | ||
|
|
54a5007c01 | ||
|
|
e25a455698 | ||
|
|
ab429dfeb6 | ||
|
|
c5289dc0e8 | ||
|
|
d191877002 | ||
|
|
4d979160c2 | ||
|
|
d00e8f6e19 | ||
|
|
91b77e5237 | ||
|
|
5b8c246d53 | ||
|
|
b374b9b91c | ||
|
|
403717117e | ||
|
|
027295d995 | ||
|
|
c9b7eccbc1 | ||
|
|
2b6d9348cd | ||
|
|
692f8c8454 | ||
|
|
6783355c4d | ||
|
|
fb9cca1e99 | ||
|
|
eb770ede1a | ||
|
|
2643e853af | ||
|
|
b79456e91b | ||
|
|
ac66c086f8 | ||
|
|
ebccf401dd | ||
|
|
66494845b7 | ||
|
|
e6c36ad602 | ||
|
|
26379182db | ||
|
|
bba03d14d4 | ||
|
|
23b728a762 | ||
|
|
819c5207d2 | ||
|
|
311358544e | ||
|
|
4480ecc96d | ||
|
|
6c5f70a205 | ||
|
|
99adfb4a9e | ||
|
|
7909cf4067 | ||
|
|
780ab20aeb | ||
|
|
73119bb7c5 | ||
|
|
f20f0f064e | ||
|
|
1b44ae098c | ||
|
|
453c230716 | ||
|
|
439d885ee1 | ||
|
|
43dee3ef76 | ||
|
|
c71ba6ff8d | ||
|
|
fb7a36eb73 | ||
|
|
e7f294a065 | ||
|
|
d5037f180e | ||
|
|
e90158809a | ||
|
|
0cb802ed9a | ||
|
|
d0b47204f4 | ||
|
|
351cb391e5 | ||
|
|
051be927cd | ||
|
|
8bad2c2113 | ||
|
|
2bcf6fb3eb | ||
|
|
d1ba0ed2b2 | ||
|
|
6e421e60c5 | ||
|
|
8385050804 | ||
|
|
bfe4f08232 | ||
|
|
132f914b0d | ||
|
|
97d82b03ab | ||
|
|
f06fa3f9b7 | ||
|
|
6337788a22 | ||
|
|
024db4358b | ||
|
|
173f35487e | ||
|
|
74cbe82dd1 | ||
|
|
a8c30d30a9 | ||
|
|
1b7a52d5af | ||
|
|
e5109789bf | ||
|
|
4d2b35e09d | ||
|
|
5c5177ec57 | ||
|
|
d93b00cd15 | ||
|
|
39ade59174 | ||
|
|
0309c815b9 | ||
|
|
ce613098db | ||
|
|
ab34044196 | ||
|
|
17f724748f | ||
|
|
f3a917b5e7 | ||
|
|
376011ea08 | ||
|
|
2ce7624c14 | ||
|
|
c62dddd5b9 | ||
|
|
490ba9f140 | ||
|
|
f76890cc56 | ||
|
|
e1c8f1fed9 | ||
|
|
6e19a4ab8b | ||
|
|
b156523a7f | ||
|
|
d20b745ae5 | ||
|
|
c51e9e6b2c | ||
|
|
1a31fa9067 | ||
|
|
558b8499af | ||
|
|
986c162988 | ||
|
|
770d5cd11c | ||
|
|
446d2ab3af | ||
|
|
2f9bf7f063 | ||
|
|
72ff9c0964 | ||
|
|
33b1a11d85 | ||
|
|
06dabf1e4e | ||
|
|
28d3691e0b | ||
|
|
ffa21fbfd2 | ||
|
|
db028665fd | ||
|
|
6bc83d9f27 | ||
|
|
790d832155 | ||
|
|
f477cecdeb | ||
|
|
e031389021 | ||
|
|
e00f826eb8 | ||
|
|
24f4e8ab99 | ||
|
|
1550d528bd | ||
|
|
40c041031e | ||
|
|
3e555ec9f1 | ||
|
|
5098f14aab | ||
|
|
a355a9c85e | ||
|
|
e7db2a8573 | ||
|
|
9b18bd0b48 | ||
|
|
f95ddd594e | ||
|
|
fe8168784f | ||
|
|
4046f143f6 | ||
|
|
e4e16999c8 | ||
|
|
10f3ba4ff4 | ||
|
|
3cd2be5081 | ||
|
|
c9359978f9 | ||
|
|
781c67b31a | ||
|
|
020bd129fb | ||
|
|
8086b6d78c | ||
|
|
48e14b36b8 | ||
|
|
b3c1c56579 | ||
|
|
bd0e932910 | ||
|
|
525e5f88ae | ||
|
|
005eeb0e0b | ||
|
|
d21bb015e8 | ||
|
|
7338838b0e | ||
|
|
8bb4803ff9 | ||
|
|
892b919cf3 | ||
|
|
572d81ecef | ||
|
|
a4ce7a4037 | ||
|
|
6eafb15cf9 | ||
|
|
e19fe5ce1c | ||
|
|
9d2017e598 | ||
|
|
f33c419ed9 | ||
|
|
f425fbaf9d | ||
|
|
bcc5ec897a | ||
|
|
f5f2fe3472 | ||
|
|
b7c3863882 | ||
|
|
d759f48ee8 | ||
|
|
3a37075e71 | ||
|
|
58366c0b87 | ||
|
|
2667ed13f1 | ||
|
|
34daffbc96 | ||
|
|
be81cd72af | ||
|
|
4ae00714d2 | ||
|
|
f24cbb6692 | ||
|
|
5a35c5b928 | ||
|
|
1880da6351 | ||
|
|
df93cb103c | ||
|
|
63b474a32c | ||
|
|
abdbf158d1 | ||
|
|
ee68d80d0a | ||
|
|
c8e6f3a627 | ||
|
|
dc941575fe | ||
|
|
e64103e5f2 | ||
|
|
f0ab03a9fb | ||
|
|
09965f1cc6 | ||
|
|
d2852bb34a | ||
|
|
b03c52a501 | ||
|
|
fd6633f536 | ||
|
|
320ac81f48 | ||
|
|
70bcd2428f | ||
|
|
71f5ada0a3 | ||
|
|
aab5141404 | ||
|
|
ff6b119f27 | ||
|
|
7ef4b7eeb8 | ||
|
|
4668be6e24 | ||
|
|
a211fc7c97 | ||
|
|
54af0b675d | ||
|
|
8c8171e774 | ||
|
|
0bb1790206 | ||
|
|
45fc84d8be | ||
|
|
f7500f4cad | ||
|
|
0cfd718d8a | ||
|
|
5f486d0f51 | ||
|
|
6e5a2f85a1 | ||
|
|
e66a89208d | ||
|
|
7f65c501c6 | ||
|
|
22c2382765 | ||
|
|
38e1a4febf | ||
|
|
8db554b377 | ||
|
|
5f5cc55331 | ||
|
|
2f8b39186f | ||
|
|
a3a724e2e6 | ||
|
|
73235c8699 | ||
|
|
7e5999e862 | ||
|
|
afa244dcb0 | ||
|
|
4ea5bb2390 | ||
|
|
e545d552f6 | ||
|
|
56fe7b3596 | ||
|
|
eb28ec866a | ||
|
|
4649454282 | ||
|
|
a45dc6efda | ||
|
|
9e56b9fbb5 | ||
|
|
5504994cb9 | ||
|
|
acff6d0432 | ||
|
|
eea9cb7c5b | ||
|
|
c0ddddfb1f | ||
|
|
f7dab3ca56 | ||
|
|
e11b4038a3 | ||
|
|
b635e64803 | ||
|
|
20a194b49a | ||
|
|
33a5fb8837 | ||
|
|
59dae640db | ||
|
|
a6ac75e97b | ||
|
|
cc5b33a8ec | ||
|
|
6e1a627b84 | ||
|
|
62d4c65e1c | ||
|
|
600134a3ac | ||
|
|
df14af7337 | ||
|
|
2f740b570d | ||
|
|
294d980b52 | ||
|
|
c9d9909d74 | ||
|
|
90eeabae7b | ||
|
|
a32c77c5f1 | ||
|
|
910846f2ce | ||
|
|
35d0438261 | ||
|
|
515af472ce | ||
|
|
f062f7f9fe | ||
|
|
f68378041f | ||
|
|
30ef3057ac | ||
|
|
48f3a934c9 | ||
|
|
38d1fde84f | ||
|
|
dd78670a4b | ||
|
|
b8a8190a43 | ||
|
|
2d0989342f | ||
|
|
15ff9b06a1 | ||
|
|
41b19f69de | ||
|
|
f2bd6f1fce | ||
|
|
ec94218a4b | ||
|
|
c2e5c7cf38 | ||
|
|
bac5734527 | ||
|
|
bef4033d94 | ||
|
|
64216cba67 | ||
|
|
a9d6167a9f | ||
|
|
6c6b40548f | ||
|
|
a916d88e85 | ||
|
|
ab2f0548a3 | ||
|
|
e30ba07285 | ||
|
|
1b336d973d | ||
|
|
7b1866737f | ||
|
|
eedc4ab648 | ||
|
|
5e429c7a94 | ||
|
|
57d23eb043 | ||
|
|
5ebd9be89a | ||
|
|
5a743779e2 | ||
|
|
0495062110 | ||
|
|
d522191f69 | ||
|
|
bbbdc8b7a6 | ||
|
|
c00ed8aa5a | ||
|
|
0beaa94068 | ||
|
|
96e76665d6 | ||
|
|
6423a29600 | ||
|
|
8bddf30dcf | ||
|
|
a6b2db182d | ||
|
|
b9f3f9d859 | ||
|
|
6331447dcd | ||
|
|
4213ee660f | ||
|
|
3bd9287c5d | ||
|
|
b23d3f7c8b | ||
|
|
f8d9e5e027 | ||
|
|
8fa7fb3b1f | ||
|
|
63d92a0872 | ||
|
|
509d83365e | ||
|
|
d6ab73c905 | ||
|
|
5a93ba05d5 | ||
|
|
2d2fdf0b1e | ||
|
|
cf96622261 | ||
|
|
47c8ccb0e5 | ||
|
|
02fdb8778b | ||
|
|
6bed7f0e66 | ||
|
|
7597d335b9 | ||
|
|
f32c5ba244 | ||
|
|
ab53ab21e2 | ||
|
|
acfe5dbb49 | ||
|
|
f9b91fa189 | ||
|
|
2462e68ba1 | ||
|
|
019b2a1681 | ||
|
|
e94a07b677 | ||
|
|
c058c29755 | ||
|
|
9e7c7ac163 | ||
|
|
fcee41f00d | ||
|
|
ff2c1bf8ed | ||
|
|
a2cf26e7ed | ||
|
|
71e6900375 | ||
|
|
3bdc98bd12 | ||
|
|
68d2a6e951 | ||
|
|
acf47ac947 | ||
|
|
fda24e5f5a | ||
|
|
05eca8e4d8 | ||
|
|
b915f3b1a9 | ||
|
|
ab58968f4d | ||
|
|
820d1e7570 | ||
|
|
a120c8cf98 | ||
|
|
5a35ea116f | ||
|
|
e72ad1f030 | ||
|
|
a17362437a | ||
|
|
8643dc43b1 | ||
|
|
e1c869a358 | ||
|
|
2f5b8d9abe | ||
|
|
db324f54eb | ||
|
|
3242efb1a2 | ||
|
|
30f9f1a021 | ||
|
|
3f58d05aa7 | ||
|
|
c611a51575 | ||
|
|
73458dcd28 | ||
|
|
23ebeb1cc0 | ||
|
|
a7ba9f1886 | ||
|
|
d5192e2244 | ||
|
|
7eb595170f | ||
|
|
bd576ca808 | ||
|
|
2f8146b11f | ||
|
|
7f321c89cb | ||
|
|
fa65f606b8 | ||
|
|
7a3285adaf | ||
|
|
8bf78fef10 | ||
|
|
78f97ce4df | ||
|
|
66ccbf70f8 | ||
|
|
cb48600b40 | ||
|
|
33ce235713 | ||
|
|
f1a68ece01 | ||
|
|
dd563360af | ||
|
|
7f6dac4271 | ||
|
|
178fd8e828 | ||
|
|
1641e02a7d | ||
|
|
cfd04e9bb4 | ||
|
|
38effaf740 | ||
|
|
a68eb4a73e | ||
|
|
c02990ef98 | ||
|
|
5aa7d5ffe9 | ||
|
|
4942b0fca5 | ||
|
|
aed1bdff5a | ||
|
|
929c840006 | ||
|
|
57aef1d3c2 | ||
|
|
c1734a094c | ||
|
|
99c46685ac | ||
|
|
066b08040a | ||
|
|
35de2334fb | ||
|
|
5564c966a5 | ||
|
|
0891b5e7b7 | ||
|
|
f3341f201f | ||
|
|
bf0dafabe2 | ||
|
|
60f6587169 | ||
|
|
a9bf32919e | ||
|
|
7633f9f88b | ||
|
|
9b56233938 | ||
|
|
65074264b8 | ||
|
|
4f6fceb87f | ||
|
|
659fdd1d37 | ||
|
|
8bce2ce040 | ||
|
|
55cc83a5d4 | ||
|
|
6a51e93ded | ||
|
|
fcf570e96e | ||
|
|
cbc184e953 | ||
|
|
98f9063352 | ||
|
|
c278f1af00 | ||
|
|
fbb17a0ba5 | ||
|
|
8637a9823e | ||
|
|
d717fe7e8c | ||
|
|
5e8dfe7267 | ||
|
|
aaa4fbcdbd | ||
|
|
150f0cf486 | ||
|
|
711b220a05 | ||
|
|
b615c485f7 | ||
|
|
2f3b6b29ae | ||
|
|
7aecd83c4a | ||
|
|
3b460ab91f | ||
|
|
661c0eb970 | ||
|
|
f4a1f1fdc8 | ||
|
|
b5432c3728 | ||
|
|
6d0625c409 | ||
|
|
2f1ea08b8a | ||
|
|
a092da1943 | ||
|
|
43ef3cc562 | ||
|
|
047774475c | ||
|
|
91b8504df5 | ||
|
|
a4fb2dfcf8 | ||
|
|
ba16ec02e5 | ||
|
|
55b7af2623 | ||
|
|
b428eff10e | ||
|
|
35aee15b6d | ||
|
|
6f53c1bfde | ||
|
|
db0230ed75 | ||
|
|
7fa3c1e12a | ||
|
|
3b5993652f | ||
|
|
be4ad8947f | ||
|
|
2ead15e78e | ||
|
|
aa0740ff94 | ||
|
|
6d3f837820 | ||
|
|
359b82c29c | ||
|
|
b54171bc2c | ||
|
|
936b2131e0 | ||
|
|
aaef6a9e9c | ||
|
|
9327006e61 | ||
|
|
5225c841ae | ||
|
|
8464e319fd | ||
|
|
98b8bd90ea | ||
|
|
ae94993b09 | ||
|
|
72f10aaed1 | ||
|
|
4a74bae8c7 | ||
|
|
5164aec37b | ||
|
|
1581e9b1cd | ||
|
|
536e3ffb11 | ||
|
|
d6103191ba | ||
|
|
49e37a19a5 | ||
|
|
d02431e260 | ||
|
|
f24f6ead92 | ||
|
|
b7bdb7ae50 | ||
|
|
2dcf8ac96f | ||
|
|
5421c94853 | ||
|
|
10f6bc092a | ||
|
|
be9ea4ea8e | ||
|
|
f5c6fa842a | ||
|
|
e0943ce905 | ||
|
|
61e7df77a7 | ||
|
|
a5434360bc | ||
|
|
ba29c66e3b | ||
|
|
b3a72d55ae | ||
|
|
c382ad1cc8 | ||
|
|
363e28f323 | ||
|
|
d695656b8c | ||
|
|
31c6cbc0a2 | ||
|
|
b93284bc2f | ||
|
|
99c855b01b | ||
|
|
c2eaedc959 | ||
|
|
a631cd67ec | ||
|
|
66fccd3c68 | ||
|
|
9a4ebf4daa | ||
|
|
91c14211c6 | ||
|
|
1ea07c458b | ||
|
|
591add6e0c | ||
|
|
b99fff66df | ||
|
|
f54ba05b00 | ||
|
|
6596fb00c7 | ||
|
|
df0b5a80dc | ||
|
|
8cdbb31dbe | ||
|
|
0be4b1222d | ||
|
|
18a6bfd73a | ||
|
|
5e2271b237 | ||
|
|
798999d490 | ||
|
|
0e68c5e8bc | ||
|
|
9694af82f4 | ||
|
|
28a4386975 | ||
|
|
a238f7beba | ||
|
|
75ba16281b | ||
|
|
ad65a278d4 | ||
|
|
a2320b3f8d | ||
|
|
ae12853ad0 | ||
|
|
68adf6dc2f | ||
|
|
f88989bd4b | ||
|
|
77ef3847ce | ||
|
|
b8291837fc | ||
|
|
423a7f951a | ||
|
|
557f5fe364 | ||
|
|
5308970ad8 | ||
|
|
6b368953f4 | ||
|
|
2d0b63c29d | ||
|
|
34e941c8cb | ||
|
|
76cf007fff | ||
|
|
321963be83 | ||
|
|
c733bda6c3 | ||
|
|
e67b50b976 | ||
|
|
9e3c080909 | ||
|
|
cb661aaebd | ||
|
|
573571978c | ||
|
|
dc492a2a0a | ||
|
|
e47747dd0e | ||
|
|
4de944b41e | ||
|
|
5f7a1fa5cd | ||
|
|
b8ad328cde | ||
|
|
3076fd19c1 | ||
|
|
fac437b8c1 | ||
|
|
697c25015e | ||
|
|
d83b404fc3 | ||
|
|
ab7313cbc4 | ||
|
|
1b8d70322b | ||
|
|
844ffab4ed | ||
|
|
f5d0513d1f | ||
|
|
557abd4285 | ||
|
|
f4f1a0fbc6 | ||
|
|
74e10dc012 | ||
|
|
359812b7ed | ||
|
|
c2449e53c4 | ||
|
|
1a91249da2 | ||
|
|
b9162f9576 | ||
|
|
f726e8a7b3 | ||
|
|
2f284cfdc9 | ||
|
|
b74696adba | ||
|
|
c8ccba0192 | ||
|
|
41b0e05f62 | ||
|
|
847d5f1b3b | ||
|
|
0445f9dfc2 | ||
|
|
3001c780bd | ||
|
|
68ad5e2320 | ||
|
|
b5e229b19c | ||
|
|
453d798fcf | ||
|
|
451afdb660 | ||
|
|
d298bda92c | ||
|
|
fd99ba6255 | ||
|
|
6ade0b2b1a | ||
|
|
9902003da9 | ||
|
|
0ff2fcac11 | ||
|
|
e80be8e7b6 | ||
|
|
fe0ad0f5cb | ||
|
|
cb8e162f4e | ||
|
|
ae8c30fe57 | ||
|
|
ab82db9e22 | ||
|
|
cb9d3098de | ||
|
|
c927419c99 | ||
|
|
c009026961 | ||
|
|
51cf442fa5 | ||
|
|
954e3553ee | ||
|
|
cde17385b4 | ||
|
|
5b9e078061 | ||
|
|
0290d9ddfc | ||
|
|
eab671d102 | ||
|
|
f9a96ff914 | ||
|
|
3ec2b46d28 | ||
|
|
aec30b89e0 | ||
|
|
309c33e190 | ||
|
|
9c0276f97b | ||
|
|
0a3402ff43 | ||
|
|
bd82308024 | ||
|
|
db3b634e62 | ||
|
|
40bcb22977 | ||
|
|
4bd94092f1 | ||
|
|
cac1ce6895 | ||
|
|
5c3696123a | ||
|
|
4140fc86ee | ||
|
|
2ad771e7fd | ||
|
|
5a38468144 | ||
|
|
0a9c81772f | ||
|
|
c9649ac501 | ||
|
|
6ea567742b | ||
|
|
f31349eaa0 | ||
|
|
9d44668d5f | ||
|
|
a12f58c1c7 | ||
|
|
b5283eaaed | ||
|
|
4b6189af5f | ||
|
|
5d0ffbe453 | ||
|
|
502706931e | ||
|
|
57c411288f | ||
|
|
b09b7b11a1 | ||
|
|
1a7b3c7294 | ||
|
|
4678fc7dde | ||
|
|
9f492fad49 | ||
|
|
bd0a959e18 | ||
|
|
dd605e2610 | ||
|
|
9910f6b817 | ||
|
|
991897aff4 | ||
|
|
3cde019208 | ||
|
|
2f6efbed63 | ||
|
|
5cff4e299b | ||
|
|
bce33639da | ||
|
|
366c465cad | ||
|
|
acc6e05bdc | ||
|
|
4ce15577cd | ||
|
|
98fa4d5e65 | ||
|
|
7fe94076c7 | ||
|
|
b8b0c8fa63 | ||
|
|
e585e87bec | ||
|
|
6a4924bb16 | ||
|
|
ab0d516d91 | ||
|
|
b756ae39d0 | ||
|
|
c15c38ea8f | ||
|
|
743963318f | ||
|
|
ed3fc50858 | ||
|
|
5b886fe6be | ||
|
|
7074bbc405 | ||
|
|
ef314c1707 | ||
|
|
a3e7626dd9 | ||
|
|
5cb5d74eed | ||
|
|
6eee10d46d | ||
|
|
2d95f2b0d6 | ||
|
|
ec41bb9c70 | ||
|
|
2d1780b1cf | ||
|
|
d9ce99887c | ||
|
|
9b9cc90414 | ||
|
|
c1eb539a5c | ||
|
|
e1793f57ef | ||
|
|
dbd09a8743 | ||
|
|
0d189ca617 | ||
|
|
dc9bcc40ee | ||
|
|
4991f7ff39 | ||
|
|
a393b8b122 | ||
|
|
c73b354386 | ||
|
|
392ecee3ff | ||
|
|
bae721c49e | ||
|
|
4e806e21a6 | ||
|
|
ec0fdf83b2 | ||
|
|
cb94d8414f | ||
|
|
8890051c17 | ||
|
|
cf00c9476f | ||
|
|
b2a24c7abd | ||
|
|
732a1f4694 | ||
|
|
4c5aa7084e | ||
|
|
fe1fea671c | ||
|
|
04c754c0ac | ||
|
|
754c22c84e | ||
|
|
629331870b | ||
|
|
78774315cb | ||
|
|
36b9c07928 | ||
|
|
40a818630d | ||
|
|
568511a4cf | ||
|
|
109fb39e09 | ||
|
|
68450d2042 | ||
|
|
8a052bbed6 | ||
|
|
3afbb56640 | ||
|
|
c0ad84a491 | ||
|
|
c72f17605c | ||
|
|
42fbee0cdb | ||
|
|
e9b7ec735f | ||
|
|
743788135f | ||
|
|
8ea3e6fa26 | ||
|
|
f23c83e681 | ||
|
|
b615bda17e | ||
|
|
f7c7cd1d3c | ||
|
|
c7e7be4379 | ||
|
|
d63d49f246 | ||
|
|
dad94edb20 | ||
|
|
7108d5f3ab | ||
|
|
ef47a74920 | ||
|
|
a43dab8057 | ||
|
|
f44039b628 | ||
|
|
08fa5205b0 | ||
|
|
b91daebd92 | ||
|
|
9cd6c5c624 | ||
|
|
650e017b72 | ||
|
|
18f9d6dec5 | ||
|
|
4df6571ad9 | ||
|
|
0f5923a10a | ||
|
|
bcdae1169e | ||
|
|
f260d5df49 | ||
|
|
808b861dd1 | ||
|
|
17f1c487a8 | ||
|
|
8dc2c1a38f | ||
|
|
220a494692 | ||
|
|
db6bc10196 | ||
|
|
1880363aeb | ||
|
|
19c7b59883 | ||
|
|
749df89229 | ||
|
|
444f2172fa | ||
|
|
77a77c0ea7 | ||
|
|
dbf380a0d1 | ||
|
|
ade34f5217 | ||
|
|
e89607799a | ||
|
|
d05d8d6a9e | ||
|
|
b6aa50d3dc | ||
|
|
9df361935f | ||
|
|
98b8a122b6 | ||
|
|
c7232522ee | ||
|
|
5280f1d745 | ||
|
|
b52a081e7b | ||
|
|
f981a44861 | ||
|
|
d7c5ce0750 | ||
|
|
9ccc66ca1e | ||
|
|
8606af3616 | ||
|
|
f6e821ba6b | ||
|
|
e8dbcf819b | ||
|
|
bbe2ef4e8e | ||
|
|
dd15455031 | ||
|
|
12ac7bb338 | ||
|
|
46ef348f0d | ||
|
|
1a55cca8af | ||
|
|
81ee989f1f | ||
|
|
c9c06f8a3d | ||
|
|
72127979c3 | ||
|
|
1ad3ddef94 | ||
|
|
97ec5eabf7 | ||
|
|
e12e3a3f2d | ||
|
|
4ff625f23b | ||
|
|
e38dcd85ac | ||
|
|
0245baf1b6 | ||
|
|
10b55c043c | ||
|
|
457655b416 | ||
|
|
7e4506c860 | ||
|
|
794d376348 | ||
|
|
c60578f5b5 | ||
|
|
3a9a392a77 | ||
|
|
a13d4698be | ||
|
|
c046a1993e | ||
|
|
f709117cc4 | ||
|
|
30dd298fca | ||
|
|
0ff8bb8090 | ||
|
|
74bbd3c3a2 | ||
|
|
2e82eaf59a | ||
|
|
7f1df1f1bd | ||
|
|
3c79238a44 | ||
|
|
0aa2565df3 | ||
|
|
22b11db16e | ||
|
|
d0e678b5e9 | ||
|
|
e7bba968b3 | ||
|
|
4934a24293 | ||
|
|
ccb68bcda9 | ||
|
|
66bf4ba3ad | ||
|
|
78a0cfd052 | ||
|
|
8548373742 | ||
|
|
2dfd725ee0 | ||
|
|
5b779b4f14 | ||
|
|
fc48aa7155 | ||
|
|
6193a842f4 | ||
|
|
eb86b471fe | ||
|
|
2b52584547 | ||
|
|
6e3cc57f48 | ||
|
|
f2c04621a5 | ||
|
|
3ed6938d4a | ||
|
|
99fec25ed5 | ||
|
|
73758ad1fd | ||
|
|
c53fe0ed1f | ||
|
|
6082c2bcac | ||
|
|
069abed784 | ||
|
|
7d8fa4d78a | ||
|
|
76081f8d89 | ||
|
|
5ef4285558 | ||
|
|
aa7df4282e | ||
|
|
0ef1d5d0de | ||
|
|
cceb4bb81f | ||
|
|
f0f45e007d | ||
|
|
6a8ffe1642 | ||
|
|
3a73868c10 | ||
|
|
ab1b5897a6 | ||
|
|
f94734a5c8 | ||
|
|
61b86c9584 | ||
|
|
1ac1d6e903 | ||
|
|
b6c58f74c0 | ||
|
|
c88e99d87c | ||
|
|
8d7ab9d05e | ||
|
|
47155a4a29 | ||
|
|
d0b87fd7c3 | ||
|
|
d49fd37656 | ||
|
|
0bd29d71be | ||
|
|
4b5b62c8ae | ||
|
|
65fb2ca2d5 | ||
|
|
0d5bfc0997 | ||
|
|
4f02c373c2 | ||
|
|
209a5b1207 | ||
|
|
95349eacab | ||
|
|
82ba604b99 | ||
|
|
46a8dec655 | ||
|
|
b5af234524 | ||
|
|
b5c41750f7 | ||
|
|
6083824eec | ||
|
|
40977785c3 | ||
|
|
5eddf4f1aa | ||
|
|
99a8e25411 | ||
|
|
08587d8f2f | ||
|
|
3480d50f61 | ||
|
|
43af55252d | ||
|
|
9c43b31fc0 | ||
|
|
9ec7184aa1 | ||
|
|
4e2cb30db7 | ||
|
|
9ca83d3291 | ||
|
|
6b2172d873 | ||
|
|
1a5d9f7dad | ||
|
|
a8425862f0 | ||
|
|
a3a3db6abb | ||
|
|
d6c3bc57c0 | ||
|
|
59c09f90f9 | ||
|
|
d982b83e14 | ||
|
|
cc0e930d34 | ||
|
|
3c3d77fbea | ||
|
|
da7453fdbf | ||
|
|
5fcd25506e | ||
|
|
4979a472de | ||
|
|
4e8d4f4591 | ||
|
|
0f5d2b15e0 | ||
|
|
7fc9631434 | ||
|
|
df5953dd7b | ||
|
|
8f5b2b4a0e | ||
|
|
43c63ffa70 | ||
|
|
6779bc7459 | ||
|
|
664be2d0ba | ||
|
|
6113898b69 | ||
|
|
79aad6b5c2 | ||
|
|
6da7757d36 | ||
|
|
dbb3cb8cc8 | ||
|
|
579f36a1dd | ||
|
|
72c2b306cf | ||
|
|
c2673cd396 | ||
|
|
8eb152816a | ||
|
|
a0bc8a21a5 | ||
|
|
08e4d72758 | ||
|
|
66340a27fa | ||
|
|
83fe9835b6 | ||
|
|
4c1a50a3ca | ||
|
|
fe44a7b3bc | ||
|
|
e86d192db7 | ||
|
|
ea8f1c52f9 | ||
|
|
a4c1573c45 | ||
|
|
182bf49ad0 | ||
|
|
13e1ddbccd | ||
|
|
327b9a1757 | ||
|
|
18c48db7f7 | ||
|
|
b6543bd87f | ||
|
|
9ad8f71d7c | ||
|
|
e369311fc2 | ||
|
|
72ff261fe3 | ||
|
|
774c6f7e05 | ||
|
|
771af6ae08 | ||
|
|
b3cd207444 | ||
|
|
03f9fa4bc2 | ||
|
|
e32bfd9aab | ||
|
|
7e47f8f893 | ||
|
|
cb816e9653 | ||
|
|
6b3e7cbc08 | ||
|
|
db4993ae9b | ||
|
|
4dc3cf6c6b | ||
|
|
2b84bbf3a8 | ||
|
|
26ef4c9961 | ||
|
|
4f56c38599 | ||
|
|
240f4dcfb1 | ||
|
|
ac6abd81c9 | ||
|
|
14bda4f3a5 | ||
|
|
61b9670b45 | ||
|
|
01e8db317e | ||
|
|
92fc09493e | ||
|
|
d927209db7 | ||
|
|
e94007b21f | ||
|
|
18750f275a | ||
|
|
d686a853f4 |
@@ -1,9 +0,0 @@
|
|||||||
[target.aarch64-unknown-linux-gnu]
|
|
||||||
linker = "aarch64-linux-gnu-gcc"
|
|
||||||
|
|
||||||
[target.armv7-unknown-linux-gnueabihf]
|
|
||||||
linker = "arm-linux-gnueabihf-gcc"
|
|
||||||
|
|
||||||
[alias]
|
|
||||||
clippy-all = "clippy --all-targets --all-features -- -D warnings"
|
|
||||||
clippy-only = "clippy --all-targets --features clippy -- -D warnings"
|
|
||||||
@@ -1,101 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "Clash Verge Rev Development Environment",
|
|
||||||
"image": "mcr.microsoft.com/devcontainers/base:ubuntu-22.04",
|
|
||||||
|
|
||||||
"features": {
|
|
||||||
"ghcr.io/devcontainers/features/node:1": {
|
|
||||||
"version": "20"
|
|
||||||
},
|
|
||||||
"ghcr.io/devcontainers/features/rust:1": {
|
|
||||||
"version": "latest",
|
|
||||||
"profile": "default"
|
|
||||||
},
|
|
||||||
"ghcr.io/devcontainers/features/git:1": {},
|
|
||||||
"ghcr.io/devcontainers/features/github-cli:1": {},
|
|
||||||
"ghcr.io/devcontainers/features/docker-in-docker:2": {}
|
|
||||||
},
|
|
||||||
|
|
||||||
"customizations": {
|
|
||||||
"vscode": {
|
|
||||||
"extensions": [
|
|
||||||
"rust-lang.rust-analyzer",
|
|
||||||
"tauri-apps.tauri-vscode",
|
|
||||||
"ms-vscode.vscode-typescript-next",
|
|
||||||
"esbenp.prettier-vscode",
|
|
||||||
"bradlc.vscode-tailwindcss",
|
|
||||||
"ms-vscode.vscode-json",
|
|
||||||
"redhat.vscode-yaml",
|
|
||||||
"formulahendry.auto-rename-tag",
|
|
||||||
"ms-vscode.hexeditor",
|
|
||||||
"christian-kohler.path-intellisense",
|
|
||||||
"yzhang.markdown-all-in-one",
|
|
||||||
"streetsidesoftware.code-spell-checker",
|
|
||||||
"ms-vscode.vscode-eslint"
|
|
||||||
],
|
|
||||||
"settings": {
|
|
||||||
"rust-analyzer.cargo.features": ["verge-dev"],
|
|
||||||
"rust-analyzer.check.command": "clippy",
|
|
||||||
"editor.formatOnSave": true,
|
|
||||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
|
||||||
"[rust]": {
|
|
||||||
"editor.defaultFormatter": "rust-lang.rust-analyzer"
|
|
||||||
},
|
|
||||||
"[json]": {
|
|
||||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
|
||||||
},
|
|
||||||
"[yaml]": {
|
|
||||||
"editor.defaultFormatter": "redhat.vscode-yaml"
|
|
||||||
},
|
|
||||||
"[typescript]": {
|
|
||||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
|
||||||
},
|
|
||||||
"[typescriptreact]": {
|
|
||||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
"forwardPorts": [1420, 3000, 8080, 9090, 7890, 7891],
|
|
||||||
|
|
||||||
"portsAttributes": {
|
|
||||||
"1420": {
|
|
||||||
"label": "Tauri Dev Server",
|
|
||||||
"onAutoForward": "notify"
|
|
||||||
},
|
|
||||||
"3000": {
|
|
||||||
"label": "Vite Dev Server",
|
|
||||||
"onAutoForward": "notify"
|
|
||||||
},
|
|
||||||
"7890": {
|
|
||||||
"label": "Clash HTTP Proxy",
|
|
||||||
"onAutoForward": "silent"
|
|
||||||
},
|
|
||||||
"7891": {
|
|
||||||
"label": "Clash SOCKS Proxy",
|
|
||||||
"onAutoForward": "silent"
|
|
||||||
},
|
|
||||||
"9090": {
|
|
||||||
"label": "Clash API",
|
|
||||||
"onAutoForward": "silent"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
"postCreateCommand": "bash .devcontainer/post-create.sh",
|
|
||||||
|
|
||||||
"mounts": [
|
|
||||||
"source=clash-verge-node-modules,target=${containerWorkspaceFolder}/node_modules,type=volume",
|
|
||||||
"source=clash-verge-cargo-registry,target=/usr/local/cargo/registry,type=volume",
|
|
||||||
"source=clash-verge-cargo-git,target=/usr/local/cargo/git,type=volume"
|
|
||||||
],
|
|
||||||
|
|
||||||
"containerEnv": {
|
|
||||||
"RUST_BACKTRACE": "1",
|
|
||||||
"NODE_OPTIONS": "--max-old-space-size=4096",
|
|
||||||
"TAURI_DEV_WATCHER_IGNORE_FILE": ".taurignore"
|
|
||||||
},
|
|
||||||
|
|
||||||
"remoteUser": "vscode",
|
|
||||||
"workspaceFolder": "/workspaces/clash-verge-rev",
|
|
||||||
"shutdownAction": "stopContainer"
|
|
||||||
}
|
|
||||||
1
.github/FUNDING.yml
vendored
@@ -1 +0,0 @@
|
|||||||
github: clash-verge-rev
|
|
||||||
43
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -2,42 +2,29 @@ name: 问题反馈 / Bug report
|
|||||||
title: "[BUG] "
|
title: "[BUG] "
|
||||||
description: 反馈你遇到的问题 / Report the issue you are experiencing
|
description: 反馈你遇到的问题 / Report the issue you are experiencing
|
||||||
labels: ["bug"]
|
labels: ["bug"]
|
||||||
type: "Bug"
|
|
||||||
|
|
||||||
body:
|
body:
|
||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
value: |
|
value: |
|
||||||
## 在提交问题之前,请确认以下事项:
|
## 在提交问题之前,请确认以下事项:
|
||||||
|
1. 请 **确保** 您已经查阅了 [Clash Verge Rev 官方文档](https://clash-verge-rev.github.io/guide.html) 以及 [常见问题](https://clash-verge-rev.github.io/faq/install/)
|
||||||
1. 请 **确保** 您已经查阅了 [Clash Verge Rev 官方文档](https://clash-verge-rev.github.io/guide/term.html) 以及 [常见问题](https://clash-verge-rev.github.io/faq/windows.html)
|
|
||||||
2. 请 **确保** [已有的问题](https://github.com/clash-verge-rev/clash-verge-rev/issues?q=is%3Aissue) 中没有人提交过相似issue,否则请在已有的issue下进行讨论
|
2. 请 **确保** [已有的问题](https://github.com/clash-verge-rev/clash-verge-rev/issues?q=is%3Aissue) 中没有人提交过相似issue,否则请在已有的issue下进行讨论
|
||||||
3. 请 **务必** 给issue填写一个简洁明了的标题,以便他人快速检索
|
3. 请 **务必** 给issue填写一个简洁明了的标题,以便他人快速检索
|
||||||
4. 请 **务必** 查看 [AutoBuild](https://github.com/clash-verge-rev/clash-verge-rev/releases/tag/autobuild) 版本更新日志
|
4. 请 **务必** 先下载 [Alpha](https://github.com/clash-verge-rev/clash-verge-rev/releases/tag/alpha) 版本测试,确保问题依然存在
|
||||||
5. 请 **务必** 尝试 [AutoBuild](https://github.com/clash-verge-rev/clash-verge-rev/releases/tag/autobuild) 版本,确定问题是否仍然存在
|
5. 请 **务必** 按照模板规范详细描述问题,否则issue将会被关闭
|
||||||
6. 请 **务必** 按照模板规范详细描述问题以及尝试更新 Alpha 版本,否则issue将会被直接关闭
|
|
||||||
|
|
||||||
## Before submitting the issue, please make sure of the following checklist:
|
## Before submitting the issue, please make sure of the following checklist:
|
||||||
|
1. Please make sure you have read the [Clash Verge Rev official documentation](https://clash-verge-rev.github.io/guide.html) and [FAQ](https://clash-verge-rev.github.io/faq/install/)
|
||||||
1. Please make sure you have read the [Clash Verge Rev official documentation](https://clash-verge-rev.github.io/guide/term.html) and [FAQ](https://clash-verge-rev.github.io/faq/windows.html)
|
|
||||||
2. Please make sure there is no similar issue in the [existing issues](https://github.com/clash-verge-rev/clash-verge-rev/issues?q=is%3Aissue), otherwise please discuss under the existing issue
|
2. Please make sure there is no similar issue in the [existing issues](https://github.com/clash-verge-rev/clash-verge-rev/issues?q=is%3Aissue), otherwise please discuss under the existing issue
|
||||||
3. Please be sure to fill in a concise and clear title for the issue so that others can quickly search
|
3. Please be sure to fill in a concise and clear title for the issue so that others can quickly search
|
||||||
4. Please be sure to check out [AutoBuild](https://github.com/clash-verge-rev/clash-verge-rev/releases/tag/autobuild) version update log
|
4. Please be sure to download the [Alpha](https://github.com/clash-verge-rev/clash-verge-rev/releases/tag/alpha) version for testing to ensure that the problem still exists
|
||||||
5. Please be sure to try the [AutoBuild](https://github.com/clash-verge-rev/clash-verge-rev/releases/tag/autobuild) version to ensure that the problem still exists
|
5. Please describe the problem in detail according to the template specification, otherwise the issue will be closed
|
||||||
6. Please describe the problem in detail according to the template specification and try to update the Alpha version, otherwise the issue will be closed
|
|
||||||
|
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: description
|
id: description
|
||||||
attributes:
|
attributes:
|
||||||
label: 问题描述 / Describe the bug
|
label: 问题描述 / Describe the bug
|
||||||
description: 详细清晰地描述你遇到的问题,并配合截图 / Describe the problem you encountered in detail and clearly, and provide screenshots
|
description: 详细清晰地描述你遇到的问题 / A clear and concise description of what the bug is
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: 软件版本 / CVR Version
|
|
||||||
description: 请提供 CVR 的具体版本,如果是 AutoBuild 版本,请注明下载时间(精确到小时分钟) / Please provide the specific version of CVR. If it is an AutoBuild version, please indicate the download time (accurate to hours and minutes)
|
|
||||||
render: text
|
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
@@ -46,13 +33,13 @@ body:
|
|||||||
description: 请提供复现问题的步骤 / Steps to reproduce the behavior
|
description: 请提供复现问题的步骤 / Steps to reproduce the behavior
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: checkboxes
|
- type: dropdown
|
||||||
attributes:
|
attributes:
|
||||||
label: 操作系统 / OS
|
label: 操作系统 / OS
|
||||||
options:
|
options:
|
||||||
- label: Windows
|
- Windows
|
||||||
- label: Linux
|
- Linux
|
||||||
- label: MacOS
|
- MacOS
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: input
|
- type: input
|
||||||
@@ -63,11 +50,7 @@ body:
|
|||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
label: 日志(勿上传日志文件,请粘贴日志内容) / Log (Do not upload the log file, paste the log content directly)
|
label: 日志 / Log
|
||||||
description: 请提供完整或相关部分的Debug日志(请在“软件左侧菜单”->“设置”->“日志等级”调整到debug,Verge错误请把“杂项设置”->“app日志等级”调整到debug,并重启Verge生效。日志文件在“软件左侧菜单”->“设置”->“日志目录”下) / Please provide a complete or relevant part of the Debug log (please adjust the "Log level" to debug in "Software left menu" -> "Settings" -> "Log level". If there is a Verge error, please adjust "Miscellaneous settings" -> "app log level" to debug, and restart Verge to take effect. The log file is under "Software left menu" -> "Settings" -> "Log directory")
|
description: 请提供完整或相关部分的Debug日志 / Please provide the complete or relevant part of the Debug log
|
||||||
placeholder: |
|
|
||||||
日志目录一般位于 Clash Verge Rev 安装目录的 "logs/" 子目录中,请将日志内容粘贴到此处。
|
|
||||||
Log directory is usually located in the "logs/" subdirectory of the Clash Verge Rev installation directory, please paste the log content here.
|
|
||||||
render: log
|
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
|
|||||||
1
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -1,4 +1,3 @@
|
|||||||
blank_issues_enabled: false
|
|
||||||
contact_links:
|
contact_links:
|
||||||
- name: 讨论交流 / Communication
|
- name: 讨论交流 / Communication
|
||||||
url: https://t.me/clash_verge_rev
|
url: https://t.me/clash_verge_rev
|
||||||
|
|||||||
20
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
@@ -2,23 +2,22 @@ name: 功能请求 / Feature request
|
|||||||
title: "[Feature] "
|
title: "[Feature] "
|
||||||
description: 提出你的功能请求 / Propose your feature request
|
description: 提出你的功能请求 / Propose your feature request
|
||||||
labels: ["enhancement"]
|
labels: ["enhancement"]
|
||||||
type: "Feature"
|
|
||||||
|
|
||||||
body:
|
body:
|
||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
value: |
|
value: |
|
||||||
## 在提交问题之前,请确认以下事项:
|
## 在提交问题之前,请确认以下事项:
|
||||||
1. 请 **确保** 您已经查阅了 [Clash Verge Rev 官方文档](https://clash-verge-rev.github.io/guide/term.html) 确认软件不存在类似的功能
|
1. 请 **确保** 您已经查阅了 [Clash Verge Rev 官方文档](https://clash-verge-rev.github.io/guide.html) 确认软件不存在类似的功能
|
||||||
2. 请 **确保** [已有的问题](https://github.com/clash-verge-rev/clash-verge-rev/issues?q=is%3Aissue) 中没有人提交过相似issue,否则请在已有的issue下进行讨论
|
2. 请 **确保** [已有的问题](https://github.com/clash-verge-rev/clash-verge-rev/issues?q=is%3Aissue) 中没有人提交过相似issue,否则请在已有的issue下进行讨论
|
||||||
3. 请 **务必** 给issue填写一个简洁明了的标题,以便他人快速检索
|
3. 请 **务必** 给issue填写一个简洁明了的标题,以便他人快速检索
|
||||||
4. 请 **务必** 先下载 [AutoBuild](https://github.com/clash-verge-rev/clash-verge-rev/releases/tag/autobuild) 版本测试,确保该功能还未实现
|
4. 请 **务必** 先下载 [Alpha](https://github.com/clash-verge-rev/clash-verge-rev/releases/tag/alpha) 版本测试,确保该功能还未实现
|
||||||
5. 请 **务必** 按照模板规范详细描述问题,否则issue将会被关闭
|
5. 请 **务必** 按照模板规范详细描述问题,否则issue将会被关闭
|
||||||
## Before submitting the issue, please make sure of the following checklist:
|
## Before submitting the issue, please make sure of the following checklist:
|
||||||
1. Please make sure you have read the [Clash Verge Rev official documentation](https://clash-verge-rev.github.io/guide/term.html) to confirm that the software does not have similar functions
|
1. Please make sure you have read the [Clash Verge Rev official documentation](https://clash-verge-rev.github.io/guide.html) to confirm that the software does not have similar functions
|
||||||
2. Please make sure there is no similar issue in the [existing issues](https://github.com/clash-verge-rev/clash-verge-rev/issues?q=is%3Aissue), otherwise please discuss under the existing issue
|
2. Please make sure there is no similar issue in the [existing issues](https://github.com/clash-verge-rev/clash-verge-rev/issues?q=is%3Aissue), otherwise please discuss under the existing issue
|
||||||
3. Please be sure to fill in a concise and clear title for the issue so that others can quickly search
|
3. Please be sure to fill in a concise and clear title for the issue so that others can quickly search
|
||||||
4. Please be sure to download the [AutoBuild](https://github.com/clash-verge-rev/clash-verge-rev/releases/tag/autobuild) version for testing to ensure that the function has not been implemented
|
4. Please be sure to download the [Alpha](https://github.com/clash-verge-rev/clash-verge-rev/releases/tag/alpha) version for testing to ensure that the function has not been implemented
|
||||||
5. Please describe the problem in detail according to the template specification, otherwise the issue will be closed
|
5. Please describe the problem in detail according to the template specification, otherwise the issue will be closed
|
||||||
|
|
||||||
- type: textarea
|
- type: textarea
|
||||||
@@ -34,14 +33,3 @@ body:
|
|||||||
description: 请描述你的功能请求的使用场景 / Please describe the use case of your feature request
|
description: 请描述你的功能请求的使用场景 / Please describe the use case of your feature request
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: checkboxes
|
|
||||||
id: os-labels
|
|
||||||
attributes:
|
|
||||||
label: 适用系统 / Target OS
|
|
||||||
description: 请选择该功能适用的操作系统(至少选择一个) / Please select the operating system(s) for this feature request (select at least one)
|
|
||||||
options:
|
|
||||||
- label: windows
|
|
||||||
- label: macos
|
|
||||||
- label: linux
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|||||||
58
.github/ISSUE_TEMPLATE/i18n_request.yml
vendored
@@ -1,58 +0,0 @@
|
|||||||
name: I18N / 多语言相关
|
|
||||||
title: "[I18N] "
|
|
||||||
description: 用于多语言翻译、国际化相关问题或建议 / For issues or suggestions related to translations and internationalization
|
|
||||||
labels: ["I18n"]
|
|
||||||
type: "Task"
|
|
||||||
|
|
||||||
body:
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: |
|
|
||||||
## I18N 相关问题/建议
|
|
||||||
请用此模板提交翻译错误、缺失、建议或新增语言请求。
|
|
||||||
Please use this template for translation errors, missing translations, suggestions, or new language requests.
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
id: description
|
|
||||||
attributes:
|
|
||||||
label: 问题描述 / Description
|
|
||||||
description: 详细描述你的 I18N 问题或建议 / Please describe your I18N issue or suggestion in detail
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: input
|
|
||||||
id: language
|
|
||||||
attributes:
|
|
||||||
label: 相关语言 / Language
|
|
||||||
description: 例如 zh, en, jp, ru, ... / e.g. zh, en, jp, ru, ...
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
id: suggestion
|
|
||||||
attributes:
|
|
||||||
label: 建议或修正内容 / Suggestion or Correction
|
|
||||||
description: 如果是翻译修正或建议,请填写建议的内容 / If this is a translation correction or suggestion, please provide the suggested content
|
|
||||||
validations:
|
|
||||||
required: false
|
|
||||||
|
|
||||||
- type: checkboxes
|
|
||||||
id: i18n-type
|
|
||||||
attributes:
|
|
||||||
label: 问题类型 / Issue Type
|
|
||||||
description: 请选择适用类型(可多选) / Please select the applicable type(s)
|
|
||||||
options:
|
|
||||||
- label: 翻译错误 / Translation error
|
|
||||||
- label: 翻译缺失 / Missing translation
|
|
||||||
- label: 建议优化 / Suggestion
|
|
||||||
- label: 新增语言 / New language
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: input
|
|
||||||
id: verge-version
|
|
||||||
attributes:
|
|
||||||
label: 软件版本 / CVR Version
|
|
||||||
description: 请提供你使用的 CVR 具体版本 / Please provide the specific version of CVR you are using
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
4
.github/build-for-linux/Dockerfile
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
FROM rust:buster
|
||||||
|
COPY entrypoint.sh /entrypoint.sh
|
||||||
|
RUN chmod a+x /entrypoint.sh
|
||||||
|
ENTRYPOINT ["/entrypoint.sh"]
|
||||||
14
.github/build-for-linux/action.yml
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
name: "Build for Linux"
|
||||||
|
branding:
|
||||||
|
icon: user-check
|
||||||
|
color: gray-dark
|
||||||
|
inputs:
|
||||||
|
target:
|
||||||
|
required: true
|
||||||
|
description: "Rust Target"
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: "docker"
|
||||||
|
image: "Dockerfile"
|
||||||
|
args:
|
||||||
|
- ${{ inputs.target }}
|
||||||
8
.github/build-for-linux/build.sh
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
pnpm install
|
||||||
|
pnpm check $INPUT_TARGET
|
||||||
|
sed -i "s/#openssl/openssl={version=\"0.10\",features=[\"vendored\"]}/g" src-tauri/Cargo.toml
|
||||||
|
if [ "$INPUT_TARGET" = "x86_64-unknown-linux-gnu" ]; then
|
||||||
|
pnpm build --target $INPUT_TARGET
|
||||||
|
else
|
||||||
|
pnpm build --target $INPUT_TARGET -b deb
|
||||||
|
fi
|
||||||
47
.github/build-for-linux/entrypoint.sh
vendored
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
wget https://nodejs.org/dist/v20.10.0/node-v20.10.0-linux-x64.tar.xz
|
||||||
|
tar -Jxvf ./node-v20.10.0-linux-x64.tar.xz
|
||||||
|
export PATH=$(pwd)/node-v20.10.0-linux-x64/bin:$PATH
|
||||||
|
npm install pnpm -g
|
||||||
|
|
||||||
|
rustup target add "$INPUT_TARGET"
|
||||||
|
|
||||||
|
if [ "$INPUT_TARGET" = "x86_64-unknown-linux-gnu" ]; then
|
||||||
|
apt-get update
|
||||||
|
apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev libayatana-appindicator3-dev librsvg2-dev patchelf
|
||||||
|
elif [ "$INPUT_TARGET" = "aarch64-unknown-linux-gnu" ]; then
|
||||||
|
dpkg --add-architecture arm64
|
||||||
|
apt-get update
|
||||||
|
apt-get install -y libncurses6:arm64 libtinfo6:arm64 linux-libc-dev:arm64 libncursesw6:arm64 libssl3:arm64 libcups2:arm64
|
||||||
|
apt-get install -y --no-install-recommends g++-aarch64-linux-gnu libc6-dev-arm64-cross libwebkit2gtk-4.0-dev:arm64 libgtk-3-dev:arm64 patchelf:arm64 librsvg2-dev:arm64 libayatana-appindicator3-dev:arm64
|
||||||
|
export CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc
|
||||||
|
export CC_aarch64_unknown_linux_gnu=aarch64-linux-gnu-gcc
|
||||||
|
export CXX_aarch64_unknown_linux_gnu=aarch64-linux-gnu-g++
|
||||||
|
export PKG_CONFIG_PATH=/usr/lib/aarch64-linux-gnu/pkgconfig
|
||||||
|
export PKG_CONFIG_ALLOW_CROSS=1
|
||||||
|
elif [ "$INPUT_TARGET" = "armv7-unknown-linux-gnueabihf" ]; then
|
||||||
|
dpkg --add-architecture armhf
|
||||||
|
apt-get update
|
||||||
|
apt-get install -y libncurses6:armhf libtinfo6:armhf linux-libc-dev:armhf libncursesw6:armhf libssl3:armhf libcups2:armhf
|
||||||
|
apt-get install -y --no-install-recommends g++-arm-linux-gnueabihf libc6-dev-armhf-cross libwebkit2gtk-4.0-dev:armhf libgtk-3-dev:armhf patchelf:armhf librsvg2-dev:armhf libayatana-appindicator3-dev:armhf
|
||||||
|
export CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc
|
||||||
|
export CC_armv7_unknown_linux_gnueabihf=arm-linux-gnueabihf-gcc
|
||||||
|
export CXX_armv7_unknown_linux_gnueabihf=arm-linux-gnueabihf-g++
|
||||||
|
export PKG_CONFIG_PATH=/usr/lib/arm-linux-gnueabihf/pkgconfig
|
||||||
|
export PKG_CONFIG_ALLOW_CROSS=1
|
||||||
|
elif [ "$INPUT_TARGET" = "riscv64gc-unknown-linux-gnu" ]; then
|
||||||
|
dpkg --add-architecture riscv64
|
||||||
|
apt-get update
|
||||||
|
apt-get install -y libncurses6:riscv64 libtinfo6:riscv64 linux-libc-dev:riscv64 libncursesw6:riscv64 libssl3:riscv64 libcups2:riscv64
|
||||||
|
apt-get install -y --no-install-recommends g++-riscv64-linux-gnu libc6-dev-riscv64-cross libwebkit2gtk-4.0-dev:riscv64 libgtk-3-dev:riscv64 patchelf:riscv64 librsvg2-dev:riscv64 libayatana-appindicator3-dev:riscv64
|
||||||
|
export CARGO_TARGET_RISCV64_UNKNOWN_LINUX_GNU_LINKER=riscv64-linux-gnu-gcc
|
||||||
|
export CC_riscv64_unknown_linux_gnu=riscv64-linux-gnu-gcc
|
||||||
|
export CXX_riscv64_unknown_linux_gnu=riscv64-linux-gnu-g++
|
||||||
|
export PKG_CONFIG_PATH=/usr/lib/riscv64-linux-gnu/pkgconfig
|
||||||
|
export PKG_CONFIG_ALLOW_CROSS=1
|
||||||
|
else
|
||||||
|
echo "Unknown target: $INPUT_TARGET" && exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
bash .github/build-for-linux/build.sh
|
||||||
575
.github/workflows/alpha.yml
vendored
@@ -1,263 +1,17 @@
|
|||||||
name: Alpha Build
|
name: Alpha Build
|
||||||
|
|
||||||
on:
|
on:
|
||||||
# 因为 alpha 不再负责频繁构建,且需要相对于 autobuild 更稳定使用环境
|
|
||||||
# 所以不再使用 workflow_dispatch 触发
|
|
||||||
# 应当通过 git tag 来触发构建
|
|
||||||
# TODO 手动控制版本号
|
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
# inputs:
|
push:
|
||||||
# tag_name:
|
branches: [main]
|
||||||
# description: "Alpha tag name (e.g. v1.2.3-alpha.1)"
|
tags-ignore: [updater, alpha]
|
||||||
# required: true
|
|
||||||
# type: string
|
|
||||||
|
|
||||||
# push:
|
|
||||||
# # 应当限制在 dev 分支上触发发布。
|
|
||||||
# branches:
|
|
||||||
# - dev
|
|
||||||
# # 应当限制 v*.*.*-alpha* 的 tag 来触发发布。
|
|
||||||
# tags:
|
|
||||||
# - "v*.*.*-alpha*"
|
|
||||||
permissions: write-all
|
permissions: write-all
|
||||||
env:
|
env:
|
||||||
TAG_NAME: alpha
|
|
||||||
TAG_CHANNEL: Alpha
|
|
||||||
CARGO_INCREMENTAL: 0
|
CARGO_INCREMENTAL: 0
|
||||||
RUST_BACKTRACE: short
|
RUST_BACKTRACE: short
|
||||||
HUSKY: 0
|
|
||||||
concurrency:
|
|
||||||
group: "${{ github.workflow }} - ${{ github.head_ref || github.ref }}"
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
check_alpha_tag:
|
alpha:
|
||||||
name: Check Alpha Tag package.json Version Consistency
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Check tag and package.json version
|
|
||||||
id: check_tag
|
|
||||||
run: |
|
|
||||||
TAG_REF="${GITHUB_REF##*/}"
|
|
||||||
echo "Current tag: $TAG_REF"
|
|
||||||
if [[ ! "$TAG_REF" =~ -alpha ]]; then
|
|
||||||
echo "Current tag is not an alpha tag."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
PKG_VERSION=$(jq -r .version package.json)
|
|
||||||
echo "package.json version: $PKG_VERSION"
|
|
||||||
if [[ "$PKG_VERSION" != *alpha* ]]; then
|
|
||||||
echo "package.json version is not an alpha version."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
if [[ "$TAG_REF" != "v$PKG_VERSION" ]]; then
|
|
||||||
echo "Tag ($TAG_REF) does not match package.json version (v$PKG_VERSION)."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo "Alpha tag and package.json version are consistent."
|
|
||||||
|
|
||||||
delete_old_assets:
|
|
||||||
name: Delete Old Alpha Release Assets and Tags
|
|
||||||
needs: check_alpha_tag
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Delete Old Alpha Tags Except Latest
|
|
||||||
uses: actions/github-script@v7
|
|
||||||
with:
|
|
||||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
script: |
|
|
||||||
const tagPattern = /-alpha.*/; // 匹配带有 -alpha 的 tag
|
|
||||||
const owner = context.repo.owner;
|
|
||||||
const repo = context.repo.repo;
|
|
||||||
|
|
||||||
try {
|
|
||||||
// 获取所有 tag
|
|
||||||
const { data: tags } = await github.rest.repos.listTags({
|
|
||||||
owner,
|
|
||||||
repo,
|
|
||||||
per_page: 100 // 调整 per_page 以获取更多 tag
|
|
||||||
});
|
|
||||||
|
|
||||||
// 过滤出包含 -alpha 的 tag
|
|
||||||
const alphaTags = (await Promise.all(
|
|
||||||
tags
|
|
||||||
.filter(tag => tagPattern.test(tag.name))
|
|
||||||
.map(async tag => {
|
|
||||||
// 获取每个 tag 的 commit 信息以获得日期
|
|
||||||
const { data: commit } = await github.rest.repos.getCommit({
|
|
||||||
owner,
|
|
||||||
repo,
|
|
||||||
ref: tag.commit.sha
|
|
||||||
});
|
|
||||||
return {
|
|
||||||
...tag,
|
|
||||||
commitDate: commit.committer && commit.committer.date ? commit.committer.date : commit.commit.author.date
|
|
||||||
};
|
|
||||||
})
|
|
||||||
)).sort((a, b) => {
|
|
||||||
// 按 commit 日期降序排序(最新的在前面)
|
|
||||||
return new Date(b.commitDate) - new Date(a.commitDate);
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log(`Found ${alphaTags.length} alpha tags`);
|
|
||||||
|
|
||||||
if (alphaTags.length === 0) {
|
|
||||||
console.log('No alpha tags found');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 保留最新的 tag
|
|
||||||
const latestTag = alphaTags[0];
|
|
||||||
console.log(`Keeping latest alpha tag: ${latestTag.name}`);
|
|
||||||
|
|
||||||
// 处理其他旧的 alpha tag
|
|
||||||
for (const tag of alphaTags.slice(1)) {
|
|
||||||
console.log(`Processing tag: ${tag.name}`);
|
|
||||||
|
|
||||||
// 获取与 tag 关联的 release
|
|
||||||
try {
|
|
||||||
const { data: release } = await github.rest.repos.getReleaseByTag({
|
|
||||||
owner,
|
|
||||||
repo,
|
|
||||||
tag: tag.name
|
|
||||||
});
|
|
||||||
|
|
||||||
// 删除 release 下的所有资产
|
|
||||||
if (release.assets && release.assets.length > 0) {
|
|
||||||
console.log(`Deleting ${release.assets.length} assets for release ${tag.name}`);
|
|
||||||
for (const asset of release.assets) {
|
|
||||||
console.log(`Deleting asset: ${asset.name} (${asset.id})`);
|
|
||||||
await github.rest.repos.deleteReleaseAsset({
|
|
||||||
owner,
|
|
||||||
repo,
|
|
||||||
asset_id: asset.id
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 删除 release
|
|
||||||
console.log(`Deleting release for tag: ${tag.name}`);
|
|
||||||
await github.rest.repos.deleteRelease({
|
|
||||||
owner,
|
|
||||||
repo,
|
|
||||||
release_id: release.id
|
|
||||||
});
|
|
||||||
|
|
||||||
// 删除 tag
|
|
||||||
console.log(`Deleting tag: ${tag.name}`);
|
|
||||||
await github.rest.git.deleteRef({
|
|
||||||
owner,
|
|
||||||
repo,
|
|
||||||
ref: `tags/${tag.name}`
|
|
||||||
});
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
if (error.status === 404) {
|
|
||||||
console.log(`No release found for tag ${tag.name}, deleting tag directly`);
|
|
||||||
await github.rest.git.deleteRef({
|
|
||||||
owner,
|
|
||||||
repo,
|
|
||||||
ref: `tags/${tag.name}`
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
console.error(`Error processing tag ${tag.name}:`, error);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('Old alpha tags and releases deleted successfully');
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error:', error);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
|
|
||||||
update_tag:
|
|
||||||
name: Update tag
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: delete_old_assets
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Fetch UPDATE logs
|
|
||||||
id: fetch_update_logs
|
|
||||||
run: |
|
|
||||||
if [ -f "UPDATELOG.md" ]; then
|
|
||||||
UPDATE_LOGS=$(awk '/^## v/{if(flag) exit; flag=1} flag' UPDATELOG.md)
|
|
||||||
if [ -n "$UPDATE_LOGS" ]; then
|
|
||||||
echo "Found update logs"
|
|
||||||
echo "UPDATE_LOGS<<EOF" >> $GITHUB_ENV
|
|
||||||
echo "$UPDATE_LOGS" >> $GITHUB_ENV
|
|
||||||
echo "EOF" >> $GITHUB_ENV
|
|
||||||
else
|
|
||||||
echo "No update sections found in UPDATELOG.md"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "UPDATELOG.md file not found"
|
|
||||||
fi
|
|
||||||
shell: bash
|
|
||||||
|
|
||||||
- name: Set Env
|
|
||||||
run: |
|
|
||||||
echo "BUILDTIME=$(TZ=Asia/Shanghai date)" >> $GITHUB_ENV
|
|
||||||
shell: bash
|
|
||||||
|
|
||||||
- run: |
|
|
||||||
if [ -z "$UPDATE_LOGS" ]; then
|
|
||||||
echo "No update logs found, using default message"
|
|
||||||
UPDATE_LOGS="More new features are now supported. Check for detailed changelog soon."
|
|
||||||
else
|
|
||||||
echo "Using found update logs"
|
|
||||||
fi
|
|
||||||
|
|
||||||
cat > release.txt << EOF
|
|
||||||
$UPDATE_LOGS
|
|
||||||
|
|
||||||
## 我应该下载哪个版本?
|
|
||||||
|
|
||||||
### MacOS
|
|
||||||
- MacOS intel芯片: x64.dmg
|
|
||||||
- MacOS apple M芯片: aarch64.dmg
|
|
||||||
|
|
||||||
### Linux
|
|
||||||
- Linux 64位: amd64.deb/amd64.rpm
|
|
||||||
- Linux arm64 architecture: arm64.deb/aarch64.rpm
|
|
||||||
- Linux armv7架构: armhf.deb/armhfp.rpm
|
|
||||||
|
|
||||||
### Windows (不再支持Win7)
|
|
||||||
#### 正常版本(推荐)
|
|
||||||
- 64位: x64-setup.exe
|
|
||||||
- arm64架构: arm64-setup.exe
|
|
||||||
#### 便携版问题很多不再提供
|
|
||||||
#### 内置Webview2版(体积较大,仅在企业版系统或无法安装webview2时使用)
|
|
||||||
- 64位: x64_fixed_webview2-setup.exe
|
|
||||||
- arm64架构: arm64_fixed_webview2-setup.exe
|
|
||||||
|
|
||||||
### FAQ
|
|
||||||
- [常见问题](https://clash-verge-rev.github.io/faq/windows.html)
|
|
||||||
|
|
||||||
### 稳定机场VPN推荐
|
|
||||||
- [狗狗加速](https://verge.dginv.click/#/register?code=oaxsAGo6)
|
|
||||||
|
|
||||||
Created at ${{ env.BUILDTIME }}.
|
|
||||||
EOF
|
|
||||||
|
|
||||||
- name: Upload Release
|
|
||||||
uses: softprops/action-gh-release@v2
|
|
||||||
with:
|
|
||||||
tag_name: ${{ env.TAG_NAME }}
|
|
||||||
name: "Clash Verge Rev ${{ env.TAG_CHANNEL }}"
|
|
||||||
body_path: release.txt
|
|
||||||
prerelease: true
|
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
generate_release_notes: true
|
|
||||||
|
|
||||||
alpha-x86-windows-macos-linux:
|
|
||||||
name: Alpha x86 Windows, MacOS and Linux
|
|
||||||
needs: update_tag
|
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
@@ -270,8 +24,7 @@ jobs:
|
|||||||
target: aarch64-apple-darwin
|
target: aarch64-apple-darwin
|
||||||
- os: macos-latest
|
- os: macos-latest
|
||||||
target: x86_64-apple-darwin
|
target: x86_64-apple-darwin
|
||||||
- os: ubuntu-22.04
|
|
||||||
target: x86_64-unknown-linux-gnu
|
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout Repository
|
- name: Checkout Repository
|
||||||
@@ -287,175 +40,69 @@ jobs:
|
|||||||
uses: Swatinem/rust-cache@v2
|
uses: Swatinem/rust-cache@v2
|
||||||
with:
|
with:
|
||||||
workspaces: src-tauri
|
workspaces: src-tauri
|
||||||
save-if: false
|
|
||||||
|
|
||||||
- name: Install dependencies (ubuntu only)
|
|
||||||
if: matrix.os == 'ubuntu-22.04'
|
|
||||||
run: |
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install -y libxslt1.1 libwebkit2gtk-4.1-dev libayatana-appindicator3-dev librsvg2-dev patchelf
|
|
||||||
|
|
||||||
- name: Install x86 OpenSSL (macOS only)
|
|
||||||
if: matrix.target == 'x86_64-apple-darwin'
|
|
||||||
run: |
|
|
||||||
arch -x86_64 brew install openssl@3
|
|
||||||
echo "OPENSSL_DIR=$(brew --prefix openssl@3)" >> $GITHUB_ENV
|
|
||||||
echo "OPENSSL_INCLUDE_DIR=$(brew --prefix openssl@3)/include" >> $GITHUB_ENV
|
|
||||||
echo "OPENSSL_LIB_DIR=$(brew --prefix openssl@3)/lib" >> $GITHUB_ENV
|
|
||||||
echo "PKG_CONFIG_PATH=$(brew --prefix openssl@3)/lib/pkgconfig" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Install Node
|
- name: Install Node
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: "22"
|
node-version: "20"
|
||||||
|
|
||||||
- uses: pnpm/action-setup@v4
|
- uses: pnpm/action-setup@v3
|
||||||
name: Install pnpm
|
name: Install pnpm
|
||||||
with:
|
with:
|
||||||
|
version: 9
|
||||||
run_install: false
|
run_install: false
|
||||||
|
|
||||||
- name: Pnpm install and check
|
- name: Pnpm install and check
|
||||||
run: |
|
run: |
|
||||||
pnpm i
|
pnpm i
|
||||||
pnpm run prebuild ${{ matrix.target }}
|
pnpm check ${{ matrix.target }}
|
||||||
|
|
||||||
# - name: Release ${{ env.TAG_CHANNEL }} Version
|
|
||||||
# run: pnpm release-version ${{ env.TAG_NAME }}
|
|
||||||
|
|
||||||
- name: Tauri build
|
- name: Tauri build
|
||||||
uses: tauri-apps/tauri-action@v0
|
uses: tauri-apps/tauri-action@v0
|
||||||
env:
|
env:
|
||||||
NODE_OPTIONS: "--max_old_space_size=4096"
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
||||||
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
||||||
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
|
|
||||||
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
|
|
||||||
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
|
|
||||||
APPLE_ID: ${{ secrets.APPLE_ID }}
|
|
||||||
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
|
|
||||||
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
|
||||||
with:
|
with:
|
||||||
tagName: ${{ env.TAG_NAME }}
|
tagName: alpha
|
||||||
releaseName: "Clash Verge Rev ${{ env.TAG_CHANNEL }}"
|
releaseName: "Clash Verge Rev Alpha"
|
||||||
releaseBody: "More new features are now supported."
|
releaseBody: "More new features are now supported."
|
||||||
releaseDraft: false
|
releaseDraft: false
|
||||||
prerelease: true
|
prerelease: true
|
||||||
tauriScript: pnpm
|
tauriScript: pnpm
|
||||||
args: --target ${{ matrix.target }}
|
args: --target ${{ matrix.target }}
|
||||||
|
|
||||||
alpha-arm-linux:
|
- name: Portable Bundle
|
||||||
name: Alpha ARM Linux
|
if: matrix.os == 'windows-latest'
|
||||||
needs: update_tag
|
run: pnpm portable ${{ matrix.target }} --alpha
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
||||||
|
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
||||||
|
|
||||||
|
alpha-for-linux:
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- os: ubuntu-22.04
|
- os: ubuntu-latest
|
||||||
|
target: x86_64-unknown-linux-gnu
|
||||||
|
- os: ubuntu-latest
|
||||||
target: aarch64-unknown-linux-gnu
|
target: aarch64-unknown-linux-gnu
|
||||||
arch: arm64
|
- os: ubuntu-latest
|
||||||
- os: ubuntu-22.04
|
|
||||||
target: armv7-unknown-linux-gnueabihf
|
target: armv7-unknown-linux-gnueabihf
|
||||||
arch: armhf
|
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout Repository
|
- name: Checkout Repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Install Rust Stable
|
|
||||||
uses: dtolnay/rust-toolchain@stable
|
|
||||||
|
|
||||||
- name: Add Rust Target
|
|
||||||
run: rustup target add ${{ matrix.target }}
|
|
||||||
|
|
||||||
- name: Rust Cache
|
|
||||||
uses: Swatinem/rust-cache@v2
|
|
||||||
with:
|
|
||||||
workspaces: src-tauri
|
|
||||||
save-if: false
|
|
||||||
|
|
||||||
- name: Install Node
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: "22"
|
|
||||||
|
|
||||||
- name: Install pnpm
|
|
||||||
uses: pnpm/action-setup@v4
|
|
||||||
with:
|
|
||||||
run_install: false
|
|
||||||
|
|
||||||
- name: Pnpm install and check
|
|
||||||
run: |
|
|
||||||
pnpm i
|
|
||||||
pnpm run prebuild ${{ matrix.target }}
|
|
||||||
|
|
||||||
# - name: Release ${{ env.TAG_CHANNEL }} Version
|
|
||||||
# run: pnpm release-version ${{ env.TAG_NAME }}
|
|
||||||
|
|
||||||
- name: Setup for linux
|
|
||||||
run: |
|
|
||||||
sudo ls -lR /etc/apt/
|
|
||||||
|
|
||||||
cat > /tmp/sources.list << EOF
|
|
||||||
deb [arch=amd64,i386] http://archive.ubuntu.com/ubuntu jammy main multiverse universe restricted
|
|
||||||
deb [arch=amd64,i386] http://archive.ubuntu.com/ubuntu jammy-security main multiverse universe restricted
|
|
||||||
deb [arch=amd64,i386] http://archive.ubuntu.com/ubuntu jammy-updates main multiverse universe restricted
|
|
||||||
deb [arch=amd64,i386] http://archive.ubuntu.com/ubuntu jammy-backports main multiverse universe restricted
|
|
||||||
|
|
||||||
deb [arch=armhf,arm64] http://ports.ubuntu.com/ubuntu-ports jammy main multiverse universe restricted
|
|
||||||
deb [arch=armhf,arm64] http://ports.ubuntu.com/ubuntu-ports jammy-security main multiverse universe restricted
|
|
||||||
deb [arch=armhf,arm64] http://ports.ubuntu.com/ubuntu-ports jammy-updates main multiverse universe restricted
|
|
||||||
deb [arch=armhf,arm64] http://ports.ubuntu.com/ubuntu-ports jammy-backports main multiverse universe restricted
|
|
||||||
EOF
|
|
||||||
|
|
||||||
sudo mv /etc/apt/sources.list /etc/apt/sources.list.default
|
|
||||||
sudo mv /tmp/sources.list /etc/apt/sources.list
|
|
||||||
|
|
||||||
sudo dpkg --add-architecture ${{ matrix.arch }}
|
|
||||||
sudo apt-get update -y
|
|
||||||
sudo apt-get -f install -y
|
|
||||||
|
|
||||||
sudo apt-get install -y \
|
|
||||||
linux-libc-dev:${{ matrix.arch }} \
|
|
||||||
libc6-dev:${{ matrix.arch }}
|
|
||||||
|
|
||||||
sudo apt-get install -y \
|
|
||||||
libxslt1.1:${{ matrix.arch }} \
|
|
||||||
libwebkit2gtk-4.1-dev:${{ matrix.arch }} \
|
|
||||||
libayatana-appindicator3-dev:${{ matrix.arch }} \
|
|
||||||
libssl-dev:${{ matrix.arch }} \
|
|
||||||
patchelf:${{ matrix.arch }} \
|
|
||||||
librsvg2-dev:${{ matrix.arch }}
|
|
||||||
|
|
||||||
- name: Install aarch64 tools
|
|
||||||
if: matrix.target == 'aarch64-unknown-linux-gnu'
|
|
||||||
run: |
|
|
||||||
sudo apt install -y \
|
|
||||||
gcc-aarch64-linux-gnu \
|
|
||||||
g++-aarch64-linux-gnu
|
|
||||||
|
|
||||||
- name: Install armv7 tools
|
|
||||||
if: matrix.target == 'armv7-unknown-linux-gnueabihf'
|
|
||||||
run: |
|
|
||||||
sudo apt install -y \
|
|
||||||
gcc-arm-linux-gnueabihf \
|
|
||||||
g++-arm-linux-gnueabihf
|
|
||||||
|
|
||||||
- name: Build for Linux
|
- name: Build for Linux
|
||||||
run: |
|
uses: ./.github/build-for-linux
|
||||||
export PKG_CONFIG_ALLOW_CROSS=1
|
|
||||||
if [ "${{ matrix.target }}" == "aarch64-unknown-linux-gnu" ]; then
|
|
||||||
export PKG_CONFIG_PATH=/usr/lib/aarch64-linux-gnu/pkgconfig/:$PKG_CONFIG_PATH
|
|
||||||
export PKG_CONFIG_SYSROOT_DIR=/usr/aarch64-linux-gnu/
|
|
||||||
elif [ "${{ matrix.target }}" == "armv7-unknown-linux-gnueabihf" ]; then
|
|
||||||
export PKG_CONFIG_PATH=/usr/lib/arm-linux-gnueabihf/pkgconfig/:$PKG_CONFIG_PATH
|
|
||||||
export PKG_CONFIG_SYSROOT_DIR=/usr/arm-linux-gnueabihf/
|
|
||||||
fi
|
|
||||||
pnpm build --target ${{ matrix.target }}
|
|
||||||
env:
|
env:
|
||||||
NODE_OPTIONS: "--max_old_space_size=4096"
|
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
||||||
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
||||||
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
with:
|
||||||
|
target: ${{ matrix.target }}
|
||||||
|
|
||||||
- name: Get Version
|
- name: Get Version
|
||||||
run: |
|
run: |
|
||||||
@@ -464,111 +111,95 @@ jobs:
|
|||||||
echo "VERSION=$(cat package.json | jq '.version' | tr -d '"')" >> $GITHUB_ENV
|
echo "VERSION=$(cat package.json | jq '.version' | tr -d '"')" >> $GITHUB_ENV
|
||||||
echo "BUILDTIME=$(TZ=Asia/Shanghai date)" >> $GITHUB_ENV
|
echo "BUILDTIME=$(TZ=Asia/Shanghai date)" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- run: |
|
||||||
|
cat > release.txt << 'EOF'
|
||||||
|
### 我应该下载哪个版本?
|
||||||
|
|
||||||
|
- Windows x86_64架构: x64-setup.exe (不支持win7)
|
||||||
|
- Windows arm64架构: arm64-setup.exe
|
||||||
|
- MacOS intel芯片: x64.dmg
|
||||||
|
- MacOS apple M芯片: aarch64.dmg (提示文件损坏看下面FAQ)
|
||||||
|
- Linux x64架构: amd64.AppImage/amd64.deb
|
||||||
|
- Linux arm64架构: arm64.deb
|
||||||
|
- Linux armv7架构: armhf.deb
|
||||||
|
- Windows 便携板 x86_64架构: x64_portable.zip (不推荐使用,无法自动更新)
|
||||||
|
- Windows 便携板 arm64架构: arm64_portable.zip (不推荐使用,无法自动更新)
|
||||||
|
|
||||||
|
### FAQ
|
||||||
|
|
||||||
|
- [FAQ](https://clash-verge-rev.github.io/faq/install/)
|
||||||
|
|
||||||
|
Created at ${{ env.BUILDTIME }}.
|
||||||
|
EOF
|
||||||
|
|
||||||
- name: Upload Release
|
- name: Upload Release
|
||||||
uses: softprops/action-gh-release@v2
|
if: startsWith(matrix.target, 'x86_64')
|
||||||
|
uses: softprops/action-gh-release@v1
|
||||||
with:
|
with:
|
||||||
tag_name: ${{ env.TAG_NAME }}
|
tag_name: alpha
|
||||||
name: "Clash Verge Rev ${{ env.TAG_CHANNEL }}"
|
name: "Clash Verge Rev Alpha"
|
||||||
|
body_path: release.txt
|
||||||
prerelease: true
|
prerelease: true
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
files: |
|
files: src-tauri/target/${{ matrix.target }}/release/bundle/appimage/*.AppImage*
|
||||||
src-tauri/target/${{ matrix.target }}/release/bundle/deb/*.deb
|
|
||||||
src-tauri/target/${{ matrix.target }}/release/bundle/rpm/*.rpm
|
|
||||||
|
|
||||||
alpha-x86-arm-windows_webview2:
|
- name: Upload Release
|
||||||
name: Alpha x86 and ARM Windows with WebView2
|
uses: softprops/action-gh-release@v1
|
||||||
needs: update_tag
|
with:
|
||||||
strategy:
|
tag_name: alpha
|
||||||
fail-fast: false
|
name: "Clash Verge Rev Alpha"
|
||||||
matrix:
|
body_path: release.txt
|
||||||
include:
|
prerelease: true
|
||||||
- os: windows-latest
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
target: x86_64-pc-windows-msvc
|
files: src-tauri/target/${{ matrix.target }}/release/bundle/deb/*.deb
|
||||||
arch: x64
|
|
||||||
- os: windows-latest
|
update_tag:
|
||||||
target: aarch64-pc-windows-msvc
|
name: Update tag
|
||||||
arch: arm64
|
runs-on: ubuntu-latest
|
||||||
runs-on: ${{ matrix.os }}
|
needs: [alpha, alpha-for-linux]
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout Repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Add Rust Target
|
- name: Set Env
|
||||||
run: rustup target add ${{ matrix.target }}
|
|
||||||
|
|
||||||
- name: Rust Cache
|
|
||||||
uses: Swatinem/rust-cache@v2
|
|
||||||
with:
|
|
||||||
workspaces: src-tauri
|
|
||||||
save-if: false
|
|
||||||
|
|
||||||
- name: Install Node
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: "22"
|
|
||||||
|
|
||||||
- uses: pnpm/action-setup@v4
|
|
||||||
name: Install pnpm
|
|
||||||
with:
|
|
||||||
run_install: false
|
|
||||||
|
|
||||||
- name: Pnpm install and check
|
|
||||||
run: |
|
run: |
|
||||||
pnpm i
|
echo "BUILDTIME=$(TZ=Asia/Shanghai date)" >> $GITHUB_ENV
|
||||||
pnpm run prebuild ${{ matrix.target }}
|
shell: bash
|
||||||
|
|
||||||
# - name: Release ${{ env.TAG_CHANNEL }} Version
|
- name: Update Tag
|
||||||
# run: pnpm release-version ${{ env.TAG_NAME }}
|
uses: richardsimko/update-tag@v1
|
||||||
|
with:
|
||||||
- name: Download WebView2 Runtime
|
tag_name: alpha
|
||||||
run: |
|
|
||||||
invoke-webrequest -uri https://github.com/westinyang/WebView2RuntimeArchive/releases/download/109.0.1518.78/Microsoft.WebView2.FixedVersionRuntime.109.0.1518.78.${{ matrix.arch }}.cab -outfile Microsoft.WebView2.FixedVersionRuntime.109.0.1518.78.${{ matrix.arch }}.cab
|
|
||||||
Expand .\Microsoft.WebView2.FixedVersionRuntime.109.0.1518.78.${{ matrix.arch }}.cab -F:* ./src-tauri
|
|
||||||
Remove-Item .\src-tauri\tauri.windows.conf.json
|
|
||||||
Rename-Item .\src-tauri\webview2.${{ matrix.arch }}.json tauri.windows.conf.json
|
|
||||||
|
|
||||||
- name: Tauri build
|
|
||||||
id: build
|
|
||||||
uses: tauri-apps/tauri-action@v0
|
|
||||||
env:
|
env:
|
||||||
NODE_OPTIONS: "--max_old_space_size=4096"
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
|
||||||
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
|
||||||
with:
|
|
||||||
tauriScript: pnpm
|
|
||||||
args: --target ${{ matrix.target }}
|
|
||||||
|
|
||||||
- name: Rename
|
- run: |
|
||||||
run: |
|
cat > release.txt << 'EOF'
|
||||||
$files = Get-ChildItem ".\src-tauri\target\${{ matrix.target }}\release\bundle\nsis\*-setup.exe"
|
### 我应该下载哪个版本?
|
||||||
foreach ($file in $files) {
|
|
||||||
$newName = $file.Name -replace "-setup\.exe$", "_fixed_webview2-setup.exe"
|
|
||||||
Rename-Item $file.FullName $newName
|
|
||||||
}
|
|
||||||
|
|
||||||
$files = Get-ChildItem ".\src-tauri\target\${{ matrix.target }}\release\bundle\nsis\*.nsis.zip"
|
- Windows x86_64架构: x64-setup.exe (不支持win7)
|
||||||
foreach ($file in $files) {
|
- Windows arm64架构: arm64-setup.exe
|
||||||
$newName = $file.Name -replace "-setup\.nsis\.zip$", "_fixed_webview2-setup.nsis.zip"
|
- MacOS intel芯片: x64.dmg
|
||||||
Rename-Item $file.FullName $newName
|
- MacOS apple M芯片: aarch64.dmg (提示文件损坏看下面FAQ)
|
||||||
}
|
- Linux x64架构: amd64.AppImage/amd64.deb
|
||||||
|
- Linux arm64架构: arm64.deb
|
||||||
|
- Linux armv7架构: armhf.deb
|
||||||
|
- Windows 便携板 x86_64架构: x64_portable.zip (不推荐使用,无法自动更新)
|
||||||
|
- Windows 便携板 arm64架构: arm64_portable.zip (不推荐使用,无法自动更新)
|
||||||
|
|
||||||
$files = Get-ChildItem ".\src-tauri\target\${{ matrix.target }}\release\bundle\nsis\*-setup.exe.sig"
|
### FAQ
|
||||||
foreach ($file in $files) {
|
|
||||||
$newName = $file.Name -replace "-setup\.exe\.sig$", "_fixed_webview2-setup.exe.sig"
|
- [FAQ](https://clash-verge-rev.github.io/faq/install/)
|
||||||
Rename-Item $file.FullName $newName
|
|
||||||
}
|
Created at ${{ env.BUILDTIME }}.
|
||||||
|
EOF
|
||||||
|
|
||||||
- name: Upload Release
|
- name: Upload Release
|
||||||
uses: softprops/action-gh-release@v2
|
uses: softprops/action-gh-release@v1
|
||||||
with:
|
with:
|
||||||
tag_name: ${{ env.TAG_NAME }}
|
tag_name: alpha
|
||||||
name: "Clash Verge Rev ${{ env.TAG_CHANNEL }}"
|
name: "Clash Verge Rev Alpha"
|
||||||
|
body_path: release.txt
|
||||||
prerelease: true
|
prerelease: true
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
files: src-tauri/target/${{ matrix.target }}/release/bundle/nsis/*setup*
|
generate_release_notes: true
|
||||||
|
|
||||||
- name: Portable Bundle
|
|
||||||
run: pnpm portable-fixed-webview2 ${{ matrix.target }} --${{ env.TAG_NAME }}
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|||||||
133
.github/workflows/autobuild-check-test.yml
vendored
@@ -1,133 +0,0 @@
|
|||||||
name: Autobuild Check Logic Test
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
check_autobuild_logic:
|
|
||||||
name: Check Autobuild Should Run Logic
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 2
|
|
||||||
|
|
||||||
- name: Check if version or source changed, or assets already exist
|
|
||||||
id: check
|
|
||||||
run: |
|
|
||||||
# # 仅用于测试逻辑,手动触发自动跳过
|
|
||||||
# if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
|
|
||||||
# echo "should_run=skip" >> $GITHUB_OUTPUT
|
|
||||||
# echo "🟡 手动触发,跳过 should_run 检查"
|
|
||||||
# exit 0
|
|
||||||
# fi
|
|
||||||
|
|
||||||
# 确保有 HEAD~1
|
|
||||||
if ! git rev-parse HEAD~1 > /dev/null 2>&1; then
|
|
||||||
echo "should_run=true" >> $GITHUB_OUTPUT
|
|
||||||
echo "🟢 没有前一个提交,默认需要构建"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 版本号变更判断
|
|
||||||
CURRENT_VERSION=$(jq -r '.version' package.json)
|
|
||||||
PREVIOUS_VERSION=$(git show HEAD~1:package.json | jq -r '.version' 2>/dev/null || echo "")
|
|
||||||
|
|
||||||
if [ "$CURRENT_VERSION" != "$PREVIOUS_VERSION" ]; then
|
|
||||||
echo "should_run=true" >> $GITHUB_OUTPUT
|
|
||||||
echo "🟢 版本号变更: $PREVIOUS_VERSION → $CURRENT_VERSION"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 检查 src 变更(排除常见产物与缓存)
|
|
||||||
SRC_DIFF=$(git diff --name-only HEAD~1 HEAD -- src/ | grep -Ev '^src/(dist|build|node_modules|\.next|\.cache)' || true)
|
|
||||||
TAURI_DIFF=$(git diff --name-only HEAD~1 HEAD -- src-tauri/ | grep -Ev '^src-tauri/(target|node_modules|dist|\.cache)' || true)
|
|
||||||
|
|
||||||
if [ -n "$SRC_DIFF" ] || [ -n "$TAURI_DIFF" ]; then
|
|
||||||
echo "should_run=true" >> $GITHUB_OUTPUT
|
|
||||||
echo "🟢 源码变更 detected"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 找到最后一个修改 Tauri 相关文件的 commit
|
|
||||||
echo "🔍 查找最后一个 Tauri 相关变更的 commit..."
|
|
||||||
|
|
||||||
LAST_TAURI_COMMIT=""
|
|
||||||
for commit in $(git rev-list HEAD --max-count=50); do
|
|
||||||
# 检查此 commit 是否修改了 Tauri 相关文件
|
|
||||||
CHANGED_FILES=$(git show --name-only --pretty=format: $commit | tr '\n' ' ')
|
|
||||||
HAS_TAURI_CHANGES=false
|
|
||||||
|
|
||||||
# 检查各个模式
|
|
||||||
if echo "$CHANGED_FILES" | grep -q "src/" && echo "$CHANGED_FILES" | grep -qvE "src/(dist|build|node_modules|\.next|\.cache)"; then
|
|
||||||
HAS_TAURI_CHANGES=true
|
|
||||||
elif echo "$CHANGED_FILES" | grep -qE "src-tauri/(src|Cargo\.(toml|lock)|tauri\..*\.conf\.json|build\.rs|capabilities)"; then
|
|
||||||
HAS_TAURI_CHANGES=true
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$HAS_TAURI_CHANGES" = true ]; then
|
|
||||||
LAST_TAURI_COMMIT=$(git rev-parse --short $commit)
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ -z "$LAST_TAURI_COMMIT" ]; then
|
|
||||||
echo "⚠️ 最近的 commits 中未找到 Tauri 相关变更,使用当前 commit"
|
|
||||||
LAST_TAURI_COMMIT=$(git rev-parse --short HEAD)
|
|
||||||
fi
|
|
||||||
|
|
||||||
CURRENT_COMMIT=$(git rev-parse --short HEAD)
|
|
||||||
echo "📝 最后 Tauri 相关 commit: $LAST_TAURI_COMMIT"
|
|
||||||
echo "📝 当前 commit: $CURRENT_COMMIT"
|
|
||||||
|
|
||||||
# 检查 autobuild release 是否存在
|
|
||||||
AUTOBUILD_RELEASE_EXISTS=$(gh release view "autobuild" --json id -q '.id' 2>/dev/null || echo "")
|
|
||||||
|
|
||||||
if [ -z "$AUTOBUILD_RELEASE_EXISTS" ]; then
|
|
||||||
echo "should_run=true" >> $GITHUB_OUTPUT
|
|
||||||
echo "🟢 没有 autobuild release,需构建"
|
|
||||||
else
|
|
||||||
# 检查 latest.json 是否存在
|
|
||||||
LATEST_JSON_EXISTS=$(gh release view "autobuild" --json assets -q '.assets[] | select(.name == "latest.json") | .name' 2>/dev/null || echo "")
|
|
||||||
|
|
||||||
if [ -z "$LATEST_JSON_EXISTS" ]; then
|
|
||||||
echo "should_run=true" >> $GITHUB_OUTPUT
|
|
||||||
echo "🟢 没有 latest.json,需构建"
|
|
||||||
else
|
|
||||||
# 下载并解析 latest.json 检查版本和 commit hash
|
|
||||||
echo "📥 下载 latest.json 检查版本..."
|
|
||||||
LATEST_JSON_URL=$(gh release view "autobuild" --json assets -q '.assets[] | select(.name == "latest.json") | .browser_download_url' 2>/dev/null)
|
|
||||||
|
|
||||||
if [ -n "$LATEST_JSON_URL" ]; then
|
|
||||||
LATEST_JSON_CONTENT=$(curl -s "$LATEST_JSON_URL" 2>/dev/null || echo "")
|
|
||||||
|
|
||||||
if [ -n "$LATEST_JSON_CONTENT" ]; then
|
|
||||||
LATEST_VERSION=$(echo "$LATEST_JSON_CONTENT" | jq -r '.version' 2>/dev/null || echo "")
|
|
||||||
echo "📦 最新 autobuild 版本: $LATEST_VERSION"
|
|
||||||
|
|
||||||
# 从版本字符串中提取 commit hash (格式: X.Y.Z+autobuild.MMDD.commit)
|
|
||||||
LATEST_COMMIT=$(echo "$LATEST_VERSION" | sed -n 's/.*+autobuild\.[0-9]\{4\}\.\([a-f0-9]*\)$/\1/p' || echo "")
|
|
||||||
echo "📝 最新 autobuild commit: $LATEST_COMMIT"
|
|
||||||
|
|
||||||
if [ "$LAST_TAURI_COMMIT" != "$LATEST_COMMIT" ]; then
|
|
||||||
echo "should_run=true" >> $GITHUB_OUTPUT
|
|
||||||
echo "🟢 Tauri commit hash 不匹配 ($LAST_TAURI_COMMIT != $LATEST_COMMIT),需构建"
|
|
||||||
else
|
|
||||||
echo "should_run=false" >> $GITHUB_OUTPUT
|
|
||||||
echo "🔴 相同 Tauri commit hash ($LAST_TAURI_COMMIT),不需构建"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "should_run=true" >> $GITHUB_OUTPUT
|
|
||||||
echo "⚠️ 无法下载或解析 latest.json,需构建"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "should_run=true" >> $GITHUB_OUTPUT
|
|
||||||
echo "⚠️ 无法获取 latest.json 下载 URL,需构建"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Output should_run result
|
|
||||||
run: |
|
|
||||||
echo "Result: ${{ steps.check.outputs.should_run }}"
|
|
||||||
598
.github/workflows/autobuild.yml
vendored
@@ -1,598 +0,0 @@
|
|||||||
name: Auto Build
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
schedule:
|
|
||||||
# UTC+8 12:00, 18:00 -> UTC 4:00, 10:00
|
|
||||||
- cron: "0 4,10 * * *"
|
|
||||||
permissions: write-all
|
|
||||||
env:
|
|
||||||
TAG_NAME: autobuild
|
|
||||||
TAG_CHANNEL: AutoBuild
|
|
||||||
CARGO_INCREMENTAL: 0
|
|
||||||
RUST_BACKTRACE: short
|
|
||||||
HUSKY: 0
|
|
||||||
concurrency:
|
|
||||||
group: "${{ github.workflow }} - ${{ github.head_ref || github.ref }}"
|
|
||||||
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
check_commit:
|
|
||||||
name: Check Commit Needs Build
|
|
||||||
uses: clash-verge-rev/clash-verge-rev/.github/workflows/check-commit-needs-build.yml@dev
|
|
||||||
with:
|
|
||||||
tag_name: autobuild
|
|
||||||
force_build: ${{ github.event_name == 'workflow_dispatch' }}
|
|
||||||
|
|
||||||
update_tag:
|
|
||||||
name: Update tag
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: check_commit
|
|
||||||
if: ${{ needs.check_commit.outputs.should_run == 'true' }}
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Fetch UPDATE logs
|
|
||||||
id: fetch_update_logs
|
|
||||||
run: |
|
|
||||||
if [ -f "UPDATELOG.md" ]; then
|
|
||||||
UPDATE_LOGS=$(awk '/^## v/{if(flag) exit; flag=1} flag' UPDATELOG.md)
|
|
||||||
if [ -n "$UPDATE_LOGS" ]; then
|
|
||||||
echo "Found update logs"
|
|
||||||
echo "UPDATE_LOGS<<EOF" >> $GITHUB_ENV
|
|
||||||
echo "$UPDATE_LOGS" >> $GITHUB_ENV
|
|
||||||
echo "EOF" >> $GITHUB_ENV
|
|
||||||
else
|
|
||||||
echo "No update sections found in UPDATELOG.md"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "UPDATELOG.md file not found"
|
|
||||||
fi
|
|
||||||
shell: bash
|
|
||||||
|
|
||||||
- uses: pnpm/action-setup@v4
|
|
||||||
name: Install pnpm
|
|
||||||
with:
|
|
||||||
run_install: false
|
|
||||||
|
|
||||||
- name: Install Node
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: "22"
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: pnpm install --frozen-lockfile
|
|
||||||
|
|
||||||
- name: Release AutoBuild Version
|
|
||||||
run: pnpm release-version autobuild-latest
|
|
||||||
|
|
||||||
- name: Set Env
|
|
||||||
run: |
|
|
||||||
echo "BUILDTIME=$(TZ=Asia/Shanghai date)" >> $GITHUB_ENV
|
|
||||||
VERSION=$(jq -r .version package.json)
|
|
||||||
echo "VERSION=$VERSION" >> $GITHUB_ENV
|
|
||||||
echo "DOWNLOAD_URL=https://github.com/clash-verge-rev/clash-verge-rev/releases/download/autobuild" >> $GITHUB_ENV
|
|
||||||
shell: bash
|
|
||||||
|
|
||||||
- run: |
|
|
||||||
if [ -z "$UPDATE_LOGS" ]; then
|
|
||||||
echo "No update logs found, using default message"
|
|
||||||
UPDATE_LOGS="More new features are now supported. Check for detailed changelog soon."
|
|
||||||
else
|
|
||||||
echo "Using found update logs"
|
|
||||||
fi
|
|
||||||
|
|
||||||
cat > release.txt << EOF
|
|
||||||
$UPDATE_LOGS
|
|
||||||
|
|
||||||
## 下载地址
|
|
||||||
|
|
||||||
### Windows (不再支持Win7)
|
|
||||||
#### 正常版本(推荐)
|
|
||||||
- [64位(常用)](${{ env.DOWNLOAD_URL }}/Clash.Verge_${{ env.VERSION }}_x64-setup_windows.exe) | [ARM64(不常用)](${{ env.DOWNLOAD_URL }}/Clash.Verge_${{ env.VERSION }}_arm64-setup.exe)
|
|
||||||
|
|
||||||
#### 内置Webview2版(体积较大,仅在企业版系统或无法安装webview2时使用)
|
|
||||||
- [64位](${{ env.DOWNLOAD_URL }}/Clash.Verge_${{ env.VERSION }}_x64_fixed_webview2-setup.exe) | [ARM64](${{ env.DOWNLOAD_URL }}/Clash.Verge_${{ env.VERSION }}_arm64_fixed_webview2-setup.exe)
|
|
||||||
|
|
||||||
### macOS
|
|
||||||
- [Apple M芯片](${{ env.DOWNLOAD_URL }}/Clash.Verge_${{ env.VERSION }}_aarch64_darwin.dmg) | [Intel芯片](${{ env.DOWNLOAD_URL }}/Clash.Verge_${{ env.VERSION }}_x64_darwin.dmg)
|
|
||||||
|
|
||||||
### Linux
|
|
||||||
#### DEB包(Debian系) 使用 apt ./路径 安装
|
|
||||||
- [64位](${{ env.DOWNLOAD_URL }}/Clash.Verge_${{ env.VERSION }}_amd64_linux.deb) | [ARM64](${{ env.DOWNLOAD_URL }}/Clash.Verge_${{ env.VERSION }}_arm64.deb) | [ARMv7](${{ env.DOWNLOAD_URL }}/Clash.Verge_${{ env.VERSION }}_armhf.deb)
|
|
||||||
|
|
||||||
#### RPM包(Redhat系) 使用 dnf ./路径 安装
|
|
||||||
- [64位](${{ env.DOWNLOAD_URL }}/Clash.Verge_${{ env.VERSION }}-1.x86_64_linux.rpm) | [ARM64](${{ env.DOWNLOAD_URL }}/Clash.Verge_${{ env.VERSION }}-1.aarch64.rpm) | [ARMv7](${{ env.DOWNLOAD_URL }}/Clash.Verge_${{ env.VERSION }}-1.armhfp.rpm)
|
|
||||||
|
|
||||||
### FAQ
|
|
||||||
- [常见问题](https://clash-verge-rev.github.io/faq/windows.html)
|
|
||||||
|
|
||||||
### 稳定机场VPN推荐
|
|
||||||
- [狗狗加速](https://verge.dginv.click/#/register?code=oaxsAGo6)
|
|
||||||
|
|
||||||
Created at ${{ env.BUILDTIME }}.
|
|
||||||
EOF
|
|
||||||
|
|
||||||
- name: Upload Release
|
|
||||||
uses: softprops/action-gh-release@v2
|
|
||||||
with:
|
|
||||||
tag_name: ${{ env.TAG_NAME }}
|
|
||||||
name: "Clash Verge Rev ${{ env.TAG_CHANNEL }}"
|
|
||||||
body_path: release.txt
|
|
||||||
prerelease: true
|
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
generate_release_notes: true
|
|
||||||
|
|
||||||
clean_old_assets:
|
|
||||||
name: Clean Old Release Assets
|
|
||||||
needs: [check_commit, update_tag]
|
|
||||||
if: ${{ needs.check_commit.outputs.should_run == 'true' && needs.update_tag.result == 'success' }}
|
|
||||||
|
|
||||||
uses: clash-verge-rev/clash-verge-rev/.github/workflows/clean-old-assets.yml@dev
|
|
||||||
with:
|
|
||||||
tag_name: autobuild
|
|
||||||
dry_run: false
|
|
||||||
|
|
||||||
autobuild-x86-windows-macos-linux:
|
|
||||||
name: Autobuild x86 Windows, MacOS and Linux
|
|
||||||
needs: [check_commit, update_tag]
|
|
||||||
if: ${{ needs.check_commit.outputs.should_run == 'true' }}
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- os: windows-latest
|
|
||||||
target: x86_64-pc-windows-msvc
|
|
||||||
- os: windows-latest
|
|
||||||
target: aarch64-pc-windows-msvc
|
|
||||||
- os: macos-latest
|
|
||||||
target: aarch64-apple-darwin
|
|
||||||
- os: macos-latest
|
|
||||||
target: x86_64-apple-darwin
|
|
||||||
- os: ubuntu-22.04
|
|
||||||
target: x86_64-unknown-linux-gnu
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
steps:
|
|
||||||
- name: Checkout Repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Install Rust Stable
|
|
||||||
uses: dtolnay/rust-toolchain@stable
|
|
||||||
|
|
||||||
- name: Add Rust Target
|
|
||||||
run: rustup target add ${{ matrix.target }}
|
|
||||||
|
|
||||||
- name: Rust Cache
|
|
||||||
uses: Swatinem/rust-cache@v2
|
|
||||||
with:
|
|
||||||
workspaces: src-tauri
|
|
||||||
cache-all-crates: true
|
|
||||||
save-if: ${{ github.ref == 'refs/heads/dev' }}
|
|
||||||
shared-key: autobuild-${{ runner.os }}-${{ matrix.target }}
|
|
||||||
key: ${{ runner.os }}-${{ matrix.target }}-${{ hashFiles('src-tauri/Cargo.lock') }}
|
|
||||||
|
|
||||||
- name: Install dependencies (ubuntu only)
|
|
||||||
if: matrix.os == 'ubuntu-22.04'
|
|
||||||
run: |
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install -y libxslt1.1 libwebkit2gtk-4.1-dev libayatana-appindicator3-dev librsvg2-dev patchelf
|
|
||||||
|
|
||||||
- name: Install x86 OpenSSL (macOS only)
|
|
||||||
if: matrix.target == 'x86_64-apple-darwin'
|
|
||||||
run: |
|
|
||||||
arch -x86_64 brew install openssl@3
|
|
||||||
echo "OPENSSL_DIR=$(brew --prefix openssl@3)" >> $GITHUB_ENV
|
|
||||||
echo "OPENSSL_INCLUDE_DIR=$(brew --prefix openssl@3)/include" >> $GITHUB_ENV
|
|
||||||
echo "OPENSSL_LIB_DIR=$(brew --prefix openssl@3)/lib" >> $GITHUB_ENV
|
|
||||||
echo "PKG_CONFIG_PATH=$(brew --prefix openssl@3)/lib/pkgconfig" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- uses: pnpm/action-setup@v4
|
|
||||||
name: Install pnpm
|
|
||||||
with:
|
|
||||||
run_install: false
|
|
||||||
|
|
||||||
- name: Install Node
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: "22"
|
|
||||||
cache: "pnpm"
|
|
||||||
|
|
||||||
- name: Cache pnpm store
|
|
||||||
uses: actions/cache@v4
|
|
||||||
with:
|
|
||||||
path: ~/.pnpm-store
|
|
||||||
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-pnpm-
|
|
||||||
|
|
||||||
- name: Pnpm install and check
|
|
||||||
run: |
|
|
||||||
pnpm i
|
|
||||||
pnpm run prebuild ${{ matrix.target }}
|
|
||||||
|
|
||||||
- name: Release ${{ env.TAG_CHANNEL }} Version
|
|
||||||
run: pnpm release-version autobuild-latest
|
|
||||||
|
|
||||||
- name: Tauri build for Windows-macOS-Linux
|
|
||||||
uses: tauri-apps/tauri-action@v0
|
|
||||||
env:
|
|
||||||
NODE_OPTIONS: "--max_old_space_size=4096"
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
|
||||||
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
|
||||||
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
|
|
||||||
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
|
|
||||||
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
|
|
||||||
APPLE_ID: ${{ secrets.APPLE_ID }}
|
|
||||||
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
|
|
||||||
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
|
||||||
with:
|
|
||||||
tagName: ${{ env.TAG_NAME }}
|
|
||||||
releaseName: "Clash Verge Rev ${{ env.TAG_CHANNEL }}"
|
|
||||||
releaseBody: "More new features are now supported."
|
|
||||||
releaseDraft: false
|
|
||||||
prerelease: true
|
|
||||||
tauriScript: pnpm
|
|
||||||
args: --target ${{ matrix.target }}
|
|
||||||
# includeUpdaterJson: true
|
|
||||||
|
|
||||||
autobuild-arm-linux:
|
|
||||||
name: Autobuild ARM Linux
|
|
||||||
needs: [check_commit, update_tag]
|
|
||||||
if: ${{ needs.check_commit.outputs.should_run == 'true' }}
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- os: ubuntu-22.04
|
|
||||||
target: aarch64-unknown-linux-gnu
|
|
||||||
arch: arm64
|
|
||||||
- os: ubuntu-22.04
|
|
||||||
target: armv7-unknown-linux-gnueabihf
|
|
||||||
arch: armhf
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
steps:
|
|
||||||
- name: Checkout Repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Install Rust Stable
|
|
||||||
uses: dtolnay/rust-toolchain@stable
|
|
||||||
|
|
||||||
- name: Add Rust Target
|
|
||||||
run: rustup target add ${{ matrix.target }}
|
|
||||||
|
|
||||||
- name: Rust Cache
|
|
||||||
uses: Swatinem/rust-cache@v2
|
|
||||||
with:
|
|
||||||
workspaces: src-tauri
|
|
||||||
cache-all-crates: true
|
|
||||||
save-if: ${{ github.ref == 'refs/heads/dev' }}
|
|
||||||
shared-key: autobuild-${{ runner.os }}-${{ matrix.target }}
|
|
||||||
key: ${{ runner.os }}-${{ matrix.target }}-${{ hashFiles('src-tauri/Cargo.lock') }}
|
|
||||||
|
|
||||||
- name: Install pnpm
|
|
||||||
uses: pnpm/action-setup@v4
|
|
||||||
with:
|
|
||||||
run_install: false
|
|
||||||
|
|
||||||
- name: Install Node
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: "22"
|
|
||||||
cache: "pnpm"
|
|
||||||
|
|
||||||
- name: Cache pnpm store
|
|
||||||
uses: actions/cache@v4
|
|
||||||
with:
|
|
||||||
path: ~/.pnpm-store
|
|
||||||
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-pnpm-
|
|
||||||
|
|
||||||
- name: Pnpm install and check
|
|
||||||
run: |
|
|
||||||
pnpm i
|
|
||||||
pnpm run prebuild ${{ matrix.target }}
|
|
||||||
|
|
||||||
- name: Release ${{ env.TAG_CHANNEL }} Version
|
|
||||||
run: pnpm release-version autobuild-latest
|
|
||||||
|
|
||||||
- name: Setup for linux
|
|
||||||
run: |
|
|
||||||
sudo ls -lR /etc/apt/
|
|
||||||
|
|
||||||
cat > /tmp/sources.list << EOF
|
|
||||||
deb [arch=amd64,i386] http://archive.ubuntu.com/ubuntu jammy main multiverse universe restricted
|
|
||||||
deb [arch=amd64,i386] http://archive.ubuntu.com/ubuntu jammy-security main multiverse universe restricted
|
|
||||||
deb [arch=amd64,i386] http://archive.ubuntu.com/ubuntu jammy-updates main multiverse universe restricted
|
|
||||||
deb [arch=amd64,i386] http://archive.ubuntu.com/ubuntu jammy-backports main multiverse universe restricted
|
|
||||||
|
|
||||||
deb [arch=armhf,arm64] http://ports.ubuntu.com/ubuntu-ports jammy main multiverse universe restricted
|
|
||||||
deb [arch=armhf,arm64] http://ports.ubuntu.com/ubuntu-ports jammy-security main multiverse universe restricted
|
|
||||||
deb [arch=armhf,arm64] http://ports.ubuntu.com/ubuntu-ports jammy-updates main multiverse universe restricted
|
|
||||||
deb [arch=armhf,arm64] http://ports.ubuntu.com/ubuntu-ports jammy-backports main multiverse universe restricted
|
|
||||||
EOF
|
|
||||||
|
|
||||||
sudo mv /etc/apt/sources.list /etc/apt/sources.list.default
|
|
||||||
sudo mv /tmp/sources.list /etc/apt/sources.list
|
|
||||||
|
|
||||||
sudo dpkg --add-architecture ${{ matrix.arch }}
|
|
||||||
sudo apt-get update -y
|
|
||||||
sudo apt-get -f install -y
|
|
||||||
|
|
||||||
sudo apt-get install -y \
|
|
||||||
linux-libc-dev:${{ matrix.arch }} \
|
|
||||||
libc6-dev:${{ matrix.arch }}
|
|
||||||
|
|
||||||
sudo apt-get install -y \
|
|
||||||
libxslt1.1:${{ matrix.arch }} \
|
|
||||||
libwebkit2gtk-4.1-dev:${{ matrix.arch }} \
|
|
||||||
libayatana-appindicator3-dev:${{ matrix.arch }} \
|
|
||||||
libssl-dev:${{ matrix.arch }} \
|
|
||||||
patchelf:${{ matrix.arch }} \
|
|
||||||
librsvg2-dev:${{ matrix.arch }}
|
|
||||||
|
|
||||||
- name: Install aarch64 tools
|
|
||||||
if: matrix.target == 'aarch64-unknown-linux-gnu'
|
|
||||||
run: |
|
|
||||||
sudo apt install -y \
|
|
||||||
gcc-aarch64-linux-gnu \
|
|
||||||
g++-aarch64-linux-gnu
|
|
||||||
|
|
||||||
- name: Install armv7 tools
|
|
||||||
if: matrix.target == 'armv7-unknown-linux-gnueabihf'
|
|
||||||
run: |
|
|
||||||
sudo apt install -y \
|
|
||||||
gcc-arm-linux-gnueabihf \
|
|
||||||
g++-arm-linux-gnueabihf
|
|
||||||
|
|
||||||
- name: Tauri Build for Linux
|
|
||||||
run: |
|
|
||||||
export PKG_CONFIG_ALLOW_CROSS=1
|
|
||||||
if [ "${{ matrix.target }}" == "aarch64-unknown-linux-gnu" ]; then
|
|
||||||
export PKG_CONFIG_PATH=/usr/lib/aarch64-linux-gnu/pkgconfig/:$PKG_CONFIG_PATH
|
|
||||||
export PKG_CONFIG_SYSROOT_DIR=/usr/aarch64-linux-gnu/
|
|
||||||
elif [ "${{ matrix.target }}" == "armv7-unknown-linux-gnueabihf" ]; then
|
|
||||||
export PKG_CONFIG_PATH=/usr/lib/arm-linux-gnueabihf/pkgconfig/:$PKG_CONFIG_PATH
|
|
||||||
export PKG_CONFIG_SYSROOT_DIR=/usr/arm-linux-gnueabihf/
|
|
||||||
fi
|
|
||||||
pnpm build --target ${{ matrix.target }}
|
|
||||||
env:
|
|
||||||
NODE_OPTIONS: "--max_old_space_size=4096"
|
|
||||||
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
|
||||||
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
|
||||||
|
|
||||||
- name: Get Version
|
|
||||||
run: |
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install jq
|
|
||||||
echo "VERSION=$(cat package.json | jq '.version' | tr -d '"')" >> $GITHUB_ENV
|
|
||||||
echo "BUILDTIME=$(TZ=Asia/Shanghai date)" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Upload Release
|
|
||||||
uses: softprops/action-gh-release@v2
|
|
||||||
with:
|
|
||||||
tag_name: ${{ env.TAG_NAME }}
|
|
||||||
name: "Clash Verge Rev ${{ env.TAG_CHANNEL }}"
|
|
||||||
prerelease: true
|
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
files: |
|
|
||||||
src-tauri/target/${{ matrix.target }}/release/bundle/deb/*.deb
|
|
||||||
src-tauri/target/${{ matrix.target }}/release/bundle/rpm/*.rpm
|
|
||||||
|
|
||||||
autobuild-x86-arm-windows_webview2:
|
|
||||||
name: Autobuild x86 and ARM Windows with WebView2
|
|
||||||
needs: [check_commit, update_tag]
|
|
||||||
if: ${{ needs.check_commit.outputs.should_run == 'true' }}
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- os: windows-latest
|
|
||||||
target: x86_64-pc-windows-msvc
|
|
||||||
arch: x64
|
|
||||||
- os: windows-latest
|
|
||||||
target: aarch64-pc-windows-msvc
|
|
||||||
arch: arm64
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
steps:
|
|
||||||
- name: Checkout Repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Add Rust Target
|
|
||||||
run: rustup target add ${{ matrix.target }}
|
|
||||||
|
|
||||||
- name: Rust Cache
|
|
||||||
uses: Swatinem/rust-cache@v2
|
|
||||||
with:
|
|
||||||
workspaces: src-tauri
|
|
||||||
cache-all-crates: true
|
|
||||||
save-if: ${{ github.ref == 'refs/heads/dev' }}
|
|
||||||
shared-key: autobuild-${{ runner.os }}-${{ matrix.target }}
|
|
||||||
key: ${{ runner.os }}-${{ matrix.target }}-${{ hashFiles('src-tauri/Cargo.lock') }}
|
|
||||||
|
|
||||||
- name: Install pnpm
|
|
||||||
uses: pnpm/action-setup@v4
|
|
||||||
with:
|
|
||||||
run_install: false
|
|
||||||
|
|
||||||
- name: Install Node
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: "22"
|
|
||||||
cache: "pnpm"
|
|
||||||
|
|
||||||
- name: Cache pnpm store
|
|
||||||
uses: actions/cache@v4
|
|
||||||
with:
|
|
||||||
path: ~/.pnpm-store
|
|
||||||
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-pnpm-
|
|
||||||
|
|
||||||
- name: Pnpm install and check
|
|
||||||
run: |
|
|
||||||
pnpm i
|
|
||||||
pnpm run prebuild ${{ matrix.target }}
|
|
||||||
|
|
||||||
- name: Release ${{ env.TAG_CHANNEL }} Version
|
|
||||||
run: pnpm release-version autobuild-latest
|
|
||||||
|
|
||||||
- name: Download WebView2 Runtime
|
|
||||||
run: |
|
|
||||||
invoke-webrequest -uri https://github.com/westinyang/WebView2RuntimeArchive/releases/download/109.0.1518.78/Microsoft.WebView2.FixedVersionRuntime.109.0.1518.78.${{ matrix.arch }}.cab -outfile Microsoft.WebView2.FixedVersionRuntime.109.0.1518.78.${{ matrix.arch }}.cab
|
|
||||||
Expand .\Microsoft.WebView2.FixedVersionRuntime.109.0.1518.78.${{ matrix.arch }}.cab -F:* ./src-tauri
|
|
||||||
Remove-Item .\src-tauri\tauri.windows.conf.json
|
|
||||||
Rename-Item .\src-tauri\webview2.${{ matrix.arch }}.json tauri.windows.conf.json
|
|
||||||
|
|
||||||
- name: Tauri build for Windows
|
|
||||||
id: build
|
|
||||||
uses: tauri-apps/tauri-action@v0
|
|
||||||
env:
|
|
||||||
NODE_OPTIONS: "--max_old_space_size=4096"
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
|
||||||
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
|
||||||
with:
|
|
||||||
tauriScript: pnpm
|
|
||||||
args: --target ${{ matrix.target }}
|
|
||||||
# includeUpdaterJson: true
|
|
||||||
|
|
||||||
- name: Rename
|
|
||||||
run: |
|
|
||||||
$files = Get-ChildItem ".\src-tauri\target\${{ matrix.target }}\release\bundle\nsis\*-setup.exe"
|
|
||||||
foreach ($file in $files) {
|
|
||||||
$newName = $file.Name -replace "-setup\.exe$", "_fixed_webview2-setup.exe"
|
|
||||||
Rename-Item $file.FullName $newName
|
|
||||||
}
|
|
||||||
|
|
||||||
$files = Get-ChildItem ".\src-tauri\target\${{ matrix.target }}\release\bundle\nsis\*.nsis.zip"
|
|
||||||
foreach ($file in $files) {
|
|
||||||
$newName = $file.Name -replace "-setup\.nsis\.zip$", "_fixed_webview2-setup.nsis.zip"
|
|
||||||
Rename-Item $file.FullName $newName
|
|
||||||
}
|
|
||||||
|
|
||||||
$files = Get-ChildItem ".\src-tauri\target\${{ matrix.target }}\release\bundle\nsis\*-setup.exe.sig"
|
|
||||||
foreach ($file in $files) {
|
|
||||||
$newName = $file.Name -replace "-setup\.exe\.sig$", "_fixed_webview2-setup.exe.sig"
|
|
||||||
Rename-Item $file.FullName $newName
|
|
||||||
}
|
|
||||||
|
|
||||||
- name: Upload Release
|
|
||||||
uses: softprops/action-gh-release@v2
|
|
||||||
with:
|
|
||||||
tag_name: ${{ env.TAG_NAME }}
|
|
||||||
name: "Clash Verge Rev ${{ env.TAG_CHANNEL }}"
|
|
||||||
prerelease: true
|
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
files: src-tauri/target/${{ matrix.target }}/release/bundle/nsis/*setup*
|
|
||||||
|
|
||||||
- name: Portable Bundle
|
|
||||||
run: pnpm portable-fixed-webview2 ${{ matrix.target }} --${{ env.TAG_NAME }}
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
notify-telegram:
|
|
||||||
name: Notify Telegram
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs:
|
|
||||||
[
|
|
||||||
update_tag,
|
|
||||||
autobuild-x86-windows-macos-linux,
|
|
||||||
autobuild-arm-linux,
|
|
||||||
autobuild-x86-arm-windows_webview2,
|
|
||||||
]
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Fetch UPDATE logs
|
|
||||||
id: fetch_update_logs
|
|
||||||
run: |
|
|
||||||
if [ -f "UPDATELOG.md" ]; then
|
|
||||||
UPDATE_LOGS=$(awk '/^## v/{if(flag) exit; flag=1} flag' UPDATELOG.md)
|
|
||||||
if [ -n "$UPDATE_LOGS" ]; then
|
|
||||||
echo "Found update logs"
|
|
||||||
echo "UPDATE_LOGS<<EOF" >> $GITHUB_ENV
|
|
||||||
echo "$UPDATE_LOGS" >> $GITHUB_ENV
|
|
||||||
echo "EOF" >> $GITHUB_ENV
|
|
||||||
else
|
|
||||||
echo "No update sections found in UPDATELOG.md"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "UPDATELOG.md file not found"
|
|
||||||
fi
|
|
||||||
shell: bash
|
|
||||||
|
|
||||||
- name: Install Node
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: "22"
|
|
||||||
|
|
||||||
- uses: pnpm/action-setup@v4
|
|
||||||
name: Install pnpm
|
|
||||||
with:
|
|
||||||
run_install: false
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: pnpm install --frozen-lockfile
|
|
||||||
|
|
||||||
- name: Release AutoBuild Version
|
|
||||||
run: pnpm release-version autobuild-latest
|
|
||||||
|
|
||||||
- name: Get Version and Release Info
|
|
||||||
run: |
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install jq
|
|
||||||
echo "VERSION=$(cat package.json | jq '.version' | tr -d '"')" >> $GITHUB_ENV
|
|
||||||
echo "DOWNLOAD_URL=https://github.com/clash-verge-rev/clash-verge-rev/releases/download/autobuild" >> $GITHUB_ENV
|
|
||||||
echo "BUILDTIME=$(TZ=Asia/Shanghai date)" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Generate release.txt
|
|
||||||
run: |
|
|
||||||
if [ -z "$UPDATE_LOGS" ]; then
|
|
||||||
echo "No update logs found, using default message"
|
|
||||||
UPDATE_LOGS="More new features are now supported. Check for detailed changelog soon."
|
|
||||||
else
|
|
||||||
echo "Using found update logs"
|
|
||||||
fi
|
|
||||||
|
|
||||||
cat > release.txt << EOF
|
|
||||||
$UPDATE_LOGS
|
|
||||||
|
|
||||||
## 下载地址
|
|
||||||
|
|
||||||
### Windows (不再支持Win7)
|
|
||||||
#### 正常版本(推荐)
|
|
||||||
- [64位(常用)](${{ env.DOWNLOAD_URL }}/Clash.Verge_${{ env.VERSION }}_x64-setup_windows.exe) | [ARM64(不常用)](${{ env.DOWNLOAD_URL }}/Clash.Verge_${{ env.VERSION }}_arm64-setup_windows.exe)
|
|
||||||
|
|
||||||
#### 内置Webview2版(体积较大,仅在企业版系统或无法安装webview2时使用)
|
|
||||||
- [64位](${{ env.DOWNLOAD_URL }}/Clash.Verge_${{ env.VERSION }}_x64_fixed_webview2-setup.exe) | [ARM64](${{ env.DOWNLOAD_URL }}/Clash.Verge_${{ env.VERSION }}_arm64_fixed_webview2-setup.exe)
|
|
||||||
|
|
||||||
### macOS
|
|
||||||
- [Apple M芯片](${{ env.DOWNLOAD_URL }}/Clash.Verge_${{ env.VERSION }}_aarch64_darwin.dmg) | [Intel芯片](${{ env.DOWNLOAD_URL }}/Clash.Verge_${{ env.VERSION }}_x64_darwin.dmg)
|
|
||||||
|
|
||||||
### Linux
|
|
||||||
#### DEB包(Debian系) 使用 apt ./路径 安装
|
|
||||||
- [64位](${{ env.DOWNLOAD_URL }}/Clash.Verge_${{ env.VERSION }}_amd64_linux.deb) | [ARM64](${{ env.DOWNLOAD_URL }}/Clash.Verge_${{ env.VERSION }}_arm64.deb) | [ARMv7](${{ env.DOWNLOAD_URL }}/Clash.Verge_${{ env.VERSION }}_armhf.deb)
|
|
||||||
|
|
||||||
#### RPM包(Redhat系) 使用 dnf ./路径 安装
|
|
||||||
- [64位](${{ env.DOWNLOAD_URL }}/Clash.Verge_${{ env.VERSION }}-1.x86_64_linux.rpm) | [ARM64](${{ env.DOWNLOAD_URL }}/Clash.Verge_${{ env.VERSION }}-1.aarch64.rpm) | [ARMv7](${{ env.DOWNLOAD_URL }}/Clash.Verge_${{ env.VERSION }}-1.armhfp.rpm)
|
|
||||||
|
|
||||||
### FAQ
|
|
||||||
- [常见问题](https://clash-verge-rev.github.io/faq/windows.html)
|
|
||||||
|
|
||||||
### 稳定机场VPN推荐
|
|
||||||
- [狗狗加速](https://verge.dginv.click/#/register?code=oaxsAGo6)
|
|
||||||
|
|
||||||
Created at ${{ env.BUILDTIME }}.
|
|
||||||
EOF
|
|
||||||
|
|
||||||
- name: Send Telegram Notification
|
|
||||||
run: node scripts/telegram.mjs
|
|
||||||
env:
|
|
||||||
TELEGRAM_BOT_TOKEN: ${{ secrets.TELEGRAM_BOT_TOKEN }}
|
|
||||||
BUILD_TYPE: autobuild
|
|
||||||
VERSION: ${{ env.VERSION }}
|
|
||||||
DOWNLOAD_URL: ${{ env.DOWNLOAD_URL }}
|
|
||||||
159
.github/workflows/check-commit-needs-build.yml
vendored
@@ -1,159 +0,0 @@
|
|||||||
name: Check Commit Needs Build
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
tag_name:
|
|
||||||
description: "Release tag name to check against (default: autobuild)"
|
|
||||||
required: false
|
|
||||||
default: "autobuild"
|
|
||||||
type: string
|
|
||||||
force_build:
|
|
||||||
description: "Force build regardless of checks"
|
|
||||||
required: false
|
|
||||||
default: false
|
|
||||||
type: boolean
|
|
||||||
workflow_call:
|
|
||||||
inputs:
|
|
||||||
tag_name:
|
|
||||||
description: "Release tag name to check against (default: autobuild)"
|
|
||||||
required: false
|
|
||||||
default: "autobuild"
|
|
||||||
type: string
|
|
||||||
force_build:
|
|
||||||
description: "Force build regardless of checks"
|
|
||||||
required: false
|
|
||||||
default: false
|
|
||||||
type: boolean
|
|
||||||
outputs:
|
|
||||||
should_run:
|
|
||||||
description: "Whether the build should run"
|
|
||||||
value: ${{ jobs.check_commit.outputs.should_run }}
|
|
||||||
last_tauri_commit:
|
|
||||||
description: "The last commit hash with Tauri-related changes"
|
|
||||||
value: ${{ jobs.check_commit.outputs.last_tauri_commit }}
|
|
||||||
autobuild_version:
|
|
||||||
description: "The generated autobuild version string"
|
|
||||||
value: ${{ jobs.check_commit.outputs.autobuild_version }}
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
actions: read
|
|
||||||
|
|
||||||
env:
|
|
||||||
TAG_NAME: ${{ inputs.tag_name || 'autobuild' }}
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
check_commit:
|
|
||||||
name: Check Commit Needs Build
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
outputs:
|
|
||||||
should_run: ${{ steps.check.outputs.should_run }}
|
|
||||||
last_tauri_commit: ${{ steps.check.outputs.last_tauri_commit }}
|
|
||||||
autobuild_version: ${{ steps.check.outputs.autobuild_version }}
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 50
|
|
||||||
|
|
||||||
- name: Check if version changed or src changed
|
|
||||||
id: check
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
run: |
|
|
||||||
# Force build if requested
|
|
||||||
if [ "${{ inputs.force_build }}" == "true" ]; then
|
|
||||||
echo "🚀 Force build requested"
|
|
||||||
echo "should_run=true" >> $GITHUB_OUTPUT
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
CURRENT_VERSION=$(cat package.json | jq -r '.version')
|
|
||||||
echo "📦 Current version: $CURRENT_VERSION"
|
|
||||||
|
|
||||||
git checkout HEAD~1 package.json
|
|
||||||
PREVIOUS_VERSION=$(cat package.json | jq -r '.version')
|
|
||||||
echo "📦 Previous version: $PREVIOUS_VERSION"
|
|
||||||
|
|
||||||
git checkout HEAD package.json
|
|
||||||
|
|
||||||
if [ "$CURRENT_VERSION" != "$PREVIOUS_VERSION" ]; then
|
|
||||||
echo "✅ Version changed from $PREVIOUS_VERSION to $CURRENT_VERSION"
|
|
||||||
echo "should_run=true" >> $GITHUB_OUTPUT
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Use get_latest_tauri_commit.bash to find the latest Tauri-related commit
|
|
||||||
echo "🔍 Finding last commit with Tauri-related changes using script..."
|
|
||||||
|
|
||||||
# Make script executable
|
|
||||||
chmod +x scripts-workflow/get_latest_tauri_commit.bash
|
|
||||||
|
|
||||||
# Get the latest Tauri-related commit hash (full hash)
|
|
||||||
LAST_TAURI_COMMIT_FULL=$(./scripts-workflow/get_latest_tauri_commit.bash)
|
|
||||||
if [[ $? -ne 0 ]] || [[ -z "$LAST_TAURI_COMMIT_FULL" ]]; then
|
|
||||||
echo "❌ Failed to get Tauri-related commit, using current commit"
|
|
||||||
LAST_TAURI_COMMIT_FULL=$(git rev-parse HEAD)
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Get short hash for display and version tagging
|
|
||||||
LAST_TAURI_COMMIT=$(git rev-parse --short "$LAST_TAURI_COMMIT_FULL")
|
|
||||||
|
|
||||||
echo "📝 Last Tauri-related commit: $LAST_TAURI_COMMIT"
|
|
||||||
|
|
||||||
# Generate autobuild version using autobuild-latest format
|
|
||||||
CURRENT_BASE_VERSION=$(echo "$CURRENT_VERSION" | sed -E 's/-(alpha|beta|rc)(\.[0-9]+)?//g' | sed -E 's/\+[a-zA-Z0-9.-]+//g')
|
|
||||||
MONTH=$(TZ=Asia/Shanghai date +%m)
|
|
||||||
DAY=$(TZ=Asia/Shanghai date +%d)
|
|
||||||
AUTOBUILD_VERSION="${CURRENT_BASE_VERSION}+autobuild.${MONTH}${DAY}.${LAST_TAURI_COMMIT}"
|
|
||||||
|
|
||||||
echo "🏷️ Autobuild version: $AUTOBUILD_VERSION"
|
|
||||||
echo "📝 Last Tauri commit: $LAST_TAURI_COMMIT"
|
|
||||||
|
|
||||||
# Set outputs for other jobs to use
|
|
||||||
echo "last_tauri_commit=$LAST_TAURI_COMMIT" >> $GITHUB_OUTPUT
|
|
||||||
echo "autobuild_version=$AUTOBUILD_VERSION" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
# Check if autobuild release exists
|
|
||||||
echo "🔍 Checking autobuild release and latest.json..."
|
|
||||||
AUTOBUILD_RELEASE_EXISTS=$(gh release view "${{ env.TAG_NAME }}" --json id -q '.id' 2>/dev/null || echo "")
|
|
||||||
|
|
||||||
if [ -z "$AUTOBUILD_RELEASE_EXISTS" ]; then
|
|
||||||
echo "✅ No autobuild release exists, build needed"
|
|
||||||
echo "should_run=true" >> $GITHUB_OUTPUT
|
|
||||||
else
|
|
||||||
# Check if latest.json exists in the release
|
|
||||||
LATEST_JSON_EXISTS=$(gh release view "${{ env.TAG_NAME }}" --json assets -q '.assets[] | select(.name == "latest.json") | .name' 2>/dev/null || echo "")
|
|
||||||
|
|
||||||
if [ -z "$LATEST_JSON_EXISTS" ]; then
|
|
||||||
echo "✅ No latest.json found in autobuild release, build needed"
|
|
||||||
echo "should_run=true" >> $GITHUB_OUTPUT
|
|
||||||
else
|
|
||||||
# Download and parse latest.json to check version and commit hash
|
|
||||||
echo "📥 Downloading latest.json to check version..."
|
|
||||||
LATEST_JSON_URL="https://github.com/clash-verge-rev/clash-verge-rev/releases/download/autobuild/latest.json"
|
|
||||||
|
|
||||||
LATEST_JSON_CONTENT=$(curl -sL "$LATEST_JSON_URL" 2>/dev/null || echo "")
|
|
||||||
|
|
||||||
if [ -n "$LATEST_JSON_CONTENT" ]; then
|
|
||||||
LATEST_VERSION=$(echo "$LATEST_JSON_CONTENT" | jq -r '.version' 2>/dev/null || echo "")
|
|
||||||
echo "📦 Latest autobuild version: $LATEST_VERSION"
|
|
||||||
|
|
||||||
# Extract commit hash from version string (format: X.Y.Z+autobuild.MMDD.commit)
|
|
||||||
LATEST_COMMIT=$(echo "$LATEST_VERSION" | sed -n 's/.*+autobuild\.[0-9]\{4\}\.\([a-f0-9]*\)$/\1/p' || echo "")
|
|
||||||
echo "📝 Latest autobuild commit: $LATEST_COMMIT"
|
|
||||||
|
|
||||||
if [ "$LAST_TAURI_COMMIT" != "$LATEST_COMMIT" ]; then
|
|
||||||
echo "✅ Tauri commit hash mismatch ($LAST_TAURI_COMMIT != $LATEST_COMMIT), build needed"
|
|
||||||
echo "should_run=true" >> $GITHUB_OUTPUT
|
|
||||||
else
|
|
||||||
echo "❌ Same Tauri commit hash ($LAST_TAURI_COMMIT), no build needed"
|
|
||||||
echo "should_run=false" >> $GITHUB_OUTPUT
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "⚠️ Failed to download or parse latest.json, build needed"
|
|
||||||
echo "should_run=true" >> $GITHUB_OUTPUT
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
220
.github/workflows/clean-old-assets.yml
vendored
@@ -1,220 +0,0 @@
|
|||||||
name: Clean Old Assets
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
tag_name:
|
|
||||||
description: "Release tag name to clean (default: autobuild)"
|
|
||||||
required: false
|
|
||||||
default: "autobuild"
|
|
||||||
type: string
|
|
||||||
dry_run:
|
|
||||||
description: "Dry run mode (only show what would be deleted)"
|
|
||||||
required: false
|
|
||||||
default: false
|
|
||||||
type: boolean
|
|
||||||
workflow_call:
|
|
||||||
inputs:
|
|
||||||
tag_name:
|
|
||||||
description: "Release tag name to clean (default: autobuild)"
|
|
||||||
required: false
|
|
||||||
default: "autobuild"
|
|
||||||
type: string
|
|
||||||
dry_run:
|
|
||||||
description: "Dry run mode (only show what would be deleted)"
|
|
||||||
required: false
|
|
||||||
default: false
|
|
||||||
type: boolean
|
|
||||||
|
|
||||||
permissions: write-all
|
|
||||||
|
|
||||||
env:
|
|
||||||
TAG_NAME: ${{ inputs.tag_name || 'autobuild' }}
|
|
||||||
TAG_CHANNEL: AutoBuild
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
check_current_version:
|
|
||||||
name: Check Current Version and Commit
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
outputs:
|
|
||||||
current_version: ${{ steps.check.outputs.current_version }}
|
|
||||||
last_tauri_commit: ${{ steps.check.outputs.last_tauri_commit }}
|
|
||||||
autobuild_version: ${{ steps.check.outputs.autobuild_version }}
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 50
|
|
||||||
|
|
||||||
- name: Get current version and find last Tauri commit
|
|
||||||
id: check
|
|
||||||
run: |
|
|
||||||
CURRENT_VERSION=$(cat package.json | jq -r '.version')
|
|
||||||
echo "📦 Current version: $CURRENT_VERSION"
|
|
||||||
|
|
||||||
# Find the last commit that changed Tauri-related files
|
|
||||||
echo "🔍 Finding last commit with Tauri-related changes..."
|
|
||||||
|
|
||||||
# Define patterns for Tauri-related files
|
|
||||||
TAURI_PATTERNS="src/ src-tauri/src src-tauri/Cargo.toml src-tauri/Cargo.lock src-tauri/tauri.*.conf.json src-tauri/build.rs src-tauri/capabilities"
|
|
||||||
|
|
||||||
# Get the last commit that changed any of these patterns (excluding build artifacts)
|
|
||||||
LAST_TAURI_COMMIT=""
|
|
||||||
for commit in $(git rev-list HEAD --max-count=50); do
|
|
||||||
# Check if this commit changed any Tauri-related files
|
|
||||||
CHANGED_FILES=$(git show --name-only --pretty=format: $commit | tr '\n' ' ')
|
|
||||||
HAS_TAURI_CHANGES=false
|
|
||||||
|
|
||||||
# Check each pattern
|
|
||||||
if echo "$CHANGED_FILES" | grep -q "src/" && echo "$CHANGED_FILES" | grep -qvE "src/(dist|build|node_modules|\.next|\.cache)"; then
|
|
||||||
HAS_TAURI_CHANGES=true
|
|
||||||
elif echo "$CHANGED_FILES" | grep -qE "src-tauri/(src|Cargo\.(toml|lock)|tauri\..*\.conf\.json|build\.rs|capabilities)"; then
|
|
||||||
HAS_TAURI_CHANGES=true
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$HAS_TAURI_CHANGES" = true ]; then
|
|
||||||
LAST_TAURI_COMMIT=$(git rev-parse --short $commit)
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ -z "$LAST_TAURI_COMMIT" ]; then
|
|
||||||
echo "⚠️ No Tauri-related changes found in recent commits, using current commit"
|
|
||||||
LAST_TAURI_COMMIT=$(git rev-parse --short HEAD)
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "📝 Last Tauri-related commit: $LAST_TAURI_COMMIT"
|
|
||||||
echo "📝 Current commit: $(git rev-parse --short HEAD)"
|
|
||||||
|
|
||||||
# Generate autobuild version for consistency
|
|
||||||
CURRENT_BASE_VERSION=$(echo "$CURRENT_VERSION" | sed -E 's/-(alpha|beta|rc)(\.[0-9]+)?//g' | sed -E 's/\+[a-zA-Z0-9.-]+//g')
|
|
||||||
MONTH=$(TZ=Asia/Shanghai date +%m)
|
|
||||||
DAY=$(TZ=Asia/Shanghai date +%d)
|
|
||||||
AUTOBUILD_VERSION="${CURRENT_BASE_VERSION}+autobuild.${MONTH}${DAY}.${LAST_TAURI_COMMIT}"
|
|
||||||
|
|
||||||
echo "🏷️ Current autobuild version: $AUTOBUILD_VERSION"
|
|
||||||
|
|
||||||
# Set outputs for other jobs to use
|
|
||||||
echo "current_version=$CURRENT_VERSION" >> $GITHUB_OUTPUT
|
|
||||||
echo "last_tauri_commit=$LAST_TAURI_COMMIT" >> $GITHUB_OUTPUT
|
|
||||||
echo "autobuild_version=$AUTOBUILD_VERSION" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
clean_old_assets:
|
|
||||||
name: Clean Old Release Assets
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: check_current_version
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Clean old assets from release
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
TAG_NAME: ${{ env.TAG_NAME }}
|
|
||||||
DRY_RUN: ${{ inputs.dry_run }}
|
|
||||||
run: |
|
|
||||||
# Use values from check_current_version job
|
|
||||||
CURRENT_AUTOBUILD_VERSION="${{ needs.check_current_version.outputs.autobuild_version }}"
|
|
||||||
LAST_TAURI_COMMIT="${{ needs.check_current_version.outputs.last_tauri_commit }}"
|
|
||||||
CURRENT_VERSION="${{ needs.check_current_version.outputs.current_version }}"
|
|
||||||
|
|
||||||
echo "📦 Current version: $CURRENT_VERSION"
|
|
||||||
echo "📦 Current autobuild version: $CURRENT_AUTOBUILD_VERSION"
|
|
||||||
echo "📝 Last Tauri commit: $LAST_TAURI_COMMIT"
|
|
||||||
echo "🏷️ Target tag: $TAG_NAME"
|
|
||||||
echo "🔍 Dry run mode: $DRY_RUN"
|
|
||||||
|
|
||||||
# Check if release exists
|
|
||||||
RELEASE_EXISTS=$(gh release view "$TAG_NAME" --json id -q '.id' 2>/dev/null || echo "")
|
|
||||||
|
|
||||||
if [ -z "$RELEASE_EXISTS" ]; then
|
|
||||||
echo "❌ Release '$TAG_NAME' not found"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "✅ Found release '$TAG_NAME'"
|
|
||||||
|
|
||||||
# Get all assets
|
|
||||||
echo "📋 Getting list of all assets..."
|
|
||||||
assets=$(gh release view "$TAG_NAME" --json assets -q '.assets[].name' || true)
|
|
||||||
|
|
||||||
if [ -z "$assets" ]; then
|
|
||||||
echo "ℹ️ No assets found in release '$TAG_NAME'"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "📋 Found assets:"
|
|
||||||
echo "$assets" | sed 's/^/ - /'
|
|
||||||
|
|
||||||
# Count assets to keep and delete
|
|
||||||
ASSETS_TO_KEEP=""
|
|
||||||
ASSETS_TO_DELETE=""
|
|
||||||
|
|
||||||
for asset in $assets; do
|
|
||||||
# Keep assets that match current autobuild version or are non-versioned files (like latest.json)
|
|
||||||
if [[ "$asset" == *"$CURRENT_AUTOBUILD_VERSION"* ]] || [[ "$asset" == "latest.json" ]]; then
|
|
||||||
ASSETS_TO_KEEP="$ASSETS_TO_KEEP$asset\n"
|
|
||||||
else
|
|
||||||
ASSETS_TO_DELETE="$ASSETS_TO_DELETE$asset\n"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "🔒 Assets to keep (current version: $CURRENT_AUTOBUILD_VERSION):"
|
|
||||||
if [ -n "$ASSETS_TO_KEEP" ]; then
|
|
||||||
echo -e "$ASSETS_TO_KEEP" | grep -v '^$' | sed 's/^/ - /'
|
|
||||||
else
|
|
||||||
echo " - None"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "🗑️ Assets to delete:"
|
|
||||||
if [ -n "$ASSETS_TO_DELETE" ]; then
|
|
||||||
echo -e "$ASSETS_TO_DELETE" | grep -v '^$' | sed 's/^/ - /'
|
|
||||||
else
|
|
||||||
echo " - None"
|
|
||||||
echo "ℹ️ No old assets to clean"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$DRY_RUN" = "true" ]; then
|
|
||||||
echo ""
|
|
||||||
echo "🔍 DRY RUN MODE: No assets will actually be deleted"
|
|
||||||
echo " To actually delete these assets, run this workflow again with dry_run=false"
|
|
||||||
else
|
|
||||||
echo ""
|
|
||||||
echo "🗑️ Deleting old assets..."
|
|
||||||
|
|
||||||
DELETED_COUNT=0
|
|
||||||
FAILED_COUNT=0
|
|
||||||
|
|
||||||
for asset in $assets; do
|
|
||||||
# Skip assets that should be kept
|
|
||||||
if [[ "$asset" == *"$CURRENT_AUTOBUILD_VERSION"* ]] || [[ "$asset" == "latest.json" ]]; then
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo " Deleting: $asset"
|
|
||||||
if gh release delete-asset "$TAG_NAME" "$asset" -y 2>/dev/null; then
|
|
||||||
DELETED_COUNT=$((DELETED_COUNT + 1))
|
|
||||||
else
|
|
||||||
echo " ⚠️ Failed to delete $asset"
|
|
||||||
FAILED_COUNT=$((FAILED_COUNT + 1))
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "📊 Cleanup summary:"
|
|
||||||
echo " - Deleted: $DELETED_COUNT assets"
|
|
||||||
if [ $FAILED_COUNT -gt 0 ]; then
|
|
||||||
echo " - Failed: $FAILED_COUNT assets"
|
|
||||||
fi
|
|
||||||
echo " - Kept: $(echo -e "$ASSETS_TO_KEEP" | grep -v '^$' | wc -l) assets"
|
|
||||||
|
|
||||||
if [ $FAILED_COUNT -gt 0 ]; then
|
|
||||||
echo "⚠️ Some assets failed to delete. Please check the logs above."
|
|
||||||
exit 1
|
|
||||||
else
|
|
||||||
echo "✅ Cleanup completed successfully!"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
67
.github/workflows/cross_check.yaml
vendored
@@ -1,67 +0,0 @@
|
|||||||
name: Cross Platform Cargo Check
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
# pull_request:
|
|
||||||
# push:
|
|
||||||
# branches: [main, dev]
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
env:
|
|
||||||
HUSKY: 0
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
cargo-check:
|
|
||||||
# Treat all Rust compiler warnings as errors
|
|
||||||
env:
|
|
||||||
RUSTFLAGS: "-D warnings"
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- os: macos-latest
|
|
||||||
target: aarch64-apple-darwin
|
|
||||||
- os: windows-latest
|
|
||||||
target: x86_64-pc-windows-msvc
|
|
||||||
- os: ubuntu-latest
|
|
||||||
target: x86_64-unknown-linux-gnu
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
steps:
|
|
||||||
- name: Checkout Repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Install Rust Stable
|
|
||||||
uses: dtolnay/rust-toolchain@stable
|
|
||||||
with:
|
|
||||||
targets: ${{ matrix.target }}
|
|
||||||
|
|
||||||
- name: Add Rust Target
|
|
||||||
run: rustup target add ${{ matrix.target }}
|
|
||||||
|
|
||||||
- name: Install Node
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: "20"
|
|
||||||
|
|
||||||
- uses: pnpm/action-setup@v4
|
|
||||||
name: Install pnpm
|
|
||||||
with:
|
|
||||||
run_install: false
|
|
||||||
|
|
||||||
- name: Pnpm install and check
|
|
||||||
run: |
|
|
||||||
pnpm i
|
|
||||||
pnpm run prebuild ${{ matrix.target }}
|
|
||||||
|
|
||||||
- name: Rust Cache
|
|
||||||
uses: Swatinem/rust-cache@v2
|
|
||||||
with:
|
|
||||||
workspaces: src-tauri
|
|
||||||
save-if: false
|
|
||||||
|
|
||||||
- name: Cargo Check (deny warnings)
|
|
||||||
working-directory: src-tauri
|
|
||||||
run: |
|
|
||||||
cargo check --target ${{ matrix.target }} --workspace --all-features
|
|
||||||
161
.github/workflows/dev.yml
vendored
@@ -1,161 +0,0 @@
|
|||||||
name: Development Test
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
run_windows:
|
|
||||||
description: "运行 Windows"
|
|
||||||
required: false
|
|
||||||
type: boolean
|
|
||||||
default: true
|
|
||||||
run_macos_aarch64:
|
|
||||||
description: "运行 macOS aarch64"
|
|
||||||
required: false
|
|
||||||
type: boolean
|
|
||||||
default: true
|
|
||||||
run_windows_arm64:
|
|
||||||
description: "运行 Windows ARM64"
|
|
||||||
required: false
|
|
||||||
type: boolean
|
|
||||||
default: true
|
|
||||||
run_linux_amd64:
|
|
||||||
description: "运行 Linux amd64"
|
|
||||||
required: false
|
|
||||||
type: boolean
|
|
||||||
default: true
|
|
||||||
|
|
||||||
permissions: write-all
|
|
||||||
env:
|
|
||||||
TAG_NAME: deploytest
|
|
||||||
TAG_CHANNEL: DeployTest
|
|
||||||
CARGO_INCREMENTAL: 0
|
|
||||||
RUST_BACKTRACE: short
|
|
||||||
HUSKY: 0
|
|
||||||
concurrency:
|
|
||||||
group: "${{ github.workflow }} - ${{ github.head_ref || github.ref }}"
|
|
||||||
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
dev:
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- os: windows-latest
|
|
||||||
target: x86_64-pc-windows-msvc
|
|
||||||
bundle: nsis
|
|
||||||
id: windows
|
|
||||||
input: run_windows
|
|
||||||
- os: macos-latest
|
|
||||||
target: aarch64-apple-darwin
|
|
||||||
bundle: dmg
|
|
||||||
id: macos-aarch64
|
|
||||||
input: run_macos_aarch64
|
|
||||||
- os: windows-latest
|
|
||||||
target: aarch64-pc-windows-msvc
|
|
||||||
bundle: nsis
|
|
||||||
id: windows-arm64
|
|
||||||
input: run_windows_arm64
|
|
||||||
- os: ubuntu-22.04
|
|
||||||
target: x86_64-unknown-linux-gnu
|
|
||||||
bundle: deb
|
|
||||||
id: linux-amd64
|
|
||||||
input: run_linux_amd64
|
|
||||||
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
steps:
|
|
||||||
- name: Skip job if not selected
|
|
||||||
if: github.event.inputs[matrix.input] != 'true'
|
|
||||||
run: echo "Job ${{ matrix.id }} skipped as requested"
|
|
||||||
|
|
||||||
- name: Checkout Repository
|
|
||||||
if: github.event.inputs[matrix.input] == 'true'
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Install Rust Stable
|
|
||||||
if: github.event.inputs[matrix.input] == 'true'
|
|
||||||
uses: dtolnay/rust-toolchain@stable
|
|
||||||
|
|
||||||
- name: Add Rust Target
|
|
||||||
if: github.event.inputs[matrix.input] == 'true'
|
|
||||||
run: rustup target add ${{ matrix.target }}
|
|
||||||
|
|
||||||
- name: Rust Cache
|
|
||||||
if: github.event.inputs[matrix.input] == 'true'
|
|
||||||
uses: Swatinem/rust-cache@v2
|
|
||||||
with:
|
|
||||||
workspaces: src-tauri
|
|
||||||
save-if: false
|
|
||||||
cache-all-crates: true
|
|
||||||
shared-key: autobuild-shared
|
|
||||||
|
|
||||||
- name: Install dependencies (ubuntu only)
|
|
||||||
if: matrix.os == 'ubuntu-22.04' && github.event.inputs[matrix.input] == 'true'
|
|
||||||
run: |
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install -y libxslt1.1 libwebkit2gtk-4.1-dev libayatana-appindicator3-dev librsvg2-dev patchelf
|
|
||||||
|
|
||||||
- uses: pnpm/action-setup@v4
|
|
||||||
name: Install pnpm
|
|
||||||
if: github.event.inputs[matrix.input] == 'true'
|
|
||||||
with:
|
|
||||||
run_install: false
|
|
||||||
|
|
||||||
- name: Install Node
|
|
||||||
if: github.event.inputs[matrix.input] == 'true'
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: "20"
|
|
||||||
cache: "pnpm"
|
|
||||||
|
|
||||||
- name: Pnpm install and check
|
|
||||||
if: github.event.inputs[matrix.input] == 'true'
|
|
||||||
run: |
|
|
||||||
pnpm i
|
|
||||||
pnpm run prebuild ${{ matrix.target }}
|
|
||||||
|
|
||||||
- name: Release ${{ env.TAG_CHANNEL }} Version
|
|
||||||
if: github.event.inputs[matrix.input] == 'true'
|
|
||||||
run: pnpm release-version ${{ env.TAG_NAME }}
|
|
||||||
|
|
||||||
- name: Tauri build
|
|
||||||
if: github.event.inputs[matrix.input] == 'true'
|
|
||||||
uses: tauri-apps/tauri-action@v0
|
|
||||||
env:
|
|
||||||
NODE_OPTIONS: "--max_old_space_size=4096"
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
|
||||||
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
|
||||||
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
|
|
||||||
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
|
|
||||||
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
|
|
||||||
APPLE_ID: ${{ secrets.APPLE_ID }}
|
|
||||||
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
|
|
||||||
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
|
||||||
with:
|
|
||||||
tauriScript: pnpm
|
|
||||||
args: --target ${{ matrix.target }} -b ${{ matrix.bundle }}
|
|
||||||
|
|
||||||
- name: Upload Artifacts (macOS)
|
|
||||||
if: matrix.os == 'macos-latest' && github.event.inputs[matrix.input] == 'true'
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: ${{ matrix.target }}
|
|
||||||
path: src-tauri/target/${{ matrix.target }}/release/bundle/dmg/*.dmg
|
|
||||||
if-no-files-found: error
|
|
||||||
|
|
||||||
- name: Upload Artifacts (Windows)
|
|
||||||
if: matrix.os == 'windows-latest' && github.event.inputs[matrix.input] == 'true'
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: ${{ matrix.target }}
|
|
||||||
path: src-tauri/target/${{ matrix.target }}/release/bundle/nsis/*.exe
|
|
||||||
if-no-files-found: error
|
|
||||||
|
|
||||||
- name: Upload Artifacts (Linux)
|
|
||||||
if: matrix.os == 'ubuntu-22.04' && github.event.inputs[matrix.input] == 'true'
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: ${{ matrix.target }}
|
|
||||||
path: src-tauri/target/${{ matrix.target }}/release/bundle/deb/*.deb
|
|
||||||
if-no-files-found: error
|
|
||||||
92
.github/workflows/fmt.yml
vendored
@@ -1,92 +0,0 @@
|
|||||||
# Copyright 2019-2024 Tauri Programme within The Commons Conservancy
|
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
|
||||||
# SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
name: Check Formatting
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
|
|
||||||
env:
|
|
||||||
HUSKY: 0
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
rustfmt:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Check Rust changes
|
|
||||||
id: check_rust
|
|
||||||
uses: dorny/paths-filter@v3
|
|
||||||
with:
|
|
||||||
filters: |
|
|
||||||
rust:
|
|
||||||
- 'src-tauri/**'
|
|
||||||
- '**/*.rs'
|
|
||||||
|
|
||||||
- name: Skip if no Rust changes
|
|
||||||
if: steps.check_rust.outputs.rust != 'true'
|
|
||||||
run: echo "No Rust changes, skipping rustfmt."
|
|
||||||
|
|
||||||
- name: install Rust stable and rustfmt
|
|
||||||
if: steps.check_rust.outputs.rust == 'true'
|
|
||||||
uses: dtolnay/rust-toolchain@stable
|
|
||||||
with:
|
|
||||||
components: rustfmt
|
|
||||||
|
|
||||||
- name: run cargo fmt
|
|
||||||
if: steps.check_rust.outputs.rust == 'true'
|
|
||||||
run: cargo fmt --manifest-path ./src-tauri/Cargo.toml --all -- --check
|
|
||||||
|
|
||||||
prettier:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Check Web changes
|
|
||||||
id: check_web
|
|
||||||
uses: dorny/paths-filter@v3
|
|
||||||
with:
|
|
||||||
filters: |
|
|
||||||
web:
|
|
||||||
- 'src/**'
|
|
||||||
- '**/*.js'
|
|
||||||
- '**/*.ts'
|
|
||||||
- '**/*.tsx'
|
|
||||||
- '**/*.css'
|
|
||||||
- '**/*.scss'
|
|
||||||
- '**/*.json'
|
|
||||||
- '**/*.md'
|
|
||||||
- '**/*.json'
|
|
||||||
|
|
||||||
- name: Skip if no Web changes
|
|
||||||
if: steps.check_web.outputs.web != 'true'
|
|
||||||
run: echo "No web changes, skipping prettier."
|
|
||||||
|
|
||||||
- uses: actions/setup-node@v4
|
|
||||||
if: steps.check_web.outputs.web == 'true'
|
|
||||||
with:
|
|
||||||
node-version: "lts/*"
|
|
||||||
- run: corepack enable
|
|
||||||
if: steps.check_web.outputs.web == 'true'
|
|
||||||
- run: pnpm install --frozen-lockfile
|
|
||||||
if: steps.check_web.outputs.web == 'true'
|
|
||||||
- run: pnpm format:check
|
|
||||||
if: steps.check_web.outputs.web == 'true'
|
|
||||||
|
|
||||||
# taplo:
|
|
||||||
# name: taplo (.toml files)
|
|
||||||
# runs-on: ubuntu-latest
|
|
||||||
# steps:
|
|
||||||
# - uses: actions/checkout@v4
|
|
||||||
|
|
||||||
# - name: install Rust stable
|
|
||||||
# uses: dtolnay/rust-toolchain@stable
|
|
||||||
|
|
||||||
# - name: install taplo-cli
|
|
||||||
# uses: taiki-e/install-action@v2
|
|
||||||
# with:
|
|
||||||
# tool: taplo-cli
|
|
||||||
|
|
||||||
# - run: taplo fmt --check --diff
|
|
||||||
82
.github/workflows/lint-clippy.yml
vendored
@@ -1,82 +0,0 @@
|
|||||||
name: Clippy Lint
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
workflow_dispatch:
|
|
||||||
env:
|
|
||||||
HUSKY: 0
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
clippy:
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- os: windows-latest
|
|
||||||
target: x86_64-pc-windows-msvc
|
|
||||||
- os: macos-latest
|
|
||||||
target: aarch64-apple-darwin
|
|
||||||
- os: ubuntu-22.04
|
|
||||||
target: x86_64-unknown-linux-gnu
|
|
||||||
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
steps:
|
|
||||||
- name: Check src-tauri changes
|
|
||||||
if: github.event_name != 'workflow_dispatch'
|
|
||||||
id: check_changes
|
|
||||||
uses: dorny/paths-filter@v3
|
|
||||||
with:
|
|
||||||
filters: |
|
|
||||||
rust:
|
|
||||||
- 'src-tauri/**'
|
|
||||||
|
|
||||||
- name: Skip if src-tauri not changed
|
|
||||||
if: github.event_name != 'workflow_dispatch' && steps.check_changes.outputs.rust != 'true'
|
|
||||||
run: echo "No src-tauri changes, skipping clippy lint."
|
|
||||||
|
|
||||||
- name: Continue if src-tauri changed
|
|
||||||
if: github.event_name != 'workflow_dispatch' && steps.check_changes.outputs.rust == 'true'
|
|
||||||
run: echo "src-tauri changed, running clippy lint."
|
|
||||||
|
|
||||||
- name: Manual trigger - always run
|
|
||||||
if: github.event_name == 'workflow_dispatch'
|
|
||||||
run: |
|
|
||||||
echo "Manual trigger detected: skipping changes check and running clippy."
|
|
||||||
|
|
||||||
- name: Checkout Repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Install Rust Stable
|
|
||||||
uses: dtolnay/rust-toolchain@master
|
|
||||||
with:
|
|
||||||
toolchain: stable
|
|
||||||
components: clippy
|
|
||||||
|
|
||||||
- name: Add Rust Target
|
|
||||||
run: rustup target add ${{ matrix.target }}
|
|
||||||
|
|
||||||
- name: Rust Cache
|
|
||||||
uses: Swatinem/rust-cache@v2
|
|
||||||
with:
|
|
||||||
workspaces: src-tauri
|
|
||||||
cache-all-crates: true
|
|
||||||
save-if: false
|
|
||||||
shared-key: autobuild-${{ runner.os }}-${{ matrix.target }}
|
|
||||||
key: ${{ runner.os }}-${{ matrix.target }}-${{ hashFiles('src-tauri/Cargo.lock') }}
|
|
||||||
|
|
||||||
- name: Install dependencies (ubuntu only)
|
|
||||||
if: matrix.os == 'ubuntu-22.04'
|
|
||||||
run: |
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install -y libxslt1.1 libwebkit2gtk-4.1-dev libayatana-appindicator3-dev librsvg2-dev patchelf
|
|
||||||
|
|
||||||
- name: Run Clippy
|
|
||||||
working-directory: ./src-tauri
|
|
||||||
run: cargo clippy-all
|
|
||||||
|
|
||||||
- name: Run Logging Check
|
|
||||||
working-directory: ./src-tauri
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
cargo install --git https://github.com/clash-verge-rev/clash-verge-logging-check.git
|
|
||||||
clash-verge-logging-check
|
|
||||||
563
.github/workflows/release.yml
vendored
@@ -1,155 +1,14 @@
|
|||||||
name: Release Build
|
name: Release Build
|
||||||
|
|
||||||
on:
|
on:
|
||||||
# ! 为了避免重复发布版本,应当通过独特 git tag 触发。
|
workflow_dispatch:
|
||||||
# ! 不再使用 workflow_dispatch 触发。
|
|
||||||
# workflow_dispatch:
|
|
||||||
push:
|
|
||||||
tags:
|
|
||||||
- "v*.*.*"
|
|
||||||
permissions: write-all
|
permissions: write-all
|
||||||
env:
|
env:
|
||||||
CARGO_INCREMENTAL: 0
|
CARGO_INCREMENTAL: 0
|
||||||
RUST_BACKTRACE: short
|
RUST_BACKTRACE: short
|
||||||
HUSKY: 0
|
|
||||||
concurrency:
|
|
||||||
# only allow per workflow per commit (and not pr) to run at a time
|
|
||||||
group: "${{ github.workflow }} - ${{ github.head_ref || github.ref }}"
|
|
||||||
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
check_tag_version:
|
|
||||||
name: Check Release Tag and package.json Version Consistency
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Check if tag is from main branch
|
|
||||||
run: |
|
|
||||||
TAG_REF="${GITHUB_REF##*/}"
|
|
||||||
echo "Checking if tag $TAG_REF is from main branch..."
|
|
||||||
|
|
||||||
TAG_COMMIT=$(git rev-list -n 1 $TAG_REF)
|
|
||||||
MAIN_COMMITS=$(git rev-list origin/main)
|
|
||||||
|
|
||||||
if echo "$MAIN_COMMITS" | grep -q "$TAG_COMMIT"; then
|
|
||||||
echo "✅ Tag $TAG_REF is from main branch"
|
|
||||||
else
|
|
||||||
echo "❌ Tag $TAG_REF is not from main branch"
|
|
||||||
echo "This release workflow only accepts tags from main branch."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Check tag and package.json version
|
|
||||||
run: |
|
|
||||||
TAG_REF="${GITHUB_REF_NAME:-${GITHUB_REF##*/}}"
|
|
||||||
echo "Current tag: $TAG_REF"
|
|
||||||
|
|
||||||
PKG_VERSION=$(jq -r .version package.json)
|
|
||||||
echo "package.json version: $PKG_VERSION"
|
|
||||||
|
|
||||||
EXPECTED_TAG="v$PKG_VERSION"
|
|
||||||
|
|
||||||
if [[ "$TAG_REF" != "$EXPECTED_TAG" ]]; then
|
|
||||||
echo "❌ Version mismatch:"
|
|
||||||
echo " Git tag : $TAG_REF"
|
|
||||||
echo " package.json : $EXPECTED_TAG"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "✅ Tag and package.json version are consistent."
|
|
||||||
|
|
||||||
update_tag:
|
|
||||||
name: Update tag
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: [release, release-for-linux-arm, release-for-fixed-webview2]
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Fetch UPDATE logs
|
|
||||||
id: fetch_update_logs
|
|
||||||
run: |
|
|
||||||
if [ -f "UPDATELOG.md" ]; then
|
|
||||||
UPDATE_LOGS=$(awk '/^## v/{if(flag) exit; flag=1} flag' UPDATELOG.md)
|
|
||||||
if [ -n "$UPDATE_LOGS" ]; then
|
|
||||||
echo "Found update logs"
|
|
||||||
echo "UPDATE_LOGS<<EOF" >> $GITHUB_ENV
|
|
||||||
echo "$UPDATE_LOGS" >> $GITHUB_ENV
|
|
||||||
echo "EOF" >> $GITHUB_ENV
|
|
||||||
else
|
|
||||||
echo "No update sections found in UPDATELOG.md"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "UPDATELOG.md file not found"
|
|
||||||
fi
|
|
||||||
shell: bash
|
|
||||||
|
|
||||||
- name: Set Env
|
|
||||||
run: |
|
|
||||||
echo "BUILDTIME=$(TZ=Asia/Shanghai date)" >> $GITHUB_ENV
|
|
||||||
TAG_REF="${GITHUB_REF##*/}"
|
|
||||||
echo "TAG_NAME=$TAG_REF" >> $GITHUB_ENV
|
|
||||||
VERSION=$(echo "$TAG_REF" | sed 's/^v//')
|
|
||||||
echo "VERSION=$VERSION" >> $GITHUB_ENV
|
|
||||||
echo "DOWNLOAD_URL=https://github.com/clash-verge-rev/clash-verge-rev/releases/download/$TAG_REF" >> $GITHUB_ENV
|
|
||||||
shell: bash
|
|
||||||
|
|
||||||
- run: |
|
|
||||||
if [ -z "$UPDATE_LOGS" ]; then
|
|
||||||
echo "No update logs found, using default message"
|
|
||||||
UPDATE_LOGS="More new features are now supported. Check for detailed changelog soon."
|
|
||||||
else
|
|
||||||
echo "Using found update logs"
|
|
||||||
fi
|
|
||||||
|
|
||||||
cat > release.txt << EOF
|
|
||||||
$UPDATE_LOGS
|
|
||||||
|
|
||||||
## 下载地址
|
|
||||||
|
|
||||||
### Windows (不再支持Win7)
|
|
||||||
#### 正常版本(推荐)
|
|
||||||
- [64位(常用)](${{ env.DOWNLOAD_URL }}/Clash.Verge_${{ env.VERSION }}_x64-setup.exe) | [ARM64(不常用)](${{ env.DOWNLOAD_URL }}/Clash.Verge_${{ env.VERSION }}_arm64-setup.exe)
|
|
||||||
|
|
||||||
#### 内置Webview2版(体积较大,仅在企业版系统或无法安装webview2时使用)
|
|
||||||
- [64位](${{ env.DOWNLOAD_URL }}/Clash.Verge_${{ env.VERSION }}_x64_fixed_webview2-setup.exe) | [ARM64](${{ env.DOWNLOAD_URL }}/Clash.Verge_${{ env.VERSION }}_arm64_fixed_webview2-setup.exe)
|
|
||||||
|
|
||||||
### macOS
|
|
||||||
- [Apple M芯片](${{ env.DOWNLOAD_URL }}/Clash.Verge_${{ env.VERSION }}_aarch64.dmg) | [Intel芯片](${{ env.DOWNLOAD_URL }}/Clash.Verge_${{ env.VERSION }}_x64.dmg)
|
|
||||||
|
|
||||||
### Linux
|
|
||||||
#### DEB包(Debian系) 使用 apt ./路径 安装
|
|
||||||
- [64位](${{ env.DOWNLOAD_URL }}/Clash.Verge_${{ env.VERSION }}_amd64.deb) | [ARM64](${{ env.DOWNLOAD_URL }}/Clash.Verge_${{ env.VERSION }}_arm64.deb) | [ARMv7](${{ env.DOWNLOAD_URL }}/Clash.Verge_${{ env.VERSION }}_armhf.deb)
|
|
||||||
|
|
||||||
#### RPM包(Redhat系) 使用 dnf ./路径 安装
|
|
||||||
- [64位](${{ env.DOWNLOAD_URL }}/Clash.Verge-${{ env.VERSION }}-1.x86_64.rpm) | [ARM64](${{ env.DOWNLOAD_URL }}/Clash.Verge-${{ env.VERSION }}-1.aarch64.rpm) | [ARMv7](${{ env.DOWNLOAD_URL }}/Clash.Verge-${{ env.VERSION }}-1.armhfp.rpm)
|
|
||||||
|
|
||||||
### FAQ
|
|
||||||
- [常见问题](https://clash-verge-rev.github.io/faq/windows.html)
|
|
||||||
|
|
||||||
### 稳定机场VPN推荐
|
|
||||||
- [狗狗加速](https://verge.dginv.click/#/register?code=oaxsAGo6)
|
|
||||||
Created at ${{ env.BUILDTIME }}.
|
|
||||||
EOF
|
|
||||||
|
|
||||||
- name: Upload Release
|
|
||||||
uses: softprops/action-gh-release@v2
|
|
||||||
with:
|
|
||||||
tag_name: ${{ env.TAG_NAME }}
|
|
||||||
name: "Clash Verge Rev ${{ env.TAG_NAME }}"
|
|
||||||
body_path: release.txt
|
|
||||||
draft: false
|
|
||||||
prerelease: false
|
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
# generate_release_notes: true
|
|
||||||
|
|
||||||
release:
|
release:
|
||||||
name: Release Build
|
|
||||||
needs: [check_tag_version]
|
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
@@ -162,8 +21,6 @@ jobs:
|
|||||||
target: aarch64-apple-darwin
|
target: aarch64-apple-darwin
|
||||||
- os: macos-latest
|
- os: macos-latest
|
||||||
target: x86_64-apple-darwin
|
target: x86_64-apple-darwin
|
||||||
- os: ubuntu-22.04
|
|
||||||
target: x86_64-unknown-linux-gnu
|
|
||||||
|
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
@@ -180,295 +37,111 @@ jobs:
|
|||||||
uses: Swatinem/rust-cache@v2
|
uses: Swatinem/rust-cache@v2
|
||||||
with:
|
with:
|
||||||
workspaces: src-tauri
|
workspaces: src-tauri
|
||||||
save-if: false
|
|
||||||
|
|
||||||
- name: Install dependencies (ubuntu only)
|
|
||||||
if: matrix.os == 'ubuntu-22.04'
|
|
||||||
run: |
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install -y libxslt1.1 libwebkit2gtk-4.1-dev libayatana-appindicator3-dev librsvg2-dev patchelf
|
|
||||||
|
|
||||||
- name: Install x86 OpenSSL (macOS only)
|
|
||||||
if: matrix.target == 'x86_64-apple-darwin'
|
|
||||||
run: |
|
|
||||||
arch -x86_64 brew install openssl@3
|
|
||||||
echo "OPENSSL_DIR=$(brew --prefix openssl@3)" >> $GITHUB_ENV
|
|
||||||
echo "OPENSSL_INCLUDE_DIR=$(brew --prefix openssl@3)/include" >> $GITHUB_ENV
|
|
||||||
echo "OPENSSL_LIB_DIR=$(brew --prefix openssl@3)/lib" >> $GITHUB_ENV
|
|
||||||
echo "PKG_CONFIG_PATH=$(brew --prefix openssl@3)/lib/pkgconfig" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Install Node
|
- name: Install Node
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: "22"
|
node-version: "20"
|
||||||
|
|
||||||
- uses: pnpm/action-setup@v4
|
- uses: pnpm/action-setup@v3
|
||||||
name: Install pnpm
|
name: Install pnpm
|
||||||
with:
|
with:
|
||||||
|
version: 9
|
||||||
run_install: false
|
run_install: false
|
||||||
|
|
||||||
- name: Pnpm install and check
|
- name: Pnpm install and check
|
||||||
run: |
|
run: |
|
||||||
pnpm i
|
pnpm i
|
||||||
pnpm run prebuild ${{ matrix.target }}
|
pnpm check ${{ matrix.target }}
|
||||||
|
|
||||||
- name: Tauri build
|
- name: Tauri build
|
||||||
uses: tauri-apps/tauri-action@v0
|
uses: tauri-apps/tauri-action@v0
|
||||||
env:
|
env:
|
||||||
NODE_OPTIONS: "--max_old_space_size=4096"
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
||||||
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
||||||
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
|
|
||||||
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
|
|
||||||
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
|
|
||||||
APPLE_ID: ${{ secrets.APPLE_ID }}
|
|
||||||
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
|
|
||||||
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
|
||||||
with:
|
with:
|
||||||
tagName: ${{ github.ref_name }}
|
tagName: v__VERSION__
|
||||||
releaseName: "Clash Verge Rev ${{ github.ref_name }}"
|
releaseName: "Clash Verge Rev v__VERSION__"
|
||||||
releaseBody: "Draft release, will be updated later."
|
releaseBody: "More new features are now supported."
|
||||||
releaseDraft: true
|
releaseDraft: false
|
||||||
prerelease: false
|
prerelease: false
|
||||||
tauriScript: pnpm
|
tauriScript: pnpm
|
||||||
args: --target ${{ matrix.target }}
|
args: --target ${{ matrix.target }}
|
||||||
includeUpdaterJson: true
|
|
||||||
|
|
||||||
release-for-linux-arm:
|
- name: Portable Bundle
|
||||||
name: Release Build for Linux ARM
|
if: matrix.os == 'windows-latest'
|
||||||
needs: [check_tag_version]
|
run: pnpm portable ${{ matrix.target }}
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
||||||
|
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
||||||
|
|
||||||
|
release-for-linux:
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- os: ubuntu-22.04
|
- os: ubuntu-latest
|
||||||
|
target: x86_64-unknown-linux-gnu
|
||||||
|
- os: ubuntu-latest
|
||||||
target: aarch64-unknown-linux-gnu
|
target: aarch64-unknown-linux-gnu
|
||||||
arch: arm64
|
- os: ubuntu-latest
|
||||||
- os: ubuntu-22.04
|
|
||||||
target: armv7-unknown-linux-gnueabihf
|
target: armv7-unknown-linux-gnueabihf
|
||||||
arch: armhf
|
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout Repository
|
- name: Checkout Repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Install Rust Stable
|
|
||||||
uses: dtolnay/rust-toolchain@stable
|
|
||||||
|
|
||||||
- name: Add Rust Target
|
|
||||||
run: rustup target add ${{ matrix.target }}
|
|
||||||
|
|
||||||
- name: Rust Cache
|
|
||||||
uses: Swatinem/rust-cache@v2
|
|
||||||
with:
|
|
||||||
workspaces: src-tauri
|
|
||||||
save-if: false
|
|
||||||
|
|
||||||
- name: Install Node
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: "22"
|
|
||||||
|
|
||||||
- name: Install pnpm
|
|
||||||
uses: pnpm/action-setup@v4
|
|
||||||
with:
|
|
||||||
run_install: false
|
|
||||||
|
|
||||||
- name: Pnpm install and check
|
|
||||||
run: |
|
|
||||||
pnpm i
|
|
||||||
pnpm run prebuild ${{ matrix.target }}
|
|
||||||
|
|
||||||
- name: "Setup for linux"
|
|
||||||
run: |-
|
|
||||||
sudo ls -lR /etc/apt/
|
|
||||||
|
|
||||||
cat > /tmp/sources.list << EOF
|
|
||||||
deb [arch=amd64,i386] http://archive.ubuntu.com/ubuntu jammy main multiverse universe restricted
|
|
||||||
deb [arch=amd64,i386] http://archive.ubuntu.com/ubuntu jammy-security main multiverse universe restricted
|
|
||||||
deb [arch=amd64,i386] http://archive.ubuntu.com/ubuntu jammy-updates main multiverse universe restricted
|
|
||||||
deb [arch=amd64,i386] http://archive.ubuntu.com/ubuntu jammy-backports main multiverse universe restricted
|
|
||||||
|
|
||||||
deb [arch=armhf,arm64] http://ports.ubuntu.com/ubuntu-ports jammy main multiverse universe restricted
|
|
||||||
deb [arch=armhf,arm64] http://ports.ubuntu.com/ubuntu-ports jammy-security main multiverse universe restricted
|
|
||||||
deb [arch=armhf,arm64] http://ports.ubuntu.com/ubuntu-ports jammy-updates main multiverse universe restricted
|
|
||||||
deb [arch=armhf,arm64] http://ports.ubuntu.com/ubuntu-ports jammy-backports main multiverse universe restricted
|
|
||||||
EOF
|
|
||||||
|
|
||||||
sudo mv /etc/apt/sources.list /etc/apt/sources.list.default
|
|
||||||
sudo mv /tmp/sources.list /etc/apt/sources.list
|
|
||||||
|
|
||||||
sudo dpkg --add-architecture ${{ matrix.arch }}
|
|
||||||
sudo apt update
|
|
||||||
|
|
||||||
sudo apt install -y \
|
|
||||||
libxslt1.1:${{ matrix.arch }} \
|
|
||||||
libwebkit2gtk-4.1-dev:${{ matrix.arch }} \
|
|
||||||
libayatana-appindicator3-dev:${{ matrix.arch }} \
|
|
||||||
libssl-dev:${{ matrix.arch }} \
|
|
||||||
patchelf:${{ matrix.arch }} \
|
|
||||||
librsvg2-dev:${{ matrix.arch }}
|
|
||||||
|
|
||||||
- name: "Install aarch64 tools"
|
|
||||||
if: matrix.target == 'aarch64-unknown-linux-gnu'
|
|
||||||
run: |
|
|
||||||
sudo apt install -y \
|
|
||||||
gcc-aarch64-linux-gnu \
|
|
||||||
g++-aarch64-linux-gnu
|
|
||||||
|
|
||||||
- name: "Install armv7 tools"
|
|
||||||
if: matrix.target == 'armv7-unknown-linux-gnueabihf'
|
|
||||||
run: |
|
|
||||||
sudo apt install -y \
|
|
||||||
gcc-arm-linux-gnueabihf \
|
|
||||||
g++-arm-linux-gnueabihf
|
|
||||||
|
|
||||||
- name: Build for Linux
|
- name: Build for Linux
|
||||||
run: |
|
uses: ./.github/build-for-linux
|
||||||
export PKG_CONFIG_ALLOW_CROSS=1
|
|
||||||
if [ "${{ matrix.target }}" == "aarch64-unknown-linux-gnu" ]; then
|
|
||||||
export PKG_CONFIG_PATH=/usr/lib/aarch64-linux-gnu/pkgconfig/:$PKG_CONFIG_PATH
|
|
||||||
export PKG_CONFIG_SYSROOT_DIR=/usr/aarch64-linux-gnu/
|
|
||||||
elif [ "${{ matrix.target }}" == "armv7-unknown-linux-gnueabihf" ]; then
|
|
||||||
export PKG_CONFIG_PATH=/usr/lib/arm-linux-gnueabihf/pkgconfig/:$PKG_CONFIG_PATH
|
|
||||||
export PKG_CONFIG_SYSROOT_DIR=/usr/arm-linux-gnueabihf/
|
|
||||||
fi
|
|
||||||
pnpm build --target ${{ matrix.target }}
|
|
||||||
env:
|
env:
|
||||||
NODE_OPTIONS: "--max_old_space_size=4096"
|
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
||||||
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
||||||
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
with:
|
||||||
|
target: ${{ matrix.target }}
|
||||||
|
|
||||||
- name: Get Version
|
- name: Get Version
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install jq
|
sudo apt-get install jq
|
||||||
echo "VERSION=$(cat package.json | jq '.version' | tr -d '"')" >> $GITHUB_ENV
|
echo "VERSION=$(cat package.json | jq '.version' | tr -d '"')" >> $GITHUB_ENV
|
||||||
echo "BUILDTIME=$(TZ=Asia/Shanghai date)" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Upload Release
|
- name: Upload Release
|
||||||
uses: softprops/action-gh-release@v2
|
if: startsWith(matrix.target, 'x86_64')
|
||||||
|
uses: softprops/action-gh-release@v1
|
||||||
with:
|
with:
|
||||||
tag_name: v${{env.VERSION}}
|
tag_name: v${{env.VERSION}}
|
||||||
name: "Clash Verge Rev v${{env.VERSION}}"
|
name: "Clash Verge Rev v${{env.VERSION}}"
|
||||||
body: "See release notes for detailed changelog."
|
body: "More new features are now supported."
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
files: |
|
files: src-tauri/target/${{ matrix.target }}/release/bundle/appimage/*.AppImage*
|
||||||
src-tauri/target/${{ matrix.target }}/release/bundle/deb/*.deb
|
|
||||||
src-tauri/target/${{ matrix.target }}/release/bundle/rpm/*.rpm
|
|
||||||
|
|
||||||
release-for-fixed-webview2:
|
|
||||||
name: Release Build for Fixed WebView2
|
|
||||||
needs: [check_tag_version]
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- os: windows-latest
|
|
||||||
target: x86_64-pc-windows-msvc
|
|
||||||
arch: x64
|
|
||||||
- os: windows-latest
|
|
||||||
target: aarch64-pc-windows-msvc
|
|
||||||
arch: arm64
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
steps:
|
|
||||||
- name: Checkout Repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Add Rust Target
|
|
||||||
run: rustup target add ${{ matrix.target }}
|
|
||||||
|
|
||||||
- name: Rust Cache
|
|
||||||
uses: Swatinem/rust-cache@v2
|
|
||||||
with:
|
|
||||||
workspaces: src-tauri
|
|
||||||
save-if: false
|
|
||||||
|
|
||||||
- name: Install Node
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: "22"
|
|
||||||
|
|
||||||
- uses: pnpm/action-setup@v4
|
|
||||||
name: Install pnpm
|
|
||||||
with:
|
|
||||||
run_install: false
|
|
||||||
|
|
||||||
- name: Pnpm install and check
|
|
||||||
run: |
|
|
||||||
pnpm i
|
|
||||||
pnpm run prebuild ${{ matrix.target }}
|
|
||||||
|
|
||||||
- name: Download WebView2 Runtime
|
|
||||||
run: |
|
|
||||||
invoke-webrequest -uri https://github.com/westinyang/WebView2RuntimeArchive/releases/download/109.0.1518.78/Microsoft.WebView2.FixedVersionRuntime.109.0.1518.78.${{ matrix.arch }}.cab -outfile Microsoft.WebView2.FixedVersionRuntime.109.0.1518.78.${{ matrix.arch }}.cab
|
|
||||||
Expand .\Microsoft.WebView2.FixedVersionRuntime.109.0.1518.78.${{ matrix.arch }}.cab -F:* ./src-tauri
|
|
||||||
Remove-Item .\src-tauri\tauri.windows.conf.json
|
|
||||||
Rename-Item .\src-tauri\webview2.${{ matrix.arch }}.json tauri.windows.conf.json
|
|
||||||
|
|
||||||
- name: Tauri build
|
|
||||||
id: build
|
|
||||||
uses: tauri-apps/tauri-action@v0
|
|
||||||
env:
|
|
||||||
NODE_OPTIONS: "--max_old_space_size=4096"
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
|
||||||
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
|
||||||
with:
|
|
||||||
tauriScript: pnpm
|
|
||||||
args: --target ${{ matrix.target }}
|
|
||||||
|
|
||||||
- name: Rename
|
|
||||||
run: |
|
|
||||||
$files = Get-ChildItem ".\src-tauri\target\${{ matrix.target }}\release\bundle\nsis\*-setup.exe"
|
|
||||||
foreach ($file in $files) {
|
|
||||||
$newName = $file.Name -replace "-setup\.exe$", "_fixed_webview2-setup.exe"
|
|
||||||
Rename-Item $file.FullName $newName
|
|
||||||
}
|
|
||||||
|
|
||||||
$files = Get-ChildItem ".\src-tauri\target\${{ matrix.target }}\release\bundle\nsis\*.nsis.zip"
|
|
||||||
foreach ($file in $files) {
|
|
||||||
$newName = $file.Name -replace "-setup\.nsis\.zip$", "_fixed_webview2-setup.nsis.zip"
|
|
||||||
Rename-Item $file.FullName $newName
|
|
||||||
}
|
|
||||||
|
|
||||||
$files = Get-ChildItem ".\src-tauri\target\${{ matrix.target }}\release\bundle\nsis\*-setup.exe.sig"
|
|
||||||
foreach ($file in $files) {
|
|
||||||
$newName = $file.Name -replace "-setup\.exe\.sig$", "_fixed_webview2-setup.exe.sig"
|
|
||||||
Rename-Item $file.FullName $newName
|
|
||||||
}
|
|
||||||
|
|
||||||
- name: Upload Release
|
- name: Upload Release
|
||||||
uses: softprops/action-gh-release@v2
|
uses: softprops/action-gh-release@v1
|
||||||
with:
|
with:
|
||||||
tag_name: v${{steps.build.outputs.appVersion}}
|
tag_name: v${{env.VERSION}}
|
||||||
name: "Clash Verge Rev v${{steps.build.outputs.appVersion}}"
|
name: "Clash Verge Rev v${{env.VERSION}}"
|
||||||
body: "See release notes for detailed changelog."
|
body: "More new features are now supported."
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
files: src-tauri/target/${{ matrix.target }}/release/bundle/nsis/*setup*
|
files: src-tauri/target/${{ matrix.target }}/release/bundle/deb/*.deb
|
||||||
|
|
||||||
- name: Portable Bundle
|
|
||||||
run: pnpm portable-fixed-webview2 ${{ matrix.target }}
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
release-update:
|
release-update:
|
||||||
name: Release Update
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: [update_tag]
|
needs: [release, release-for-linux]
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Install Node
|
- name: Install Node
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: "22"
|
node-version: "20"
|
||||||
|
|
||||||
- uses: pnpm/action-setup@v4
|
- uses: pnpm/action-setup@v2
|
||||||
name: Install pnpm
|
name: Install pnpm
|
||||||
with:
|
with:
|
||||||
|
version: 8
|
||||||
run_install: false
|
run_install: false
|
||||||
|
|
||||||
- name: Pnpm install
|
- name: Pnpm install
|
||||||
@@ -478,151 +151,3 @@ jobs:
|
|||||||
run: pnpm updater
|
run: pnpm updater
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
release-update-for-fixed-webview2:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: [update_tag]
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Install Node
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: "22"
|
|
||||||
|
|
||||||
- uses: pnpm/action-setup@v4
|
|
||||||
name: Install pnpm
|
|
||||||
with:
|
|
||||||
run_install: false
|
|
||||||
|
|
||||||
- name: Pnpm install
|
|
||||||
run: pnpm i
|
|
||||||
|
|
||||||
- name: Release updater file
|
|
||||||
run: pnpm updater-fixed-webview2
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
submit-to-winget:
|
|
||||||
name: Submit to Winget
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: [update_tag, release-update]
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
- name: Get Version
|
|
||||||
run: |
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install jq
|
|
||||||
echo "VERSION=$(cat package.json | jq '.version' | tr -d '"')" >> $GITHUB_ENV
|
|
||||||
- name: Submit to Winget
|
|
||||||
uses: vedantmgoyal9/winget-releaser@main
|
|
||||||
with:
|
|
||||||
identifier: ClashVergeRev.ClashVergeRev
|
|
||||||
version: ${{env.VERSION}}
|
|
||||||
release-tag: v${{env.VERSION}}
|
|
||||||
installers-regex: '_(arm64|x64|x86)-setup\.exe$'
|
|
||||||
token: ${{ secrets.WINGET_TOKEN }}
|
|
||||||
|
|
||||||
notify-telegram:
|
|
||||||
name: Notify Telegram
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs:
|
|
||||||
[
|
|
||||||
update_tag,
|
|
||||||
release-update,
|
|
||||||
release-update-for-fixed-webview2,
|
|
||||||
submit-to-winget,
|
|
||||||
]
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Fetch UPDATE logs
|
|
||||||
id: fetch_update_logs
|
|
||||||
run: |
|
|
||||||
if [ -f "UPDATELOG.md" ]; then
|
|
||||||
UPDATE_LOGS=$(awk '/^## v/{if(flag) exit; flag=1} flag' UPDATELOG.md)
|
|
||||||
if [ -n "$UPDATE_LOGS" ]; then
|
|
||||||
echo "Found update logs"
|
|
||||||
echo "UPDATE_LOGS<<EOF" >> $GITHUB_ENV
|
|
||||||
echo "$UPDATE_LOGS" >> $GITHUB_ENV
|
|
||||||
echo "EOF" >> $GITHUB_ENV
|
|
||||||
else
|
|
||||||
echo "No update sections found in UPDATELOG.md"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "UPDATELOG.md file not found"
|
|
||||||
fi
|
|
||||||
shell: bash
|
|
||||||
|
|
||||||
- name: Install Node
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: "22"
|
|
||||||
|
|
||||||
- uses: pnpm/action-setup@v4
|
|
||||||
name: Install pnpm
|
|
||||||
with:
|
|
||||||
run_install: false
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: pnpm install --frozen-lockfile
|
|
||||||
|
|
||||||
- name: Get Version and Release Info
|
|
||||||
run: |
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install jq
|
|
||||||
echo "VERSION=$(cat package.json | jq '.version' | tr -d '"')" >> $GITHUB_ENV
|
|
||||||
echo "DOWNLOAD_URL=https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v$(cat package.json | jq '.version' | tr -d '"')" >> $GITHUB_ENV
|
|
||||||
echo "BUILDTIME=$(TZ=Asia/Shanghai date)" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Generate release.txt
|
|
||||||
run: |
|
|
||||||
if [ -z "$UPDATE_LOGS" ]; then
|
|
||||||
echo "No update logs found, using default message"
|
|
||||||
UPDATE_LOGS="More new features are now supported. Check for detailed changelog soon."
|
|
||||||
else
|
|
||||||
echo "Using found update logs"
|
|
||||||
fi
|
|
||||||
|
|
||||||
cat > release.txt << EOF
|
|
||||||
$UPDATE_LOGS
|
|
||||||
|
|
||||||
## 下载地址
|
|
||||||
|
|
||||||
### Windows (不再支持Win7)
|
|
||||||
#### 正常版本(推荐)
|
|
||||||
- [64位(常用)](${{ env.DOWNLOAD_URL }}/Clash.Verge_${{ env.VERSION }}_x64-setup.exe) | [ARM64(不常用)](${{ env.DOWNLOAD_URL }}/Clash.Verge_${{ env.VERSION }}_arm64-setup.exe)
|
|
||||||
|
|
||||||
#### 内置Webview2版(体积较大,仅在企业版系统或无法安装webview2时使用)
|
|
||||||
- [64位](${{ env.DOWNLOAD_URL }}/Clash.Verge_${{ env.VERSION }}_x64_fixed_webview2-setup.exe) | [ARM64](${{ env.DOWNLOAD_URL }}/Clash.Verge_${{ env.VERSION }}_arm64_fixed_webview2-setup.exe)
|
|
||||||
|
|
||||||
### macOS
|
|
||||||
- [Apple M芯片](${{ env.DOWNLOAD_URL }}/Clash.Verge_${{ env.VERSION }}_aarch64.dmg) | [Intel芯片](${{ env.DOWNLOAD_URL }}/Clash.Verge_${{ env.VERSION }}_x64.dmg)
|
|
||||||
|
|
||||||
### Linux
|
|
||||||
#### DEB包(Debian系) 使用 apt ./路径 安装
|
|
||||||
- [64位](${{ env.DOWNLOAD_URL }}/Clash.Verge_${{ env.VERSION }}_amd64.deb) | [ARM64](${{ env.DOWNLOAD_URL }}/Clash.Verge_${{ env.VERSION }}_arm64.deb) | [ARMv7](${{ env.DOWNLOAD_URL }}/Clash.Verge_${{ env.VERSION }}_armhf.deb)
|
|
||||||
|
|
||||||
#### RPM包(Redhat系) 使用 dnf ./路径 安装
|
|
||||||
- [64位](${{ env.DOWNLOAD_URL }}/Clash.Verge-${{ env.VERSION }}-1.x86_64.rpm) | [ARM64](${{ env.DOWNLOAD_URL }}/Clash.Verge-${{ env.VERSION }}-1.aarch64.rpm) | [ARMv7](${{ env.DOWNLOAD_URL }}/Clash.Verge-${{ env.VERSION }}-1.armhfp.rpm)
|
|
||||||
|
|
||||||
### FAQ
|
|
||||||
- [常见问题](https://clash-verge-rev.github.io/faq/windows.html)
|
|
||||||
|
|
||||||
### 稳定机场VPN推荐
|
|
||||||
- [狗狗加速](https://verge.dginv.click/#/register?code=oaxsAGo6)
|
|
||||||
Created at ${{ env.BUILDTIME }}.
|
|
||||||
EOF
|
|
||||||
|
|
||||||
- name: Send Telegram Notification
|
|
||||||
run: node scripts/telegram.mjs
|
|
||||||
env:
|
|
||||||
TELEGRAM_BOT_TOKEN: ${{ secrets.TELEGRAM_BOT_TOKEN }}
|
|
||||||
BUILD_TYPE: release
|
|
||||||
VERSION: ${{ env.VERSION }}
|
|
||||||
DOWNLOAD_URL: ${{ env.DOWNLOAD_URL }}
|
|
||||||
|
|||||||
36
.github/workflows/updater.yml
vendored
@@ -2,24 +2,22 @@ name: Updater CI
|
|||||||
|
|
||||||
on: workflow_dispatch
|
on: workflow_dispatch
|
||||||
permissions: write-all
|
permissions: write-all
|
||||||
env:
|
|
||||||
HUSKY: 0
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
release-update:
|
release-update:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Install Node
|
- name: Install Node
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: "22"
|
node-version: "20"
|
||||||
|
|
||||||
- uses: pnpm/action-setup@v4
|
- uses: pnpm/action-setup@v2
|
||||||
name: Install pnpm
|
name: Install pnpm
|
||||||
with:
|
with:
|
||||||
|
version: 8
|
||||||
run_install: false
|
run_install: false
|
||||||
|
|
||||||
- name: Pnpm install
|
- name: Pnpm install
|
||||||
@@ -29,27 +27,3 @@ jobs:
|
|||||||
run: pnpm updater
|
run: pnpm updater
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
release-update-for-fixed-webview2:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Install Node
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: "22"
|
|
||||||
|
|
||||||
- uses: pnpm/action-setup@v4
|
|
||||||
name: Install pnpm
|
|
||||||
with:
|
|
||||||
run_install: false
|
|
||||||
|
|
||||||
- name: Pnpm install
|
|
||||||
run: pnpm i
|
|
||||||
|
|
||||||
- name: Release updater file
|
|
||||||
run: pnpm updater-fixed-webview2
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|||||||
6
.gitignore
vendored
@@ -7,8 +7,4 @@ dist-ssr
|
|||||||
update.json
|
update.json
|
||||||
scripts/_env.sh
|
scripts/_env.sh
|
||||||
.vscode
|
.vscode
|
||||||
.tool-versions
|
.tool-versions
|
||||||
.idea
|
|
||||||
.old
|
|
||||||
.eslintcache
|
|
||||||
target
|
|
||||||
@@ -1,44 +1,4 @@
|
|||||||
#!/bin/bash
|
#!/bin/sh
|
||||||
set -euo pipefail
|
. "$(dirname "$0")/_/husky.sh"
|
||||||
|
|
||||||
ROOT_DIR="$(git rev-parse --show-toplevel)"
|
pnpm pretty-quick --staged
|
||||||
cd "$ROOT_DIR"
|
|
||||||
|
|
||||||
if ! command -v pnpm >/dev/null 2>&1; then
|
|
||||||
echo "❌ pnpm is required for pre-commit checks."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "[pre-commit] Running lint-staged for JS/TS files..."
|
|
||||||
pnpm exec lint-staged
|
|
||||||
|
|
||||||
RUST_FILES="$(git diff --cached --name-only --diff-filter=ACMR | grep -E '^src-tauri/.*\.rs$' || true)"
|
|
||||||
if [ -n "$RUST_FILES" ]; then
|
|
||||||
echo "[pre-commit] Formatting Rust changes with cargo fmt..."
|
|
||||||
(
|
|
||||||
cd src-tauri
|
|
||||||
cargo fmt
|
|
||||||
)
|
|
||||||
while IFS= read -r file; do
|
|
||||||
[ -n "$file" ] && git add "$file"
|
|
||||||
done <<< "$RUST_FILES"
|
|
||||||
|
|
||||||
echo "[pre-commit] Linting Rust changes with cargo clippy..."
|
|
||||||
(
|
|
||||||
cd src-tauri
|
|
||||||
cargo clippy-all
|
|
||||||
if ! command -v clash-verge-logging-check >/dev/null 2>&1; then
|
|
||||||
echo "[pre-commit] Installing clash-verge-logging-check..."
|
|
||||||
cargo install --git https://github.com/clash-verge-rev/clash-verge-logging-check.git
|
|
||||||
fi
|
|
||||||
clash-verge-logging-check
|
|
||||||
)
|
|
||||||
fi
|
|
||||||
|
|
||||||
TS_FILES="$(git diff --cached --name-only --diff-filter=ACMR | grep -E '\.(ts|tsx)$' || true)"
|
|
||||||
if [ -n "$TS_FILES" ]; then
|
|
||||||
echo "[pre-commit] Running TypeScript type check..."
|
|
||||||
pnpm typecheck
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "[pre-commit] All checks completed successfully."
|
|
||||||
|
|||||||
@@ -1,43 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
remote_name="${1:-origin}"
|
|
||||||
remote_url="${2:-unknown}"
|
|
||||||
|
|
||||||
ROOT_DIR="$(git rev-parse --show-toplevel)"
|
|
||||||
cd "$ROOT_DIR"
|
|
||||||
|
|
||||||
if ! command -v pnpm >/dev/null 2>&1; then
|
|
||||||
echo "❌ pnpm is required for pre-push checks."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "[pre-push] Preparing to push to '$remote_name' ($remote_url). Running full validation..."
|
|
||||||
|
|
||||||
echo "[pre-push] Checking Prettier formatting..."
|
|
||||||
pnpm format:check
|
|
||||||
|
|
||||||
echo "[pre-push] Running ESLint..."
|
|
||||||
pnpm lint
|
|
||||||
|
|
||||||
echo "[pre-push] Running TypeScript type checking..."
|
|
||||||
pnpm typecheck
|
|
||||||
|
|
||||||
if command -v cargo >/dev/null 2>&1; then
|
|
||||||
echo "[pre-push] Verifying Rust formatting..."
|
|
||||||
(
|
|
||||||
cd src-tauri
|
|
||||||
cargo fmt --check
|
|
||||||
)
|
|
||||||
|
|
||||||
echo "[pre-push] Running cargo clippy..."
|
|
||||||
(
|
|
||||||
cd src-tauri
|
|
||||||
cargo clippy-all
|
|
||||||
)
|
|
||||||
else
|
|
||||||
echo "[pre-push] ⚠️ cargo not found; skipping Rust checks."
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "[pre-push] All checks passed."
|
|
||||||
exit 0
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
# README.md
|
|
||||||
# UPDATELOG.md
|
|
||||||
# CONTRIBUTING.md
|
|
||||||
|
|
||||||
pnpm-lock.yaml
|
|
||||||
|
|
||||||
src-tauri/target/
|
|
||||||
src-tauri/gen/
|
|
||||||
|
|
||||||
target
|
|
||||||
16
.prettierrc
@@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
"printWidth": 80,
|
|
||||||
"tabWidth": 2,
|
|
||||||
"useTabs": false,
|
|
||||||
"semi": true,
|
|
||||||
"singleQuote": false,
|
|
||||||
"jsxSingleQuote": false,
|
|
||||||
"trailingComma": "all",
|
|
||||||
"bracketSpacing": true,
|
|
||||||
"bracketSameLine": false,
|
|
||||||
"arrowParens": "always",
|
|
||||||
"proseWrap": "preserve",
|
|
||||||
"htmlWhitespaceSensitivity": "css",
|
|
||||||
"endOfLine": "auto",
|
|
||||||
"embeddedLanguageFormatting": "auto"
|
|
||||||
}
|
|
||||||
106
CONTRIBUTING.md
@@ -2,73 +2,40 @@
|
|||||||
|
|
||||||
Thank you for your interest in contributing to Clash Verge Rev! This document provides guidelines and instructions to help you set up your development environment and start contributing.
|
Thank you for your interest in contributing to Clash Verge Rev! This document provides guidelines and instructions to help you set up your development environment and start contributing.
|
||||||
|
|
||||||
## Internationalization (i18n)
|
|
||||||
|
|
||||||
We welcome translations and improvements to existing locales. Please follow the detailed guidelines in [CONTRIBUTING_i18n.md](docs/CONTRIBUTING_i18n.md) for instructions on extracting strings, file naming conventions, testing translations, and submitting translation PRs.
|
|
||||||
|
|
||||||
## Development Setup
|
## Development Setup
|
||||||
|
|
||||||
Before you start contributing to the project, you need to set up your development environment. Here are the steps you need to follow:
|
Before you start contributing to the project, you need to set up your development environment. Here are the steps you need to follow:
|
||||||
|
|
||||||
### Prerequisites
|
### Prerequisites
|
||||||
|
|
||||||
1. **Install Rust and Node.js**: Our project requires both Rust and Node.js. Please follow the instructions provided [here](https://tauri.app/start/prerequisites/) to install them on your system.
|
1. **Install Rust and Node.js**: Our project requires both Rust and Node.js. Please follow the instructions provided [here](https://tauri.app/v1/guides/getting-started/prerequisites) to install them on your system.
|
||||||
|
|
||||||
### Setup for Windows Users
|
### Setup for Windows Users
|
||||||
|
|
||||||
> [!NOTE]
|
|
||||||
> **If you are using a Windows ARM device, you additionally need to install [LLVM](https://github.com/llvm/llvm-project/releases) (including clang) and set the environment variable.**
|
|
||||||
>
|
|
||||||
> Because the `ring` crate is compiled based on `clang` under Windows ARM.
|
|
||||||
|
|
||||||
If you're a Windows user, you may need to perform some additional steps:
|
If you're a Windows user, you may need to perform some additional steps:
|
||||||
|
|
||||||
- Make sure to add Rust and Node.js to your system's PATH. This is usually done during the installation process, but you can verify and manually add them if necessary.
|
- Make sure to add Rust and Node.js to your system's PATH. This is usually done during the installation process, but you can verify and manually add them if necessary.
|
||||||
- The gnu `patch` tool should be installed
|
- The gnu `patch` tool should be installed
|
||||||
|
|
||||||
When you setup `Rust` environment, Only use toolchain with `Windows MSVC` , to change settings follow command:
|
### Install Node.js Packages
|
||||||
|
|
||||||
|
After installing Rust and Node.js, install the necessary Node.js packages:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
rustup target add x86_64-pc-windows-msvc
|
pnpm i
|
||||||
rustup set default-host x86_64-pc-windows-msvc
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Install Node.js Package
|
### Download the Clash Binary
|
||||||
|
|
||||||
After installing Rust and Node.js, install the necessary Node.js and Node Package Manager:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
npm install pnpm -g
|
|
||||||
```
|
|
||||||
|
|
||||||
### Install Dependencies
|
|
||||||
|
|
||||||
Install node packages
|
|
||||||
|
|
||||||
```shell
|
|
||||||
pnpm install
|
|
||||||
```
|
|
||||||
|
|
||||||
Install apt packages ONLY for Ubuntu
|
|
||||||
|
|
||||||
```shell
|
|
||||||
apt-get install -y libxslt1.1 libwebkit2gtk-4.1-dev libayatana-appindicator3-dev librsvg2-dev patchelf
|
|
||||||
```
|
|
||||||
|
|
||||||
### Download the Mihomo Core Binary
|
|
||||||
|
|
||||||
You have two options for downloading the clash binary:
|
You have two options for downloading the clash binary:
|
||||||
|
|
||||||
- Automatically download it via the provided script:
|
- Automatically download it via the provided script:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
pnpm run prebuild
|
pnpm run check
|
||||||
# Use '--force' or '-f' to update both the Mihomo core version
|
# Use '--force' to force update to the latest version
|
||||||
# and the Clash Verge Rev service version to the latest available.
|
# pnpm run check --force
|
||||||
pnpm run prebuild --force
|
|
||||||
```
|
```
|
||||||
|
- Manually download it from the [Clash Meta release](https://github.com/MetaCubeX/Clash.Meta/releases). After downloading, rename the binary according to the [Tauri configuration](https://tauri.app/v1/api/config#bundleconfig.externalbin).
|
||||||
- Manually download it from the [Mihomo release](https://github.com/MetaCubeX/mihomo/releases). After downloading, rename the binary according to the [Tauri configuration](https://tauri.app/v1/api/config#bundleconfig.externalbin).
|
|
||||||
|
|
||||||
### Run the Development Server
|
### Run the Development Server
|
||||||
|
|
||||||
@@ -78,69 +45,18 @@ To run the development server, use the following command:
|
|||||||
pnpm dev
|
pnpm dev
|
||||||
# If an app instance already exists, use a different command
|
# If an app instance already exists, use a different command
|
||||||
pnpm dev:diff
|
pnpm dev:diff
|
||||||
# To using tauri built-in dev tool
|
|
||||||
pnpm dev:tauri
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Build the Project
|
### Build the Project
|
||||||
|
|
||||||
To build this project:
|
If you want to build the project, use:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
pnpm build
|
pnpm build
|
||||||
```
|
```
|
||||||
|
|
||||||
For a faster build, use the following command
|
|
||||||
|
|
||||||
```shell
|
|
||||||
pnpm build:fast
|
|
||||||
```
|
|
||||||
|
|
||||||
This uses Rust's fast-release profile which significantly reduces compilation time by disabling optimization and LTO. The resulting binary will be larger and less performant than the standard build, but it's useful for testing changes quickly.
|
|
||||||
|
|
||||||
The `Artifacts` will display in the `log` in the Terminal.
|
|
||||||
|
|
||||||
### Build clean
|
|
||||||
|
|
||||||
To clean rust build:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
pnpm clean
|
|
||||||
```
|
|
||||||
|
|
||||||
### Portable Version (Windows Only)
|
|
||||||
|
|
||||||
To package portable version after the build:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
pnpm portable
|
|
||||||
```
|
|
||||||
|
|
||||||
## Contributing Your Changes
|
## Contributing Your Changes
|
||||||
|
|
||||||
#### Before commit your changes
|
|
||||||
|
|
||||||
If you changed the rust code, it's recommanded to execute code style formatting and quailty checks.
|
|
||||||
|
|
||||||
1. Code quailty checks
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# For rust backend
|
|
||||||
$ clash-verge-rev: pnpm clippy
|
|
||||||
# For frontend (not yet).
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Code style formatting
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# For rust backend
|
|
||||||
$ clash-verge-rev: cd src-tauri
|
|
||||||
$ clash-verge-rev/src-tauri: cargo fmt
|
|
||||||
# For frontend
|
|
||||||
$ clash-verge-rev: pnpm format:check
|
|
||||||
$ clash-verge-rev: pnpm format
|
|
||||||
```
|
|
||||||
|
|
||||||
Once you have made your changes:
|
Once you have made your changes:
|
||||||
|
|
||||||
1. Fork the repository.
|
1. Fork the repository.
|
||||||
|
|||||||
68
README.md
@@ -1,5 +1,5 @@
|
|||||||
<h1 align="center">
|
<h1 align="center">
|
||||||
<img src="./src-tauri/icons/icon.png" alt="Clash" width="128" />
|
<img src="./src/assets/image/logo.png" alt="Clash" width="128" />
|
||||||
<br>
|
<br>
|
||||||
Continuation of <a href="https://github.com/zzzgydi/clash-verge">Clash Verge</a>
|
Continuation of <a href="https://github.com/zzzgydi/clash-verge">Clash Verge</a>
|
||||||
<br>
|
<br>
|
||||||
@@ -9,85 +9,47 @@
|
|||||||
A Clash Meta GUI based on <a href="https://github.com/tauri-apps/tauri">Tauri</a>.
|
A Clash Meta GUI based on <a href="https://github.com/tauri-apps/tauri">Tauri</a>.
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
<p align="center">
|
|
||||||
Languages:
|
|
||||||
<a href="./README.md">简体中文</a> ·
|
|
||||||
<a href="./docs/README_en.md">English</a> ·
|
|
||||||
<a href="./docs/README_es.md">Español</a> ·
|
|
||||||
<a href="./docs/README_ru.md">Русский</a> ·
|
|
||||||
<a href="./docs/README_ja.md">日本語</a>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
## Preview
|
## Preview
|
||||||
|
|
||||||
| Dark | Light |
|

|
||||||
| -------------------------------- | --------------------------------- |
|
|
||||||
|  |  |
|
|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
|
|
||||||
请到发布页面下载对应的安装包:[Release page](https://github.com/clash-verge-rev/clash-verge-rev/releases)<br>
|
请到发布页面下载对应的安装包:[Release page](https://github.com/clash-verge-rev/clash-verge-rev/releases)<br>
|
||||||
Go to the [Release page](https://github.com/clash-verge-rev/clash-verge-rev/releases) to download the corresponding installation package<br>
|
Go to the [release page](https://github.com/clash-verge-rev/clash-verge-rev/releases) to download the corresponding installation package<br>
|
||||||
Supports Windows (x64/x86), Linux (x64/arm64) and macOS 10.15+ (intel/apple).
|
Supports Windows (x64/x86), Linux (x64/arm64) and macOS 10.15+ (intel/apple).
|
||||||
|
|
||||||
#### 我应当怎样选择发行版
|
### 安装说明和常见问题,请到[文档页](https://clash-verge-rev.github.io/)查看:[Doc](https://clash-verge-rev.github.io/)
|
||||||
|
|
||||||
| 版本 | 特征 | 链接 |
|
|
||||||
| :---------- | :--------------------------------------- | :------------------------------------------------------------------------------------- |
|
|
||||||
| Stable | 正式版,高可靠性,适合日常使用。 | [Release](https://github.com/clash-verge-rev/clash-verge-rev/releases) |
|
|
||||||
| Alpha(废弃) | 测试发布流程。 | [Alpha](https://github.com/clash-verge-rev/clash-verge-rev/releases/tag/alpha) |
|
|
||||||
| AutoBuild | 滚动更新版,适合测试反馈,可能存在缺陷。 | [AutoBuild](https://github.com/clash-verge-rev/clash-verge-rev/releases/tag/autobuild) |
|
|
||||||
|
|
||||||
#### 安装说明和常见问题,请到 [文档页](https://clash-verge-rev.github.io/) 查看
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### TG 频道: [@clash_verge_rev](https://t.me/clash_verge_re)
|
### TG Group: [@clash_verge_rev](https://t.me/clash_verge_rev)
|
||||||
|
|
||||||
## Promotion
|
## Promotion
|
||||||
|
|
||||||
#### [狗狗加速 —— 技术流机场 Doggygo VPN](https://verge.dginv.click/#/register?code=oaxsAGo6)
|
[狗狗加速 —— 技术流机场 Doggygo VPN](https://狗狗加速.com)
|
||||||
|
|
||||||
- 高性能海外机场,免费试用,优惠套餐,解锁流媒体,全球首家支持 Hysteria 协议。
|
- 高性能海外机场,免费试用,优惠套餐,解锁流媒体,全球首家支持 Hysteria 协议。
|
||||||
- 使用 Clash Verge 专属邀请链接注册送 3 天,每天 1G 流量免费试用:[点此注册](https://verge.dginv.click/#/register?code=oaxsAGo6)
|
- 使用 Clash Verge 专属邀请链接注册送 3 天,每天 1G 流量免费试用:https://verge.狗狗加速.com/#/register?code=oaxsAGo6
|
||||||
- Clash Verge 专属 8 折优惠码: verge20 (仅有 500 份)
|
- Clash Verge 专属 8 折优惠码: verge20 (仅有 500 份)
|
||||||
- 优惠套餐每月仅需 15.8 元,160G 流量,年付 8 折
|
- 优惠套餐每月仅需 15.8 元,160G 流量,年付 8 折
|
||||||
- 海外团队,无跑路风险,高达 50% 返佣
|
- 海外团队,无跑路风险,高达 50% 返佣
|
||||||
- 集群负载均衡设计,高速专线(兼容老客户端),极低延迟,无视晚高峰,4K 秒开
|
- 集群负载均衡设计,高速专线(兼容老客户端),极低延迟,无视晚高峰,4K 秒开
|
||||||
- 全球首家 Hysteria 协议机场,现已上线更快的 `Hysteria2` 协议(Clash Verge 客户端最佳搭配)
|
- 全球首家 Hysteria 协议机场,现已上线更快的 `Hysteria2` 协议(Clash Verge 客户端最佳搭配)
|
||||||
- 解锁流媒体及 ChatGPT
|
- 解锁流媒体及 ChatGPT
|
||||||
- 官网:[https://狗狗加速.com](https://verge.dginv.click/#/register?code=oaxsAGo6)
|
- 官网:https://狗狗加速.com
|
||||||
|
|
||||||
#### 本项目的构建与发布环境由 [YXVM](https://yxvm.com/aff.php?aff=827) 独立服务器全力支持,
|
|
||||||
|
|
||||||
感谢提供 独享资源、高性能、高速网络 的强大后端环境。如果你觉得下载够快、使用够爽,那是因为我们用了好服务器!
|
|
||||||
|
|
||||||
🧩 YXVM 独立服务器优势:
|
|
||||||
|
|
||||||
- 🌎 优质网络,回程优化,下载快到飞起
|
|
||||||
- 🔧 物理机独享资源,非VPS可比,性能拉满
|
|
||||||
- 🧠 适合跑代理、搭建 WEB 站 CDN 站 、搞 CI/CD 或任何高负载应用
|
|
||||||
- 💡 支持即开即用,多机房选择,CN2 / IEPL 可选
|
|
||||||
- 📦 本项目使用配置已在售,欢迎同款入手!
|
|
||||||
- 🎯 想要同款构建体验?[立即下单 YXVM 独立服务器!](https://yxvm.com/aff.php?aff=827)
|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- 基于性能强劲的 Rust 和 Tauri 2 框架
|
- Since the clash core has been removed. The project no longer maintains the clash core, but only the Clash Meta core.
|
||||||
- 内置[Clash.Meta(mihomo)](https://github.com/MetaCubeX/mihomo)内核,并支持切换 `Alpha` 版本内核。
|
- Profiles management and enhancement (by yaml and Javascript). [Doc](https://clash-verge-rev.github.io)
|
||||||
- 简洁美观的用户界面,支持自定义主题颜色、代理组/托盘图标以及 `CSS Injection`。
|
- Improved UI and supports custom theme color.
|
||||||
- 配置文件管理和增强(Merge 和 Script),配置文件语法提示。
|
- Built-in support [Clash.Meta(mihomo)](https://github.com/MetaCubeX/mihomo) core.
|
||||||
- 系统代理和守卫、`TUN(虚拟网卡)` 模式。
|
- System proxy setting and guard.
|
||||||
- 可视化节点和规则编辑
|
|
||||||
- WebDav 配置备份和同步
|
|
||||||
|
|
||||||
### FAQ
|
### FAQ
|
||||||
|
|
||||||
Refer to [Doc FAQ Page](https://clash-verge-rev.github.io/faq/windows.html)
|
Refer to [Doc FAQ Page](https://clash-verge-rev.github.io/faq/install/)
|
||||||
|
|
||||||
### Donation
|
|
||||||
|
|
||||||
[捐助Clash Verge Rev的开发](https://github.com/sponsors/clash-verge-rev)
|
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
@@ -97,7 +59,7 @@ To run the development server, execute the following commands after all prerequi
|
|||||||
|
|
||||||
```shell
|
```shell
|
||||||
pnpm i
|
pnpm i
|
||||||
pnpm run prebuild
|
pnpm run check
|
||||||
pnpm dev
|
pnpm dev
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
1096
UPDATELOG.md
@@ -1,4 +0,0 @@
|
|||||||
files:
|
|
||||||
- source: /src/locales/en.json
|
|
||||||
translation: /src/locales
|
|
||||||
multilingual: 1
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
# CONTRIBUTING — i18n
|
|
||||||
|
|
||||||
Thank you for considering contributing to our localization work — your help is appreciated.
|
|
||||||
|
|
||||||
Quick overview
|
|
||||||
|
|
||||||
- cvr-i18 is a CLI that helps manage simple top-level JSON locale files:
|
|
||||||
- Detect duplicated top-level keys
|
|
||||||
- Find keys missing versus a base file (default: en.json)
|
|
||||||
- Export missing entries for translators
|
|
||||||
- Reorder keys to match the base file for predictable diffs
|
|
||||||
- Operate on a directory or a single file
|
|
||||||
|
|
||||||
Get the CLI (No binary provided yet)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git clone https://github.com/clash-verge-rev/clash-verge-rev-i18n-cli
|
|
||||||
cd clash-verge-rev-i18n-cli
|
|
||||||
cargo install --path .
|
|
||||||
# or
|
|
||||||
cargo install --git https://github.com/clash-verge-rev/clash-verge-rev-i18n-cli
|
|
||||||
```
|
|
||||||
|
|
||||||
Common commands
|
|
||||||
|
|
||||||
- Show help: `cvr-i18`
|
|
||||||
- Directory (auto-detects `./locales` or `./src/locales`): `cvr-i18 -d /path/to/locales`
|
|
||||||
- Check duplicates: `cvr-i18 -k`
|
|
||||||
- Check missing keys: `cvr-i18 -m`
|
|
||||||
- Export missing keys: `cvr-i18 -m -e ./exports`
|
|
||||||
- Sort keys to base file: `cvr-i18 -s`
|
|
||||||
- Use a base file: `cvr-i18 -b base.json`
|
|
||||||
- Single file: `cvr-i18 -f locales/zh.json`
|
|
||||||
|
|
||||||
Options (short)
|
|
||||||
|
|
||||||
- `-d, --directory <DIR>`
|
|
||||||
- `-f, --file <FILE>`
|
|
||||||
- `-k, --duplicated-key`
|
|
||||||
- `-m, --missing-key`
|
|
||||||
- `-e, --export <DIR>`
|
|
||||||
- `-s, --sort`
|
|
||||||
- `-b, --base <FILE>`
|
|
||||||
|
|
||||||
Exit codes
|
|
||||||
|
|
||||||
- `0` — success (no issues)
|
|
||||||
- `1` — issues found (duplicates/missing)
|
|
||||||
- `2` — error (IO/parse/runtime)
|
|
||||||
|
|
||||||
How to contribute (recommended steps)
|
|
||||||
|
|
||||||
- Start small: fix typos, improve phrasing, or refine tone and consistency.
|
|
||||||
- Run the CLI against your locale files to detect duplicates or missing keys.
|
|
||||||
- Export starter JSONs for translators with `-m -e <DIR>`.
|
|
||||||
- Prefer incremental PRs or draft PRs; leave a comment on the issue if you want guidance.
|
|
||||||
- Open an issue to report missing strings, UI context, or localization bugs.
|
|
||||||
- Add or improve docs and tests to make future contributions easier.
|
|
||||||
|
|
||||||
PR checklist
|
|
||||||
|
|
||||||
- Keep JSON files UTF-8 encoded.
|
|
||||||
- Follow the repo’s locale file structure and naming conventions.
|
|
||||||
- Reorder keys to match the base file (`-s`) for minimal diffs.
|
|
||||||
- Test translations in a local dev build before opening a PR.
|
|
||||||
- Reference related issues and explain any context for translations or changes.
|
|
||||||
|
|
||||||
Notes
|
|
||||||
|
|
||||||
- The tool expects simple top-level JSON key/value maps.
|
|
||||||
- Exported JSONs are starter files for translators (fill in values, keep keys).
|
|
||||||
- Sorting keeps diffs consistent and reviewable.
|
|
||||||
|
|
||||||
Repository
|
|
||||||
https://github.com/clash-verge-rev/clash-verge-rev-i18n-cli
|
|
||||||
|
|
||||||
## Feedback & Contributions
|
|
||||||
|
|
||||||
- For tool usage issues or feedback: please open an Issue in the [repository](https://github.com/clash-verge-rev/clash-verge-rev-i18n-cli) so it can be tracked and addressed.
|
|
||||||
- For localization contributions (translations, fixes, context notes, etc.): submit a PR or Issue in this repository and include examples, context, and testing instructions when possible.
|
|
||||||
- If you need help or a review, leave a comment on your submission requesting assistance.
|
|
||||||
@@ -1,124 +0,0 @@
|
|||||||
<h1 align="center">
|
|
||||||
<img src="../src-tauri/icons/icon.png" alt="Clash" width="128" />
|
|
||||||
<br>
|
|
||||||
Continuation of <a href="https://github.com/zzzgydi/clash-verge">Clash Verge</a>
|
|
||||||
<br>
|
|
||||||
</h1>
|
|
||||||
|
|
||||||
<h3 align="center">
|
|
||||||
A Clash Meta GUI built with <a href="https://github.com/tauri-apps/tauri">Tauri</a>.
|
|
||||||
</h3>
|
|
||||||
|
|
||||||
<p align="center">
|
|
||||||
Languages:
|
|
||||||
<a href="../README.md">简体中文</a> ·
|
|
||||||
<a href="./README_en.md">English</a> ·
|
|
||||||
<a href="./README_es.md">Español</a> ·
|
|
||||||
<a href="./README_ru.md">Русский</a> ·
|
|
||||||
<a href="./README_ja.md">日本語</a>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
## Preview
|
|
||||||
|
|
||||||
| Dark | Light |
|
|
||||||
| ----------------------------------- | ------------------------------------- |
|
|
||||||
|  |  |
|
|
||||||
|
|
||||||
## Install
|
|
||||||
|
|
||||||
Visit the [Release page](https://github.com/clash-verge-rev/clash-verge-rev/releases) to download the installer that matches your platform.<br>
|
|
||||||
We provide packages for Windows (x64/x86), Linux (x64/arm64), and macOS 10.15+ (Intel/Apple).
|
|
||||||
|
|
||||||
#### Choosing a Release Channel
|
|
||||||
|
|
||||||
| Channel | Description | Link |
|
|
||||||
| :---------- | :-------------------------------------------------------------------- | :------------------------------------------------------------------------------------- |
|
|
||||||
| Stable | Official builds with high reliability, ideal for daily use. | [Release](https://github.com/clash-verge-rev/clash-verge-rev/releases) |
|
|
||||||
| Alpha (EOL) | Legacy builds used to validate the publish pipeline. | [Alpha](https://github.com/clash-verge-rev/clash-verge-rev/releases/tag/alpha) |
|
|
||||||
| AutoBuild | Rolling builds for testing and feedback. Expect experimental changes. | [AutoBuild](https://github.com/clash-verge-rev/clash-verge-rev/releases/tag/autobuild) |
|
|
||||||
|
|
||||||
#### Installation Guides & FAQ
|
|
||||||
|
|
||||||
Read the [project documentation](https://clash-verge-rev.github.io/) for install steps, troubleshooting, and frequently asked questions.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Telegram Channel
|
|
||||||
|
|
||||||
Join [@clash_verge_rev](https://t.me/clash_verge_re) for update announcements.
|
|
||||||
|
|
||||||
## Promotion
|
|
||||||
|
|
||||||
#### [Doggygo VPN — Performance-oriented global accelerator](https://verge.dginv.click/#/register?code=oaxsAGo6)
|
|
||||||
|
|
||||||
- High-performance overseas network service with free trials, discounted plans, streaming unlocks, and first-class Hysteria protocol support.
|
|
||||||
- Register through the exclusive Clash Verge link to get a 3-day trial with 1 GB of traffic per day: [Sign up](https://verge.dginv.click/#/register?code=oaxsAGo6)
|
|
||||||
- Exclusive 20% off coupon for Clash Verge users: `verge20` (limited to 500 uses)
|
|
||||||
- Discounted bundle from ¥15.8 per month for 160 GB, plus an additional 20% off for yearly billing
|
|
||||||
- Operated by an overseas team with reliable service and up to 50% revenue share
|
|
||||||
- Load-balanced clusters with high-speed dedicated routes (compatible with legacy clients), exceptionally low latency, smooth 4K playback
|
|
||||||
- First global provider to support the `Hysteria2` protocol—perfect fit for the Clash Verge client
|
|
||||||
- Supports streaming services and ChatGPT access
|
|
||||||
- Official site: [https://狗狗加速.com](https://verge.dginv.click/#/register?code=oaxsAGo6)
|
|
||||||
|
|
||||||
#### Build Infrastructure Sponsor — [YXVM Dedicated Servers](https://yxvm.com/aff.php?aff=827)
|
|
||||||
|
|
||||||
Our builds and releases run on YXVM dedicated servers that deliver premium resources, strong performance, and high-speed networking. If downloads feel fast and usage feels snappy, it is thanks to robust hardware.
|
|
||||||
|
|
||||||
🧩 Highlights of YXVM Dedicated Servers:
|
|
||||||
|
|
||||||
- 🌎 Optimized global routes for dramatically faster downloads
|
|
||||||
- 🔧 Bare-metal resources instead of shared VPS capacity for maximum performance
|
|
||||||
- 🧠 Great for proxy workloads, hosting web/CDN services, CI/CD pipelines, or any high-load tasks
|
|
||||||
- 💡 Ready to use instantly with multiple datacenter options, including CN2 and IEPL
|
|
||||||
- 📦 The configuration used by this project is on sale—feel free to get the same setup
|
|
||||||
- 🎯 Want the same build environment? [Order a YXVM server today](https://yxvm.com/aff.php?aff=827)
|
|
||||||
|
|
||||||
## Features
|
|
||||||
|
|
||||||
- Built on high-performance Rust with the Tauri 2 framework
|
|
||||||
- Ships with the embedded [Clash.Meta (mihomo)](https://github.com/MetaCubeX/mihomo) core and supports switching to the `Alpha` channel
|
|
||||||
- Clean, polished UI with theme color controls, proxy group/tray icons, and `CSS Injection`
|
|
||||||
- Enhanced profile management (Merge and Script helpers) with configuration syntax hints
|
|
||||||
- System proxy controls, guard mode, and `TUN` (virtual network adapter) support
|
|
||||||
- Visual editors for nodes and rules
|
|
||||||
- WebDAV-based backup and sync for configurations
|
|
||||||
|
|
||||||
### FAQ
|
|
||||||
|
|
||||||
See the [FAQ page](https://clash-verge-rev.github.io/faq/windows.html) for platform-specific guidance.
|
|
||||||
|
|
||||||
### Donation
|
|
||||||
|
|
||||||
[Support Clash Verge Rev development](https://github.com/sponsors/clash-verge-rev)
|
|
||||||
|
|
||||||
## Development
|
|
||||||
|
|
||||||
See [CONTRIBUTING.md](../CONTRIBUTING.md) for detailed contribution guidelines.
|
|
||||||
|
|
||||||
After installing all **Tauri** prerequisites, run the development shell with:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
pnpm i
|
|
||||||
pnpm run prebuild
|
|
||||||
pnpm dev
|
|
||||||
```
|
|
||||||
|
|
||||||
## Contributions
|
|
||||||
|
|
||||||
Issues and pull requests are welcome!
|
|
||||||
|
|
||||||
## Acknowledgement
|
|
||||||
|
|
||||||
Clash Verge Rev builds on or draws inspiration from these projects:
|
|
||||||
|
|
||||||
- [zzzgydi/clash-verge](https://github.com/zzzgydi/clash-verge): A Tauri-based Clash GUI for Windows, macOS, and Linux.
|
|
||||||
- [tauri-apps/tauri](https://github.com/tauri-apps/tauri): Build smaller, faster, more secure desktop apps with a web frontend.
|
|
||||||
- [Dreamacro/clash](https://github.com/Dreamacro/clash): A rule-based tunnel written in Go.
|
|
||||||
- [MetaCubeX/mihomo](https://github.com/MetaCubeX/mihomo): A rule-based tunnel written in Go.
|
|
||||||
- [Fndroid/clash_for_windows_pkg](https://github.com/Fndroid/clash_for_windows_pkg): A Clash GUI for Windows and macOS.
|
|
||||||
- [vitejs/vite](https://github.com/vitejs/vite): Next-generation frontend tooling with blazing-fast DX.
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
GPL-3.0 License. See the [license file](../LICENSE) for details.
|
|
||||||
@@ -1,124 +0,0 @@
|
|||||||
<h1 align="center">
|
|
||||||
<img src="../src-tauri/icons/icon.png" alt="Clash" width="128" />
|
|
||||||
<br>
|
|
||||||
Continuación de <a href="https://github.com/zzzgydi/clash-verge">Clash Verge</a>
|
|
||||||
<br>
|
|
||||||
</h1>
|
|
||||||
|
|
||||||
<h3 align="center">
|
|
||||||
Una interfaz gráfica para Clash Meta construida con <a href="https://github.com/tauri-apps/tauri">Tauri</a>.
|
|
||||||
</h3>
|
|
||||||
|
|
||||||
<p align="center">
|
|
||||||
Idiomas:
|
|
||||||
<a href="../README.md">简体中文</a> ·
|
|
||||||
<a href="./README_en.md">English</a> ·
|
|
||||||
<a href="./README_es.md">Español</a> ·
|
|
||||||
<a href="./README_ru.md">Русский</a> ·
|
|
||||||
<a href="./README_ja.md">日本語</a>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
## Vista previa
|
|
||||||
|
|
||||||
| Oscuro | Claro |
|
|
||||||
| ----------------------------------- | ----------------------------------- |
|
|
||||||
|  |  |
|
|
||||||
|
|
||||||
## Instalación
|
|
||||||
|
|
||||||
Visita la [página de lanzamientos](https://github.com/clash-verge-rev/clash-verge-rev/releases) y descarga el instalador que corresponda a tu plataforma.<br>
|
|
||||||
Ofrecemos paquetes para Windows (x64/x86), Linux (x64/arm64) y macOS 10.15+ (Intel/Apple).
|
|
||||||
|
|
||||||
#### Cómo elegir el canal de lanzamiento
|
|
||||||
|
|
||||||
| Canal | Descripción | Enlace |
|
|
||||||
| :---------- | :----------------------------------------------------------------------------- | :------------------------------------------------------------------------------------- |
|
|
||||||
| Stable | Compilaciones oficiales de alta fiabilidad; ideales para el uso diario. | [Release](https://github.com/clash-verge-rev/clash-verge-rev/releases) |
|
|
||||||
| Alpha (EOL) | Compilaciones heredadas usadas para validar el flujo de publicación. | [Alpha](https://github.com/clash-verge-rev/clash-verge-rev/releases/tag/alpha) |
|
|
||||||
| AutoBuild | Compilaciones continuas para pruebas y retroalimentación. Espera cambios beta. | [AutoBuild](https://github.com/clash-verge-rev/clash-verge-rev/releases/tag/autobuild) |
|
|
||||||
|
|
||||||
#### Guías de instalación y preguntas frecuentes
|
|
||||||
|
|
||||||
Consulta la [documentación del proyecto](https://clash-verge-rev.github.io/) para encontrar los pasos de instalación, solución de problemas y preguntas frecuentes.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Canal de Telegram
|
|
||||||
|
|
||||||
Únete a [@clash_verge_rev](https://t.me/clash_verge_re) para enterarte de las novedades.
|
|
||||||
|
|
||||||
## Promociones
|
|
||||||
|
|
||||||
#### [Doggygo VPN — Acelerador global orientado al rendimiento](https://verge.dginv.click/#/register?code=oaxsAGo6)
|
|
||||||
|
|
||||||
- Servicio internacional de alto rendimiento con prueba gratuita, planes con descuento, desbloqueo de streaming y soporte de protocolo Hysteria de primera clase.
|
|
||||||
- Regístrate mediante el enlace exclusivo de Clash Verge y obtén una prueba de 3 días con 1 GB de tráfico diario: [Regístrate](https://verge.dginv.click/#/register?code=oaxsAGo6)
|
|
||||||
- Cupón exclusivo de 20% de descuento para usuarios de Clash Verge: `verge20` (limitado a 500 usos)
|
|
||||||
- Plan promocional desde ¥15.8 al mes con 160 GB, más 20% de descuento adicional por pago anual
|
|
||||||
- Equipo ubicado en el extranjero para un servicio confiable, con hasta 50% de comisión compartida
|
|
||||||
- Clústeres balanceados con rutas dedicadas de alta velocidad (compatibles con clientes antiguos), latencia extremadamente baja, reproducción 4K sin interrupciones
|
|
||||||
- Primer proveedor global que soporta el protocolo `Hysteria2`, ideal para el cliente Clash Verge
|
|
||||||
- Desbloquea servicios de streaming y acceso a ChatGPT
|
|
||||||
- Sitio oficial: [https://狗狗加速.com](https://verge.dginv.click/#/register?code=oaxsAGo6)
|
|
||||||
|
|
||||||
#### Patrocinador de la infraestructura de compilación — [Servidores dedicados YXVM](https://yxvm.com/aff.php?aff=827)
|
|
||||||
|
|
||||||
Las compilaciones y lanzamientos del proyecto se ejecutan en servidores dedicados de YXVM, que proporcionan recursos premium, alto rendimiento y redes de alta velocidad. Si las descargas son rápidas y el uso es fluido, es gracias a este hardware robusto.
|
|
||||||
|
|
||||||
🧩 Ventajas de los servidores dedicados YXVM:
|
|
||||||
|
|
||||||
- 🌎 Rutas globales optimizadas para descargas significativamente más rápidas
|
|
||||||
- 🔧 Recursos bare-metal, en lugar de VPS compartidos, para obtener el máximo rendimiento
|
|
||||||
- 🧠 Ideales para proxys, alojamiento de sitios web/CDN, pipelines de CI/CD o cualquier carga elevada
|
|
||||||
- 💡 Listos para usar al instante, con múltiples centros de datos disponibles (incluidos CN2 e IEPL)
|
|
||||||
- 📦 La misma configuración utilizada por este proyecto está disponible para su compra
|
|
||||||
- 🎯 ¿Quieres el mismo entorno de compilación? [Solicita un servidor YXVM hoy](https://yxvm.com/aff.php?aff=827)
|
|
||||||
|
|
||||||
## Funciones
|
|
||||||
|
|
||||||
- Basado en Rust de alto rendimiento y en el framework Tauri 2
|
|
||||||
- Incluye el núcleo integrado [Clash.Meta (mihomo)](https://github.com/MetaCubeX/mihomo) y permite cambiar al canal `Alpha`
|
|
||||||
- Interfaz limpia y elegante con controles de color de tema, iconos de grupos proxy/bandeja y `CSS Injection`
|
|
||||||
- Gestión avanzada de perfiles (herramientas Merge y Script) con sugerencias de sintaxis para configuraciones
|
|
||||||
- Control del proxy del sistema, modo guardián y soporte para `TUN` (adaptador de red virtual)
|
|
||||||
- Editores visuales para nodos y reglas
|
|
||||||
- Copias de seguridad y sincronización mediante WebDAV
|
|
||||||
|
|
||||||
### Preguntas frecuentes
|
|
||||||
|
|
||||||
Visita la [página de FAQ](https://clash-verge-rev.github.io/faq/windows.html) para obtener instrucciones específicas por plataforma.
|
|
||||||
|
|
||||||
### Donaciones
|
|
||||||
|
|
||||||
[Apoya el desarrollo de Clash Verge Rev](https://github.com/sponsors/clash-verge-rev)
|
|
||||||
|
|
||||||
## Desarrollo
|
|
||||||
|
|
||||||
Consulta [CONTRIBUTING.md](../CONTRIBUTING.md) para conocer las pautas de contribución.
|
|
||||||
|
|
||||||
Después de instalar todos los requisitos de **Tauri**, ejecuta el entorno de desarrollo con:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
pnpm i
|
|
||||||
pnpm run prebuild
|
|
||||||
pnpm dev
|
|
||||||
```
|
|
||||||
|
|
||||||
## Contribuciones
|
|
||||||
|
|
||||||
Se agradecen los issues y pull requests.
|
|
||||||
|
|
||||||
## Agradecimientos
|
|
||||||
|
|
||||||
Clash Verge Rev se basa en, o se inspira en, los siguientes proyectos:
|
|
||||||
|
|
||||||
- [zzzgydi/clash-verge](https://github.com/zzzgydi/clash-verge): Interfaz gráfica para Clash basada en Tauri. Compatible con Windows, macOS y Linux.
|
|
||||||
- [tauri-apps/tauri](https://github.com/tauri-apps/tauri): Construye aplicaciones de escritorio más pequeñas, rápidas y seguras con un frontend web.
|
|
||||||
- [Dreamacro/clash](https://github.com/Dreamacro/clash): Túnel basado en reglas escrito en Go.
|
|
||||||
- [MetaCubeX/mihomo](https://github.com/MetaCubeX/mihomo): Túnel basado en reglas escrito en Go.
|
|
||||||
- [Fndroid/clash_for_windows_pkg](https://github.com/Fndroid/clash_for_windows_pkg): Interfaz de Clash para Windows y macOS.
|
|
||||||
- [vitejs/vite](https://github.com/vitejs/vite): Herramientas de frontend de nueva generación con una experiencia rapidísima.
|
|
||||||
|
|
||||||
## Licencia
|
|
||||||
|
|
||||||
Licencia GPL-3.0. Consulta el [archivo de licencia](../LICENSE) para más detalles.
|
|
||||||
@@ -1,124 +0,0 @@
|
|||||||
<h1 align="center">
|
|
||||||
<img src="../src-tauri/icons/icon.png" alt="Clash" width="128" />
|
|
||||||
<br>
|
|
||||||
<a href="https://github.com/zzzgydi/clash-verge">Clash Verge</a> の継続プロジェクト
|
|
||||||
<br>
|
|
||||||
</h1>
|
|
||||||
|
|
||||||
<h3 align="center">
|
|
||||||
<a href="https://github.com/tauri-apps/tauri">Tauri</a> で構築された Clash Meta GUI。
|
|
||||||
</h3>
|
|
||||||
|
|
||||||
<p align="center">
|
|
||||||
言語:
|
|
||||||
<a href="../README.md">简体中文</a> ·
|
|
||||||
<a href="./README_en.md">English</a> ·
|
|
||||||
<a href="./README_es.md">Español</a> ·
|
|
||||||
<a href="./README_ru.md">Русский</a> ·
|
|
||||||
<a href="./README_ja.md">日本語</a>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
## プレビュー
|
|
||||||
|
|
||||||
| ダーク | ライト |
|
|
||||||
| --------------------------------------- | ---------------------------------------- |
|
|
||||||
|  |  |
|
|
||||||
|
|
||||||
## インストール
|
|
||||||
|
|
||||||
[リリースページ](https://github.com/clash-verge-rev/clash-verge-rev/releases) から、ご利用のプラットフォームに対応したインストーラーをダウンロードしてください。<br>
|
|
||||||
Windows (x64/x86)、Linux (x64/arm64)、macOS 10.15+ (Intel/Apple) をサポートしています。
|
|
||||||
|
|
||||||
#### リリースチャンネルの選び方
|
|
||||||
|
|
||||||
| チャンネル | 説明 | リンク |
|
|
||||||
| :---------- | :--------------------------------------------------------------- | :------------------------------------------------------------------------------------- |
|
|
||||||
| Stable | 安定版。信頼性が高く、日常利用に最適です。 | [Release](https://github.com/clash-verge-rev/clash-verge-rev/releases) |
|
|
||||||
| Alpha (EOL) | 公開フローの検証に使用した旧テスト版。 | [Alpha](https://github.com/clash-verge-rev/clash-verge-rev/releases/tag/alpha) |
|
|
||||||
| AutoBuild | 継続的に更新されるテスト版。フィードバックや新機能検証向けです。 | [AutoBuild](https://github.com/clash-verge-rev/clash-verge-rev/releases/tag/autobuild) |
|
|
||||||
|
|
||||||
#### インストール手順と FAQ
|
|
||||||
|
|
||||||
詳しい導入手順やトラブルシュートは [ドキュメントサイト](https://clash-verge-rev.github.io/) を参照してください。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Telegram チャンネル
|
|
||||||
|
|
||||||
更新情報は [@clash_verge_rev](https://t.me/clash_verge_re) をフォローしてください。
|
|
||||||
|
|
||||||
## プロモーション
|
|
||||||
|
|
||||||
#### [Doggygo VPN — 高性能グローバルアクセラレータ](https://verge.dginv.click/#/register?code=oaxsAGo6)
|
|
||||||
|
|
||||||
- 無料トライアル、割引プラン、ストリーミング解放、世界初の Hysteria プロトコル対応を備えた高性能海外ネットワークサービス。
|
|
||||||
- Clash Verge 専用リンクから登録すると、3 日間・1 日 1 GB の無料体験が利用できます。 [登録はこちら](https://verge.dginv.click/#/register?code=oaxsAGo6)
|
|
||||||
- Clash Verge 利用者限定 20% オフクーポン: `verge20`(先着 500 名)
|
|
||||||
- 月額 15.8 元で 160 GB を利用できるプラン、年額契約ならさらに 20% オフ
|
|
||||||
- 海外チーム運営による高信頼サービス、収益シェアは最大 50%
|
|
||||||
- 負荷分散クラスタと高速専用回線(旧クライアント互換)、極低レイテンシで 4K も快適
|
|
||||||
- 世界初の `Hysteria2` プロトコル対応。Clash Verge クライアントとの相性抜群
|
|
||||||
- ストリーミングおよび ChatGPT の利用にも対応
|
|
||||||
- 公式サイト: [https://狗狗加速.com](https://verge.dginv.click/#/register?code=oaxsAGo6)
|
|
||||||
|
|
||||||
#### ビルド環境スポンサー — [YXVM 専用サーバー](https://yxvm.com/aff.php?aff=827)
|
|
||||||
|
|
||||||
本プロジェクトのビルドとリリースは、YXVM の専用サーバーによって支えられています。高速ダウンロードや快適な操作性は、強力なハードウェアがあってこそです。
|
|
||||||
|
|
||||||
🧩 YXVM 専用サーバーの特長:
|
|
||||||
|
|
||||||
- 🌎 最適化されたグローバル回線で圧倒的なダウンロード速度
|
|
||||||
- 🔧 VPS とは異なるベアメタル資源で最高性能を発揮
|
|
||||||
- 🧠 プロキシ運用、Web/CDN ホスティング、CI/CD など高負荷ワークロードに最適
|
|
||||||
- 💡 複数データセンターから即時利用可能。CN2 や IEPL も選択可
|
|
||||||
- 📦 本プロジェクトが使用している構成も販売中。同じ環境を入手できます
|
|
||||||
- 🎯 同じビルド体験をしたい方は [今すぐ YXVM サーバーを注文](https://yxvm.com/aff.php?aff=827)
|
|
||||||
|
|
||||||
## 機能
|
|
||||||
|
|
||||||
- 高性能な Rust と Tauri 2 フレームワークに基づくデスクトップアプリ
|
|
||||||
- 組み込みの [Clash.Meta (mihomo)](https://github.com/MetaCubeX/mihomo) コアを搭載し、`Alpha` チャンネルへの切り替えも可能
|
|
||||||
- テーマカラーやプロキシグループ/トレイアイコン、`CSS Injection` をカスタマイズできる洗練された UI
|
|
||||||
- 設定ファイルの管理および拡張(Merge・Script 支援)、構成シンタックスヒントを提供
|
|
||||||
- システムプロキシ制御、ガード機能、`TUN`(仮想ネットワークアダプタ)モード
|
|
||||||
- ノードとルールのビジュアルエディタ
|
|
||||||
- WebDAV による設定のバックアップと同期
|
|
||||||
|
|
||||||
### FAQ
|
|
||||||
|
|
||||||
プラットフォーム別の案内は [FAQ ページ](https://clash-verge-rev.github.io/faq/windows.html) を参照してください。
|
|
||||||
|
|
||||||
### 寄付
|
|
||||||
|
|
||||||
[Clash Verge Rev の開発を支援する](https://github.com/sponsors/clash-verge-rev)
|
|
||||||
|
|
||||||
## 開発
|
|
||||||
|
|
||||||
詳細な貢献ガイドは [CONTRIBUTING.md](../CONTRIBUTING.md) をご覧ください。
|
|
||||||
|
|
||||||
**Tauri** の前提条件を整えたら、以下のコマンドで開発サーバーを起動できます:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
pnpm i
|
|
||||||
pnpm run prebuild
|
|
||||||
pnpm dev
|
|
||||||
```
|
|
||||||
|
|
||||||
## コントリビューション
|
|
||||||
|
|
||||||
Issue や Pull Request を歓迎します。
|
|
||||||
|
|
||||||
## 謝辞
|
|
||||||
|
|
||||||
Clash Verge Rev は、以下のプロジェクトに影響を受けています。
|
|
||||||
|
|
||||||
- [zzzgydi/clash-verge](https://github.com/zzzgydi/clash-verge): Tauri ベースの Clash GUI。Windows / macOS / Linux に対応。
|
|
||||||
- [tauri-apps/tauri](https://github.com/tauri-apps/tauri): Web フロントエンドで小型・高速・安全なデスクトップアプリを構築するためのフレームワーク。
|
|
||||||
- [Dreamacro/clash](https://github.com/Dreamacro/clash): Go 製のルールベーストンネル。
|
|
||||||
- [MetaCubeX/mihomo](https://github.com/MetaCubeX/mihomo): Go 製のルールベーストンネル。
|
|
||||||
- [Fndroid/clash_for_windows_pkg](https://github.com/Fndroid/clash_for_windows_pkg): Windows / macOS 向けの Clash GUI。
|
|
||||||
- [vitejs/vite](https://github.com/vitejs/vite): 次世代のフロントエンドツール群。高速な開発体験を提供。
|
|
||||||
|
|
||||||
## ライセンス
|
|
||||||
|
|
||||||
GPL-3.0 ライセンス。詳細は [LICENSE](../LICENSE) を参照してください。
|
|
||||||
@@ -1,120 +0,0 @@
|
|||||||
<h1 align="center">
|
|
||||||
<img src="../src-tauri/icons/icon.png" alt="Clash" width="128" />
|
|
||||||
<br>
|
|
||||||
Continuation of <a href="https://github.com/zzzgydi/clash-verge">Clash Verge</a>
|
|
||||||
<br>
|
|
||||||
</h1>
|
|
||||||
|
|
||||||
<h3 align="center">
|
|
||||||
Clash Meta GUI базируется на <a href="https://github.com/tauri-apps/tauri">Tauri</a>.
|
|
||||||
</h3>
|
|
||||||
|
|
||||||
<p align="center">
|
|
||||||
Языки:
|
|
||||||
<a href="../README.md">简体中文</a> ·
|
|
||||||
<a href="./README_en.md">English</a> ·
|
|
||||||
<a href="./README_es.md">Español</a> ·
|
|
||||||
<a href="./README_ru.md">Русский</a> ·
|
|
||||||
<a href="./README_ja.md">日本語</a>
|
|
||||||
</p>
|
|
||||||
## Предпросмотр
|
|
||||||
|
|
||||||
| Тёмная тема | Светлая тема |
|
|
||||||
| ---------------------------------- | ------------------------------------ |
|
|
||||||
|  |  |
|
|
||||||
|
|
||||||
## Установка
|
|
||||||
|
|
||||||
Пожалуйста, перейдите на страницу релизов, чтобы скачать соответствующий установочный пакет: [Страница релизов](https://github.com/clash-verge-rev/clash-verge-rev/releases)<br>
|
|
||||||
Перейти на [Страницу релизов](https://github.com/clash-verge-rev/clash-verge-rev/releases) to download the corresponding installation package<br>
|
|
||||||
Поддержка Windows (x64/x86), Linux (x64/arm64) и macOS 10.15+ (intel/apple).
|
|
||||||
|
|
||||||
#### Как выбрать дистрибутив?
|
|
||||||
|
|
||||||
| Версия | Характеристики | Ссылка |
|
|
||||||
| :-------------------- | :------------------------------------------------------------------------------------------------------ | :------------------------------------------------------------------------------------- |
|
|
||||||
| Stable | Официальный релиз, высокая надежность, подходит для повседневного использования. | [Release](https://github.com/clash-verge-rev/clash-verge-rev/releases) |
|
|
||||||
| Alpha(неиспользуемый) | Тестирование процесса публикации. | [Alpha](https://github.com/clash-verge-rev/clash-verge-rev/releases/tag/alpha) |
|
|
||||||
| AutoBuild | Версия с постоянным обновлением, подходящая для тестирования и обратной связи. Может содержать дефекты. | [AutoBuild](https://github.com/clash-verge-rev/clash-verge-rev/releases/tag/autobuild) |
|
|
||||||
|
|
||||||
#### Инструкции по установке и ответы на часто задаваемые вопросы можно найти на [странице документации](https://clash-verge-rev.github.io/)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### TG канал: [@clash_verge_rev](https://t.me/clash_verge_re)
|
|
||||||
|
|
||||||
## Продвижение
|
|
||||||
|
|
||||||
#### [Doggygo VPN —— технический VPN-сервис (айрпорт)](https://verge.dginv.click/#/register?code=oaxsAGo6)
|
|
||||||
|
|
||||||
- Высокопроизводительный иностранный VPN-сервис (айрпорт) с бесплатным пробным периодом, выгодными тарифами, возможностью разблокировки потокового ТВ и первым в мире поддержкой протокола Hysteria.
|
|
||||||
- Зарегистрируйтесь по эксклюзивной ссылке Clash Verge и получите 3 дня бесплатного использования, 1 Гб трафика в день: [регистрация](https://verge.dginv.click/#/register?code=oaxsAGo6)
|
|
||||||
- Эксклюзивный промо-код на скидку 20% для Clash Verge: verge20 (только 500 штук)
|
|
||||||
- Специальный тарифный план всего за 15,8 юаней в месяц, 160 Гб трафика, скидка 20% при оплате за год
|
|
||||||
- Команда за рубежом, без риска побега, до 50% кэшбэка
|
|
||||||
- Архитектура с балансировкойнагрузки, высокоскоростная выделенная линия (совместима со старыми клиентами), чрезвычайно низкая задержка, без проблем в часы пик, 4K видео загружается мгновенно
|
|
||||||
- Первый в мире VPN-сервис (айрпорт), поддерживающий протокол Hysteria, теперь доступен более быстрый протокол `Hysteria2` (лучшее сочетание с клиентом Clash Verge)
|
|
||||||
- Разблокировка потоковые сервисы и ChatGPT
|
|
||||||
- Официальный сайт: [https://狗狗加速.com](https://verge.dginv.click/#/register?code=oaxsAGo6)
|
|
||||||
|
|
||||||
#### Среда сборки и публикации этого проекта полностью поддерживается выделенным сервером [YXVM](https://yxvm.com/aff.php?aff=827)
|
|
||||||
|
|
||||||
Благодарим вас за предоставление надежной бэкэнд-среды с эксклюзивными ресурсами, высокой производительностью и высокоскоростной сетью. Если вы считаете, что загрузка файлов происходит достаточно быстро, а использование — достаточно плавно, то это потому, что мы используем серверы высшего уровня!
|
|
||||||
|
|
||||||
🧩 Преимущества выделенного сервера YXVM:
|
|
||||||
|
|
||||||
- 🌎 Премиум-сеть с оптимизацией обратного пути для молниеносной скорости загрузки
|
|
||||||
- 🔧 Выделенные физические серверные ресурсы, не имеющие аналогов среди VPS, обеспечивающие максимальную производительность
|
|
||||||
- 🧠 Идеально подходит для прокси, хостинга веб-сайтов/CDN-сайтов, рабочих процессов CI/CD или любых приложений с высокой нагрузкой
|
|
||||||
- 💡 Поддержка использования сразу после включения, выбор нескольких дата-центров, CN2 / IEPL на выбор
|
|
||||||
- 📦 Эта конфигурация в настоящее время доступна для покупки — не стесняйтесь заказывать ту же модель!
|
|
||||||
- 🎯 Хотите попробовать такую же сборку? [Закажите выделенный сервер YXVM прямо сейчас!](https://yxvm.com/aff.php?aff=827)
|
|
||||||
|
|
||||||
## Фичи
|
|
||||||
|
|
||||||
- Основан на произвоительном Rust и фреймворке Tauri 2
|
|
||||||
- Имеет встроенное ядро [Clash.Meta(mihomo)](https://github.com/MetaCubeX/mihomo) и поддерживает переключение на ядро версии `Alpha`.
|
|
||||||
- Чистый и эстетичный пользовательский интерфейс, поддержка настраиваемых цветов темы, значков прокси-группы/системного трея и `CSS Injection`。
|
|
||||||
- Управление и расширение конфигурационными файлами (Merge и Script), подсказки по синтаксису конфигурационных файлов.
|
|
||||||
- Режим системного прокси и защита, `TUN (Tunneled Network Interface)` режим.
|
|
||||||
- Визуальное редактирование узлов и правил
|
|
||||||
- Резервное копирование и синхронизация конфигурации WebDAV
|
|
||||||
|
|
||||||
### FAQ
|
|
||||||
|
|
||||||
Смотрите [Страница часто задаваемых вопросов](https://clash-verge-rev.github.io/faq/windows.html)
|
|
||||||
|
|
||||||
### Донат
|
|
||||||
|
|
||||||
[Поддержите развитие Clash Verge Rev](https://github.com/sponsors/clash-verge-rev)
|
|
||||||
|
|
||||||
## Разработка
|
|
||||||
|
|
||||||
Дополнительные сведения смотреть в файле [CONTRIBUTING.md](../CONTRIBUTING.md).
|
|
||||||
|
|
||||||
Для запуска сервера разработки выполните следующие команды после установки всех необходимых компонентов для **Tauri**:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
pnpm i
|
|
||||||
pnpm run prebuild
|
|
||||||
pnpm dev
|
|
||||||
```
|
|
||||||
|
|
||||||
## Вклад
|
|
||||||
|
|
||||||
Обращения и запросы на PR приветствуются!
|
|
||||||
|
|
||||||
## Благодарность
|
|
||||||
|
|
||||||
Clash Verge rev был основан на этих проектах или вдохновлен ими, и так далее:
|
|
||||||
|
|
||||||
- [zzzgydi/clash-verge](https://github.com/zzzgydi/clash-verge): Графический интерфейс Clash на основе tauri. Поддерживает Windows, macOS и Linux.
|
|
||||||
- [tauri-apps/tauri](https://github.com/tauri-apps/tauri): Создавайте более компактные, быстрые и безопасные настольные приложения с веб-интерфейсом.
|
|
||||||
- [Dreamacro/clash](https://github.com/Dreamacro/clash): Правило-ориентированный туннель на Go.
|
|
||||||
- [MetaCubeX/mihomo](https://github.com/MetaCubeX/mihomo): Правило-ориентированный туннель на Go.
|
|
||||||
- [Fndroid/clash_for_windows_pkg](https://github.com/Fndroid/clash_for_windows_pkg): Графический интерфейс пользователя для Windows/macOS на основе Clash.
|
|
||||||
- [vitejs/vite](https://github.com/vitejs/vite): Инструменты нового поколения для фронтенда. Они быстрые!
|
|
||||||
|
|
||||||
## Лицензия
|
|
||||||
|
|
||||||
GPL-3.0 License. Подробности смотрите в [Лицензии](../LICENSE).
|
|
||||||
BIN
docs/preview.png
Normal file
|
After Width: | Height: | Size: 576 KiB |
|
Before Width: | Height: | Size: 314 KiB |
|
Before Width: | Height: | Size: 274 KiB |
135
eslint.config.ts
@@ -1,135 +0,0 @@
|
|||||||
import eslintJS from "@eslint/js";
|
|
||||||
import eslintReact from "@eslint-react/eslint-plugin";
|
|
||||||
import { defineConfig } from "eslint/config";
|
|
||||||
import configPrettier from "eslint-config-prettier";
|
|
||||||
import { createTypeScriptImportResolver } from "eslint-import-resolver-typescript";
|
|
||||||
import pluginImportX from "eslint-plugin-import-x";
|
|
||||||
import pluginPrettier from "eslint-plugin-prettier";
|
|
||||||
import pluginReactHooks from "eslint-plugin-react-hooks";
|
|
||||||
import pluginReactRefresh from "eslint-plugin-react-refresh";
|
|
||||||
import pluginUnusedImports from "eslint-plugin-unused-imports";
|
|
||||||
import globals from "globals";
|
|
||||||
import tseslint from "typescript-eslint";
|
|
||||||
|
|
||||||
export default defineConfig([
|
|
||||||
{
|
|
||||||
files: ["**/*.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"],
|
|
||||||
|
|
||||||
plugins: {
|
|
||||||
js: eslintJS,
|
|
||||||
"react-hooks": pluginReactHooks,
|
|
||||||
// @ts-expect-error -- https://github.com/un-ts/eslint-plugin-import-x/issues/421
|
|
||||||
"import-x": pluginImportX,
|
|
||||||
"react-refresh": pluginReactRefresh,
|
|
||||||
"unused-imports": pluginUnusedImports,
|
|
||||||
prettier: pluginPrettier,
|
|
||||||
},
|
|
||||||
|
|
||||||
extends: [
|
|
||||||
eslintJS.configs.recommended,
|
|
||||||
tseslint.configs.recommended,
|
|
||||||
eslintReact.configs["recommended-typescript"],
|
|
||||||
configPrettier,
|
|
||||||
],
|
|
||||||
|
|
||||||
languageOptions: {
|
|
||||||
globals: globals.browser,
|
|
||||||
},
|
|
||||||
|
|
||||||
settings: {
|
|
||||||
react: {
|
|
||||||
version: "detect",
|
|
||||||
},
|
|
||||||
"import-x/resolver-next": [
|
|
||||||
createTypeScriptImportResolver({
|
|
||||||
project: "./tsconfig.json",
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
},
|
|
||||||
|
|
||||||
rules: {
|
|
||||||
// React
|
|
||||||
"react-hooks/rules-of-hooks": "error",
|
|
||||||
"react-hooks/exhaustive-deps": "error",
|
|
||||||
"react-refresh/only-export-components": [
|
|
||||||
"warn",
|
|
||||||
{ allowConstantExport: true },
|
|
||||||
],
|
|
||||||
|
|
||||||
"@eslint-react/no-forward-ref": "off",
|
|
||||||
|
|
||||||
// React performance and production quality rules
|
|
||||||
"@eslint-react/no-array-index-key": "warn",
|
|
||||||
"@eslint-react/no-children-count": "error",
|
|
||||||
"@eslint-react/no-children-for-each": "error",
|
|
||||||
"@eslint-react/no-children-map": "error",
|
|
||||||
"@eslint-react/no-children-only": "error",
|
|
||||||
"@eslint-react/no-children-prop": "error",
|
|
||||||
"@eslint-react/no-children-to-array": "error",
|
|
||||||
"@eslint-react/no-class-component": "error",
|
|
||||||
"@eslint-react/no-clone-element": "error",
|
|
||||||
"@eslint-react/no-create-ref": "error",
|
|
||||||
"@eslint-react/no-default-props": "error",
|
|
||||||
"@eslint-react/no-direct-mutation-state": "error",
|
|
||||||
"@eslint-react/no-implicit-key": "error",
|
|
||||||
"@eslint-react/no-prop-types": "error",
|
|
||||||
"@eslint-react/no-set-state-in-component-did-mount": "error",
|
|
||||||
"@eslint-react/no-set-state-in-component-did-update": "error",
|
|
||||||
"@eslint-react/no-set-state-in-component-will-update": "error",
|
|
||||||
"@eslint-react/no-string-refs": "error",
|
|
||||||
"@eslint-react/no-unstable-context-value": "warn",
|
|
||||||
"@eslint-react/no-unstable-default-props": "warn",
|
|
||||||
"@eslint-react/no-unused-class-component-members": "error",
|
|
||||||
"@eslint-react/no-unused-state": "error",
|
|
||||||
"@eslint-react/no-useless-fragment": "warn",
|
|
||||||
"@eslint-react/prefer-destructuring-assignment": "warn",
|
|
||||||
|
|
||||||
// TypeScript
|
|
||||||
"@typescript-eslint/no-explicit-any": "off",
|
|
||||||
|
|
||||||
// unused-imports 代替 no-unused-vars
|
|
||||||
"@typescript-eslint/no-unused-vars": "off",
|
|
||||||
"unused-imports/no-unused-imports": "error",
|
|
||||||
"unused-imports/no-unused-vars": [
|
|
||||||
"warn",
|
|
||||||
{
|
|
||||||
vars: "all",
|
|
||||||
varsIgnorePattern: "^_",
|
|
||||||
args: "after-used",
|
|
||||||
argsIgnorePattern: "^_",
|
|
||||||
caughtErrorsIgnorePattern: "^ignore",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
|
|
||||||
// Import
|
|
||||||
"import-x/no-unresolved": "error",
|
|
||||||
"import-x/order": [
|
|
||||||
"warn",
|
|
||||||
{
|
|
||||||
groups: [
|
|
||||||
"builtin",
|
|
||||||
"external",
|
|
||||||
"internal",
|
|
||||||
"parent",
|
|
||||||
"sibling",
|
|
||||||
"index",
|
|
||||||
],
|
|
||||||
"newlines-between": "always",
|
|
||||||
alphabetize: {
|
|
||||||
order: "asc",
|
|
||||||
caseInsensitive: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
|
|
||||||
// 其他常见
|
|
||||||
"prefer-const": "warn",
|
|
||||||
"no-case-declarations": "error",
|
|
||||||
"no-fallthrough": "error",
|
|
||||||
"no-empty": ["warn", { allowEmptyCatch: true }],
|
|
||||||
|
|
||||||
// Prettier 格式化问题
|
|
||||||
"prettier/prettier": "warn",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
177
package.json
@@ -1,136 +1,83 @@
|
|||||||
{
|
{
|
||||||
"name": "clash-verge",
|
"name": "clash-verge",
|
||||||
"version": "2.4.3",
|
"version": "1.6.1",
|
||||||
"license": "GPL-3.0-only",
|
"license": "GPL-3.0-only",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"prepare": "husky || true",
|
"dev": "tauri dev",
|
||||||
"dev": "cross-env RUST_BACKTRACE=full tauri dev -f verge-dev",
|
"dev:diff": "tauri dev -f verge-dev",
|
||||||
"dev:diff": "cross-env RUST_BACKTRACE=full tauri dev -f verge-dev",
|
"build": "tauri build",
|
||||||
"dev:trace": "cross-env RUST_BACKTRACE=full RUSTFLAGS=\"--cfg tokio_unstable\" tauri dev -f verge-dev tokio-trace",
|
|
||||||
"dev:tauri": "cross-env RUST_BACKTRACE=full tauri dev -f tauri-dev",
|
|
||||||
"build": "cross-env NODE_OPTIONS='--max-old-space-size=4096' tauri build",
|
|
||||||
"build:fast": "cross-env NODE_OPTIONS='--max-old-space-size=4096' tauri build -- --profile fast-release",
|
|
||||||
"tauri": "tauri",
|
"tauri": "tauri",
|
||||||
"web:dev": "vite",
|
"web:dev": "vite",
|
||||||
"web:build": "tsc --noEmit && vite build",
|
"web:build": "tsc && vite build",
|
||||||
"web:serve": "vite preview",
|
"web:serve": "vite preview",
|
||||||
"prebuild": "node scripts/prebuild.mjs",
|
"check": "node scripts/check.mjs",
|
||||||
"updater": "node scripts/updater.mjs",
|
"updater": "node scripts/updater.mjs",
|
||||||
"updater-fixed-webview2": "node scripts/updater-fixed-webview2.mjs",
|
|
||||||
"portable": "node scripts/portable.mjs",
|
"portable": "node scripts/portable.mjs",
|
||||||
"portable-fixed-webview2": "node scripts/portable-fixed-webview2.mjs",
|
"prepare": "husky install"
|
||||||
"fix-alpha-version": "node scripts/fix-alpha_version.mjs",
|
|
||||||
"release-version": "node scripts/release-version.mjs",
|
|
||||||
"release:autobuild": "pnpm release-version autobuild",
|
|
||||||
"release:deploytest": "pnpm release-version deploytest",
|
|
||||||
"publish-version": "node scripts/publish-version.mjs",
|
|
||||||
"fmt": "cargo fmt --manifest-path ./src-tauri/Cargo.toml",
|
|
||||||
"clippy": "cargo clippy --all-features --all-targets --manifest-path ./src-tauri/Cargo.toml",
|
|
||||||
"lint": "eslint -c eslint.config.ts --max-warnings=0 --cache --cache-location .eslintcache src",
|
|
||||||
"lint:fix": "eslint -c eslint.config.ts --max-warnings=0 --cache --cache-location .eslintcache --fix src",
|
|
||||||
"format": "prettier --write .",
|
|
||||||
"format:check": "prettier --check .",
|
|
||||||
"typecheck": "tsc --noEmit",
|
|
||||||
"test": "vitest run"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@dnd-kit/core": "^6.3.1",
|
"@dnd-kit/core": "^6.1.0",
|
||||||
"@dnd-kit/sortable": "^10.0.0",
|
"@dnd-kit/sortable": "^8.0.0",
|
||||||
"@dnd-kit/utilities": "^3.2.2",
|
"@dnd-kit/utilities": "^3.2.2",
|
||||||
"@emotion/react": "^11.14.0",
|
"@emotion/react": "^11.11.4",
|
||||||
"@emotion/styled": "^11.14.1",
|
"@emotion/styled": "^11.11.5",
|
||||||
"@juggle/resize-observer": "^3.4.0",
|
"@juggle/resize-observer": "^3.4.0",
|
||||||
"@mui/icons-material": "^7.3.4",
|
"@mui/icons-material": "^5.15.15",
|
||||||
"@mui/lab": "7.0.0-beta.17",
|
"@mui/lab": "5.0.0-alpha.149",
|
||||||
"@mui/material": "^7.3.4",
|
"@mui/material": "^5.15.15",
|
||||||
"@mui/x-data-grid": "^8.16.0",
|
"@mui/x-data-grid": "^6.19.11",
|
||||||
"@tauri-apps/api": "2.9.0",
|
"@tauri-apps/api": "^1.5.4",
|
||||||
"@tauri-apps/plugin-clipboard-manager": "^2.3.2",
|
|
||||||
"@tauri-apps/plugin-dialog": "^2.4.2",
|
|
||||||
"@tauri-apps/plugin-fs": "^2.4.4",
|
|
||||||
"@tauri-apps/plugin-http": "~2.5.4",
|
|
||||||
"@tauri-apps/plugin-process": "^2.3.1",
|
|
||||||
"@tauri-apps/plugin-shell": "2.3.3",
|
|
||||||
"@tauri-apps/plugin-updater": "2.9.0",
|
|
||||||
"@types/json-schema": "^7.0.15",
|
"@types/json-schema": "^7.0.15",
|
||||||
"ahooks": "^3.9.6",
|
"ahooks": "^3.7.11",
|
||||||
"axios": "^1.13.1",
|
"axios": "^1.6.8",
|
||||||
"dayjs": "1.11.19",
|
"dayjs": "1.11.5",
|
||||||
"foxact": "^0.2.49",
|
"i18next": "^23.11.2",
|
||||||
"i18next": "^25.6.0",
|
|
||||||
"js-yaml": "^4.1.0",
|
|
||||||
"json-schema": "^0.4.0",
|
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"monaco-editor": "^0.54.0",
|
"meta-json-schema": "1.18.4-beta2",
|
||||||
"monaco-yaml": "^5.4.0",
|
"monaco-editor": "^0.47.0",
|
||||||
"nanoid": "^5.1.6",
|
"monaco-yaml": "^5.1.1",
|
||||||
"react": "19.2.0",
|
"nanoid": "^5.0.7",
|
||||||
"react-dom": "19.2.0",
|
"react": "^18.3.1",
|
||||||
"react-error-boundary": "6.0.0",
|
"react-dom": "^18.3.1",
|
||||||
"react-hook-form": "^7.66.0",
|
"react-error-boundary": "^3.1.4",
|
||||||
"react-i18next": "16.2.3",
|
"react-hook-form": "^7.51.3",
|
||||||
"react-markdown": "10.1.0",
|
"react-i18next": "^13.5.0",
|
||||||
"react-monaco-editor": "0.59.0",
|
"react-markdown": "^9.0.1",
|
||||||
"react-router": "^7.9.5",
|
"react-router-dom": "^6.23.0",
|
||||||
"react-virtuoso": "^4.14.1",
|
"react-transition-group": "^4.4.5",
|
||||||
"swr": "^2.3.6",
|
"react-virtuoso": "^4.7.10",
|
||||||
"tauri-plugin-mihomo-api": "git+https://github.com/clash-verge-rev/tauri-plugin-mihomo",
|
"recoil": "^0.7.7",
|
||||||
"types-pac": "^1.0.3"
|
"swr": "^1.3.0",
|
||||||
|
"tar": "^6.2.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@actions/github": "^6.0.1",
|
"@actions/github": "^5.1.1",
|
||||||
"@eslint-react/eslint-plugin": "^2.2.4",
|
"@tauri-apps/cli": "^1.5.12",
|
||||||
"@eslint/js": "^9.39.0",
|
"@types/fs-extra": "^9.0.13",
|
||||||
"@tauri-apps/cli": "2.9.2",
|
"@types/js-cookie": "^3.0.6",
|
||||||
"@types/js-yaml": "^4.0.9",
|
|
||||||
"@types/lodash-es": "^4.17.12",
|
"@types/lodash-es": "^4.17.12",
|
||||||
"@types/node": "^24.9.2",
|
"@types/react": "^18.3.1",
|
||||||
"@types/react": "19.2.2",
|
"@types/react-dom": "^18.3.0",
|
||||||
"@types/react-dom": "19.2.2",
|
"@types/react-transition-group": "^4.4.10",
|
||||||
"@vitejs/plugin-legacy": "^7.2.1",
|
"@vitejs/plugin-react": "^4.2.1",
|
||||||
"@vitejs/plugin-react-swc": "^4.2.0",
|
"adm-zip": "^0.5.12",
|
||||||
"adm-zip": "^0.5.16",
|
"cross-env": "^7.0.3",
|
||||||
"cli-color": "^2.0.4",
|
"fs-extra": "^11.2.0",
|
||||||
"commander": "^14.0.2",
|
"https-proxy-agent": "^5.0.1",
|
||||||
"cross-env": "^10.1.0",
|
"husky": "^7.0.4",
|
||||||
"eslint": "^9.39.0",
|
|
||||||
"eslint-config-prettier": "^10.1.8",
|
|
||||||
"eslint-import-resolver-typescript": "^4.4.4",
|
|
||||||
"eslint-plugin-import-x": "^4.16.1",
|
|
||||||
"eslint-plugin-prettier": "^5.5.4",
|
|
||||||
"eslint-plugin-react-hooks": "^7.0.1",
|
|
||||||
"eslint-plugin-react-refresh": "^0.4.24",
|
|
||||||
"eslint-plugin-unused-imports": "^4.3.0",
|
|
||||||
"glob": "^11.0.3",
|
|
||||||
"globals": "^16.5.0",
|
|
||||||
"https-proxy-agent": "^7.0.6",
|
|
||||||
"husky": "^9.1.7",
|
|
||||||
"jiti": "^2.6.1",
|
|
||||||
"lint-staged": "^16.2.6",
|
|
||||||
"meta-json-schema": "^1.19.14",
|
|
||||||
"node-fetch": "^3.3.2",
|
"node-fetch": "^3.3.2",
|
||||||
"prettier": "^3.6.2",
|
"prettier": "^2.8.8",
|
||||||
"sass": "^1.93.3",
|
"pretty-quick": "^3.3.1",
|
||||||
"tar": "^7.5.2",
|
"sass": "^1.75.0",
|
||||||
"terser": "^5.44.0",
|
"typescript": "^5.4.5",
|
||||||
"typescript": "^5.9.3",
|
"vite": "^5.2.10",
|
||||||
"typescript-eslint": "^8.46.2",
|
"vite-plugin-monaco-editor": "^1.1.0",
|
||||||
"vite": "^7.1.12",
|
"vite-plugin-svgr": "^4.2.0"
|
||||||
"vite-plugin-monaco-editor-esm": "^2.0.2",
|
|
||||||
"vite-plugin-svgr": "^4.5.0",
|
|
||||||
"vitest": "^4.0.6"
|
|
||||||
},
|
},
|
||||||
"lint-staged": {
|
"prettier": {
|
||||||
"*.{ts,tsx,js,jsx}": [
|
"tabWidth": 2,
|
||||||
"eslint --fix --max-warnings=0",
|
"semi": true,
|
||||||
"prettier --write",
|
"singleQuote": false,
|
||||||
"git add"
|
"endOfLine": "lf"
|
||||||
],
|
}
|
||||||
"*.{css,scss,json,md}": [
|
|
||||||
"prettier --write",
|
|
||||||
"git add"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"type": "module",
|
|
||||||
"packageManager": "pnpm@9.13.2"
|
|
||||||
}
|
}
|
||||||
|
|||||||
10996
pnpm-lock.yaml
generated
@@ -1,47 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": ["config:recommended", ":disableDependencyDashboard"],
|
|
||||||
"baseBranches": ["dev"],
|
|
||||||
"enabledManagers": ["cargo", "npm"],
|
|
||||||
"labels": ["dependencies"],
|
|
||||||
"ignorePaths": [
|
|
||||||
"**/node_modules/**",
|
|
||||||
"**/bower_components/**",
|
|
||||||
"**/vendor/**",
|
|
||||||
"**/__tests__/**",
|
|
||||||
"**/test/**",
|
|
||||||
"**/tests/**",
|
|
||||||
"**/__fixtures__/**",
|
|
||||||
"**/crate/**",
|
|
||||||
"shared/**"
|
|
||||||
],
|
|
||||||
"rangeStrategy": "bump",
|
|
||||||
"packageRules": [
|
|
||||||
{
|
|
||||||
"semanticCommitType": "chore",
|
|
||||||
"matchPackageNames": ["*"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "Disable node/pnpm version updates",
|
|
||||||
"matchPackageNames": ["node", "pnpm"],
|
|
||||||
"matchDepTypes": ["engines", "packageManager"],
|
|
||||||
"enabled": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "Group all cargo dependencies into a single PR",
|
|
||||||
"matchManagers": ["cargo"],
|
|
||||||
"groupName": "cargo dependencies"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "Group all npm dependencies into a single PR",
|
|
||||||
"matchManagers": ["npm"],
|
|
||||||
"groupName": "npm dependencies"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "Group all GitHub Actions updates into a single PR",
|
|
||||||
"matchManagers": ["github-actions"],
|
|
||||||
"groupName": "github actions"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"postUpdateOptions": ["pnpmDedupe", "updateCargoLock"],
|
|
||||||
"ignoreDeps": ["criterion"]
|
|
||||||
}
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# 获取最近一个和 Tauri 相关的改动的 commit hash
|
|
||||||
# This script finds the latest commit that modified Tauri-related files
|
|
||||||
|
|
||||||
# Tauri 相关文件的模式
|
|
||||||
TAURI_PATTERNS=(
|
|
||||||
"src-tauri/"
|
|
||||||
"Cargo.toml"
|
|
||||||
"Cargo.lock"
|
|
||||||
"tauri.*.conf.json"
|
|
||||||
"package.json"
|
|
||||||
"pnpm-lock.yaml"
|
|
||||||
"src/"
|
|
||||||
)
|
|
||||||
|
|
||||||
# 排除的文件模式(build artifacts 等)
|
|
||||||
EXCLUDE_PATTERNS=(
|
|
||||||
"src-tauri/target/"
|
|
||||||
"src-tauri/gen/"
|
|
||||||
"*.log"
|
|
||||||
"*.tmp"
|
|
||||||
"node_modules/"
|
|
||||||
".git/"
|
|
||||||
)
|
|
||||||
|
|
||||||
# 构建 git log 的路径过滤参数
|
|
||||||
PATHS=""
|
|
||||||
for pattern in "${TAURI_PATTERNS[@]}"; do
|
|
||||||
if [[ -e "$pattern" ]]; then
|
|
||||||
PATHS="$PATHS $pattern"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
# 如果没有找到相关路径,返回错误
|
|
||||||
if [[ -z "$PATHS" ]]; then
|
|
||||||
echo "Error: No Tauri-related paths found in current directory" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 获取最新的 commit hash
|
|
||||||
# 使用 git log 查找最近修改了 Tauri 相关文件的提交
|
|
||||||
LATEST_COMMIT=$(git log --format="%H" -n 1 -- $PATHS)
|
|
||||||
|
|
||||||
# 验证是否找到了 commit
|
|
||||||
if [[ -z "$LATEST_COMMIT" ]]; then
|
|
||||||
echo "Error: No commits found for Tauri-related files" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 输出结果
|
|
||||||
echo "$LATEST_COMMIT"
|
|
||||||
|
|
||||||
# 如果需要更多信息,可以取消注释以下行
|
|
||||||
# echo "Latest Tauri-related commit: $LATEST_COMMIT"
|
|
||||||
# git show --stat --oneline "$LATEST_COMMIT"
|
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
import fs from "fs";
|
|
||||||
import path from "path";
|
|
||||||
import { fileURLToPath } from "url";
|
|
||||||
|
|
||||||
const __filename = fileURLToPath(import.meta.url);
|
|
||||||
const __dirname = path.dirname(__filename);
|
|
||||||
|
|
||||||
const LOCALES_DIR = path.resolve(__dirname, "../src/locales");
|
|
||||||
const SRC_DIRS = [
|
|
||||||
path.resolve(__dirname, "../src"),
|
|
||||||
path.resolve(__dirname, "../src-tauri"),
|
|
||||||
];
|
|
||||||
const exts = [".js", ".ts", ".tsx", ".jsx", ".vue", ".rs"];
|
|
||||||
|
|
||||||
// 递归获取所有文件
|
|
||||||
function getAllFiles(dir, exts) {
|
|
||||||
let files = [];
|
|
||||||
fs.readdirSync(dir).forEach((file) => {
|
|
||||||
const full = path.join(dir, file);
|
|
||||||
if (fs.statSync(full).isDirectory()) {
|
|
||||||
files = files.concat(getAllFiles(full, exts));
|
|
||||||
} else if (exts.includes(path.extname(full))) {
|
|
||||||
files.push(full);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return files;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 读取所有源码内容为一个大字符串
|
|
||||||
function getAllSourceContent() {
|
|
||||||
const files = SRC_DIRS.flatMap((dir) => getAllFiles(dir, exts));
|
|
||||||
return files.map((f) => fs.readFileSync(f, "utf8")).join("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 白名单 key,不检查这些 key 是否被使用
|
|
||||||
const WHITELIST_KEYS = [
|
|
||||||
"theme.light",
|
|
||||||
"theme.dark",
|
|
||||||
"theme.system",
|
|
||||||
"Already Using Latest Core Version",
|
|
||||||
];
|
|
||||||
|
|
||||||
// 主流程
|
|
||||||
function processI18nFile(i18nPath, lang, allSource) {
|
|
||||||
const i18n = JSON.parse(fs.readFileSync(i18nPath, "utf8"));
|
|
||||||
const keys = Object.keys(i18n);
|
|
||||||
|
|
||||||
const used = {};
|
|
||||||
const unused = [];
|
|
||||||
|
|
||||||
let checked = 0;
|
|
||||||
const total = keys.length;
|
|
||||||
keys.forEach((key) => {
|
|
||||||
if (WHITELIST_KEYS.includes(key)) {
|
|
||||||
used[key] = i18n[key];
|
|
||||||
} else {
|
|
||||||
// 只查找一次
|
|
||||||
const regex = new RegExp(`["'\`]${key}["'\`]`);
|
|
||||||
if (regex.test(allSource)) {
|
|
||||||
used[key] = i18n[key];
|
|
||||||
} else {
|
|
||||||
unused.push(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
checked++;
|
|
||||||
if (checked % 20 === 0 || checked === total) {
|
|
||||||
const percent = ((checked / total) * 100).toFixed(1);
|
|
||||||
process.stdout.write(
|
|
||||||
`\r[${lang}] Progress: ${checked}/${total} (${percent}%)`,
|
|
||||||
);
|
|
||||||
if (checked === total) process.stdout.write("\n");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 输出未使用的 key
|
|
||||||
console.log(`\n[${lang}] Unused keys:`, unused);
|
|
||||||
|
|
||||||
// 备份原文件
|
|
||||||
const oldPath = i18nPath + ".old";
|
|
||||||
fs.renameSync(i18nPath, oldPath);
|
|
||||||
|
|
||||||
// 写入精简后的 i18n 文件(保留原文件名)
|
|
||||||
fs.writeFileSync(i18nPath, JSON.stringify(used, null, 2), "utf8");
|
|
||||||
console.log(
|
|
||||||
`[${lang}] Cleaned i18n file written to src/locales/${path.basename(i18nPath)}`,
|
|
||||||
);
|
|
||||||
console.log(`[${lang}] Original file backed up as ${path.basename(oldPath)}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
function main() {
|
|
||||||
// 支持 zhtw.json、zh-tw.json、zh_CN.json 等
|
|
||||||
const files = fs
|
|
||||||
.readdirSync(LOCALES_DIR)
|
|
||||||
.filter((f) => /^[a-z0-9\-_]+\.json$/i.test(f) && !f.endsWith(".old"));
|
|
||||||
const allSource = getAllSourceContent();
|
|
||||||
files.forEach((file) => {
|
|
||||||
const lang = path.basename(file, ".json");
|
|
||||||
processI18nFile(path.join(LOCALES_DIR, file), lang, allSource);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
main();
|
|
||||||
491
scripts/check.mjs
Normal file
@@ -0,0 +1,491 @@
|
|||||||
|
import fs from "fs-extra";
|
||||||
|
import zlib from "zlib";
|
||||||
|
import tar from "tar";
|
||||||
|
import path from "path";
|
||||||
|
import AdmZip from "adm-zip";
|
||||||
|
import fetch from "node-fetch";
|
||||||
|
import proxyAgent from "https-proxy-agent";
|
||||||
|
import { execSync } from "child_process";
|
||||||
|
|
||||||
|
const cwd = process.cwd();
|
||||||
|
const TEMP_DIR = path.join(cwd, "node_modules/.verge");
|
||||||
|
const FORCE = process.argv.includes("--force");
|
||||||
|
|
||||||
|
const PLATFORM_MAP = {
|
||||||
|
"x86_64-pc-windows-msvc": "win32",
|
||||||
|
"i686-pc-windows-msvc": "win32",
|
||||||
|
"aarch64-pc-windows-msvc": "win32",
|
||||||
|
"x86_64-apple-darwin": "darwin",
|
||||||
|
"aarch64-apple-darwin": "darwin",
|
||||||
|
"x86_64-unknown-linux-gnu": "linux",
|
||||||
|
"i686-unknown-linux-gnu": "linux",
|
||||||
|
"aarch64-unknown-linux-gnu": "linux",
|
||||||
|
"armv7-unknown-linux-gnueabihf": "linux",
|
||||||
|
"riscv64gc-unknown-linux-gnu": "linux",
|
||||||
|
"loongarch64-unknown-linux-gnu": "linux",
|
||||||
|
};
|
||||||
|
const ARCH_MAP = {
|
||||||
|
"x86_64-pc-windows-msvc": "x64",
|
||||||
|
"i686-pc-windows-msvc": "ia32",
|
||||||
|
"aarch64-pc-windows-msvc": "arm64",
|
||||||
|
"x86_64-apple-darwin": "x64",
|
||||||
|
"aarch64-apple-darwin": "arm64",
|
||||||
|
"x86_64-unknown-linux-gnu": "x64",
|
||||||
|
"i686-unknown-linux-gnu": "ia32",
|
||||||
|
"aarch64-unknown-linux-gnu": "arm64",
|
||||||
|
"armv7-unknown-linux-gnueabihf": "arm",
|
||||||
|
"riscv64gc-unknown-linux-gnu": "riscv64",
|
||||||
|
"loongarch64-unknown-linux-gnu": "loong64",
|
||||||
|
};
|
||||||
|
|
||||||
|
const arg1 = process.argv.slice(2)[0];
|
||||||
|
const arg2 = process.argv.slice(2)[1];
|
||||||
|
const target = arg1 === "--force" ? arg2 : arg1;
|
||||||
|
const { platform, arch } = target
|
||||||
|
? { platform: PLATFORM_MAP[target], arch: ARCH_MAP[target] }
|
||||||
|
: process;
|
||||||
|
|
||||||
|
const SIDECAR_HOST = target
|
||||||
|
? target
|
||||||
|
: execSync("rustc -vV")
|
||||||
|
.toString()
|
||||||
|
.match(/(?<=host: ).+(?=\s*)/g)[0];
|
||||||
|
|
||||||
|
/* ======= clash meta alpha======= */
|
||||||
|
const META_ALPHA_VERSION_URL =
|
||||||
|
"https://github.com/MetaCubeX/mihomo/releases/download/Prerelease-Alpha/version.txt";
|
||||||
|
const META_ALPHA_URL_PREFIX = `https://github.com/MetaCubeX/mihomo/releases/download/Prerelease-Alpha`;
|
||||||
|
let META_ALPHA_VERSION;
|
||||||
|
|
||||||
|
const META_ALPHA_MAP = {
|
||||||
|
"win32-x64": "mihomo-windows-amd64-compatible",
|
||||||
|
"win32-ia32": "mihomo-windows-386",
|
||||||
|
"win32-arm64": "mihomo-windows-arm64",
|
||||||
|
"darwin-x64": "mihomo-darwin-amd64",
|
||||||
|
"darwin-arm64": "mihomo-darwin-arm64",
|
||||||
|
"linux-x64": "mihomo-linux-amd64-compatible",
|
||||||
|
"linux-ia32": "mihomo-linux-386",
|
||||||
|
"linux-arm64": "mihomo-linux-arm64",
|
||||||
|
"linux-arm": "mihomo-linux-armv7",
|
||||||
|
"linux-riscv64": "mihomo-linux-riscv64",
|
||||||
|
"linux-loong64": "mihomo-linux-loong64",
|
||||||
|
};
|
||||||
|
|
||||||
|
// Fetch the latest alpha release version from the version.txt file
|
||||||
|
async function getLatestAlphaVersion() {
|
||||||
|
const options = {};
|
||||||
|
|
||||||
|
const httpProxy =
|
||||||
|
process.env.HTTP_PROXY ||
|
||||||
|
process.env.http_proxy ||
|
||||||
|
process.env.HTTPS_PROXY ||
|
||||||
|
process.env.https_proxy;
|
||||||
|
|
||||||
|
if (httpProxy) {
|
||||||
|
options.agent = proxyAgent(httpProxy);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const response = await fetch(META_ALPHA_VERSION_URL, {
|
||||||
|
...options,
|
||||||
|
method: "GET",
|
||||||
|
});
|
||||||
|
let v = await response.text();
|
||||||
|
META_ALPHA_VERSION = v.trim(); // Trim to remove extra whitespaces
|
||||||
|
console.log(`Latest alpha version: ${META_ALPHA_VERSION}`);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching latest alpha version:", error.message);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ======= clash meta stable ======= */
|
||||||
|
const META_VERSION_URL =
|
||||||
|
"https://github.com/MetaCubeX/mihomo/releases/latest/download/version.txt";
|
||||||
|
const META_URL_PREFIX = `https://github.com/MetaCubeX/mihomo/releases/download`;
|
||||||
|
let META_VERSION;
|
||||||
|
|
||||||
|
const META_MAP = {
|
||||||
|
"win32-x64": "mihomo-windows-amd64-compatible",
|
||||||
|
"win32-ia32": "mihomo-windows-386",
|
||||||
|
"win32-arm64": "mihomo-windows-arm64",
|
||||||
|
"darwin-x64": "mihomo-darwin-amd64",
|
||||||
|
"darwin-arm64": "mihomo-darwin-arm64",
|
||||||
|
"linux-x64": "mihomo-linux-amd64-compatible",
|
||||||
|
"linux-ia32": "mihomo-linux-386",
|
||||||
|
"linux-arm64": "mihomo-linux-arm64",
|
||||||
|
"linux-arm": "mihomo-linux-armv7",
|
||||||
|
"linux-riscv64": "mihomo-linux-riscv64",
|
||||||
|
"linux-loong64": "mihomo-linux-loong64",
|
||||||
|
};
|
||||||
|
|
||||||
|
// Fetch the latest release version from the version.txt file
|
||||||
|
async function getLatestReleaseVersion() {
|
||||||
|
const options = {};
|
||||||
|
|
||||||
|
const httpProxy =
|
||||||
|
process.env.HTTP_PROXY ||
|
||||||
|
process.env.http_proxy ||
|
||||||
|
process.env.HTTPS_PROXY ||
|
||||||
|
process.env.https_proxy;
|
||||||
|
|
||||||
|
if (httpProxy) {
|
||||||
|
options.agent = proxyAgent(httpProxy);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const response = await fetch(META_VERSION_URL, {
|
||||||
|
...options,
|
||||||
|
method: "GET",
|
||||||
|
});
|
||||||
|
let v = await response.text();
|
||||||
|
META_VERSION = v.trim(); // Trim to remove extra whitespaces
|
||||||
|
console.log(`Latest release version: ${META_VERSION}`);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching latest release version:", error.message);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* check available
|
||||||
|
*/
|
||||||
|
if (!META_MAP[`${platform}-${arch}`]) {
|
||||||
|
throw new Error(
|
||||||
|
`clash meta alpha unsupported platform "${platform}-${arch}"`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!META_ALPHA_MAP[`${platform}-${arch}`]) {
|
||||||
|
throw new Error(
|
||||||
|
`clash meta alpha unsupported platform "${platform}-${arch}"`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* core info
|
||||||
|
*/
|
||||||
|
function clashMetaAlpha() {
|
||||||
|
const name = META_ALPHA_MAP[`${platform}-${arch}`];
|
||||||
|
const isWin = platform === "win32";
|
||||||
|
const urlExt = isWin ? "zip" : "gz";
|
||||||
|
const downloadURL = `${META_ALPHA_URL_PREFIX}/${name}-${META_ALPHA_VERSION}.${urlExt}`;
|
||||||
|
const exeFile = `${name}${isWin ? ".exe" : ""}`;
|
||||||
|
const zipFile = `${name}-${META_ALPHA_VERSION}.${urlExt}`;
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: "clash-meta-alpha",
|
||||||
|
targetFile: `clash-meta-alpha-${SIDECAR_HOST}${isWin ? ".exe" : ""}`,
|
||||||
|
exeFile,
|
||||||
|
zipFile,
|
||||||
|
downloadURL,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function clashMeta() {
|
||||||
|
const name = META_MAP[`${platform}-${arch}`];
|
||||||
|
const isWin = platform === "win32";
|
||||||
|
const urlExt = isWin ? "zip" : "gz";
|
||||||
|
const downloadURL = `${META_URL_PREFIX}/${META_VERSION}/${name}-${META_VERSION}.${urlExt}`;
|
||||||
|
const exeFile = `${name}${isWin ? ".exe" : ""}`;
|
||||||
|
const zipFile = `${name}-${META_VERSION}.${urlExt}`;
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: "clash-meta",
|
||||||
|
targetFile: `clash-meta-${SIDECAR_HOST}${isWin ? ".exe" : ""}`,
|
||||||
|
exeFile,
|
||||||
|
zipFile,
|
||||||
|
downloadURL,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* download sidecar and rename
|
||||||
|
*/
|
||||||
|
async function resolveSidecar(binInfo) {
|
||||||
|
const { name, targetFile, zipFile, exeFile, downloadURL } = binInfo;
|
||||||
|
|
||||||
|
const sidecarDir = path.join(cwd, "src-tauri", "sidecar");
|
||||||
|
const sidecarPath = path.join(sidecarDir, targetFile);
|
||||||
|
|
||||||
|
await fs.mkdirp(sidecarDir);
|
||||||
|
if (!FORCE && (await fs.pathExists(sidecarPath))) return;
|
||||||
|
|
||||||
|
const tempDir = path.join(TEMP_DIR, name);
|
||||||
|
const tempZip = path.join(tempDir, zipFile);
|
||||||
|
const tempExe = path.join(tempDir, exeFile);
|
||||||
|
|
||||||
|
await fs.mkdirp(tempDir);
|
||||||
|
try {
|
||||||
|
if (!(await fs.pathExists(tempZip))) {
|
||||||
|
await downloadFile(downloadURL, tempZip);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (zipFile.endsWith(".zip")) {
|
||||||
|
const zip = new AdmZip(tempZip);
|
||||||
|
zip.getEntries().forEach((entry) => {
|
||||||
|
console.log(`[DEBUG]: "${name}" entry name`, entry.entryName);
|
||||||
|
});
|
||||||
|
zip.extractAllTo(tempDir, true);
|
||||||
|
await fs.rename(tempExe, sidecarPath);
|
||||||
|
console.log(`[INFO]: "${name}" unzip finished`);
|
||||||
|
} else if (zipFile.endsWith(".tgz")) {
|
||||||
|
// tgz
|
||||||
|
await fs.mkdirp(tempDir);
|
||||||
|
await tar.extract({
|
||||||
|
cwd: tempDir,
|
||||||
|
file: tempZip,
|
||||||
|
//strip: 1, // 可能需要根据实际的 .tgz 文件结构调整
|
||||||
|
});
|
||||||
|
const files = await fs.readdir(tempDir);
|
||||||
|
console.log(`[DEBUG]: "${name}" files in tempDir:`, files);
|
||||||
|
const extractedFile = files.find((file) => file.startsWith("虚空终端-"));
|
||||||
|
if (extractedFile) {
|
||||||
|
const extractedFilePath = path.join(tempDir, extractedFile);
|
||||||
|
await fs.rename(extractedFilePath, sidecarPath);
|
||||||
|
console.log(`[INFO]: "${name}" file renamed to "${sidecarPath}"`);
|
||||||
|
execSync(`chmod 755 ${sidecarPath}`);
|
||||||
|
console.log(`[INFO]: "${name}" chmod binary finished`);
|
||||||
|
} else {
|
||||||
|
throw new Error(`Expected file not found in ${tempDir}`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// gz
|
||||||
|
const readStream = fs.createReadStream(tempZip);
|
||||||
|
const writeStream = fs.createWriteStream(sidecarPath);
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
const onError = (error) => {
|
||||||
|
console.error(`[ERROR]: "${name}" gz failed:`, error.message);
|
||||||
|
reject(error);
|
||||||
|
};
|
||||||
|
readStream
|
||||||
|
.pipe(zlib.createGunzip().on("error", onError))
|
||||||
|
.pipe(writeStream)
|
||||||
|
.on("finish", () => {
|
||||||
|
console.log(`[INFO]: "${name}" gunzip finished`);
|
||||||
|
execSync(`chmod 755 ${sidecarPath}`);
|
||||||
|
console.log(`[INFO]: "${name}" chmod binary finished`);
|
||||||
|
resolve();
|
||||||
|
})
|
||||||
|
.on("error", onError);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
// 需要删除文件
|
||||||
|
await fs.remove(sidecarPath);
|
||||||
|
throw err;
|
||||||
|
} finally {
|
||||||
|
// delete temp dir
|
||||||
|
await fs.remove(tempDir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* download the file to the resources dir
|
||||||
|
*/
|
||||||
|
async function resolveResource(binInfo) {
|
||||||
|
const { file, downloadURL } = binInfo;
|
||||||
|
|
||||||
|
const resDir = path.join(cwd, "src-tauri/resources");
|
||||||
|
const targetPath = path.join(resDir, file);
|
||||||
|
|
||||||
|
if (!FORCE && (await fs.pathExists(targetPath))) return;
|
||||||
|
|
||||||
|
await fs.mkdirp(resDir);
|
||||||
|
await downloadFile(downloadURL, targetPath);
|
||||||
|
|
||||||
|
console.log(`[INFO]: ${file} finished`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* download file and save to `path`
|
||||||
|
*/
|
||||||
|
async function downloadFile(url, path) {
|
||||||
|
const options = {};
|
||||||
|
|
||||||
|
const httpProxy =
|
||||||
|
process.env.HTTP_PROXY ||
|
||||||
|
process.env.http_proxy ||
|
||||||
|
process.env.HTTPS_PROXY ||
|
||||||
|
process.env.https_proxy;
|
||||||
|
|
||||||
|
if (httpProxy) {
|
||||||
|
options.agent = proxyAgent(httpProxy);
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await fetch(url, {
|
||||||
|
...options,
|
||||||
|
method: "GET",
|
||||||
|
headers: { "Content-Type": "application/octet-stream" },
|
||||||
|
});
|
||||||
|
const buffer = await response.arrayBuffer();
|
||||||
|
await fs.writeFile(path, new Uint8Array(buffer));
|
||||||
|
|
||||||
|
console.log(`[INFO]: download finished "${url}"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// SimpleSC.dll
|
||||||
|
const resolvePlugin = async () => {
|
||||||
|
const url =
|
||||||
|
"https://nsis.sourceforge.io/mediawiki/images/e/ef/NSIS_Simple_Service_Plugin_Unicode_1.30.zip";
|
||||||
|
|
||||||
|
const tempDir = path.join(TEMP_DIR, "SimpleSC");
|
||||||
|
const tempZip = path.join(
|
||||||
|
tempDir,
|
||||||
|
"NSIS_Simple_Service_Plugin_Unicode_1.30.zip"
|
||||||
|
);
|
||||||
|
const tempDll = path.join(tempDir, "SimpleSC.dll");
|
||||||
|
const pluginDir = path.join(process.env.APPDATA, "Local/NSIS");
|
||||||
|
const pluginPath = path.join(pluginDir, "SimpleSC.dll");
|
||||||
|
await fs.mkdirp(pluginDir);
|
||||||
|
await fs.mkdirp(tempDir);
|
||||||
|
if (!FORCE && (await fs.pathExists(pluginPath))) return;
|
||||||
|
try {
|
||||||
|
if (!(await fs.pathExists(tempZip))) {
|
||||||
|
await downloadFile(url, tempZip);
|
||||||
|
}
|
||||||
|
const zip = new AdmZip(tempZip);
|
||||||
|
zip.getEntries().forEach((entry) => {
|
||||||
|
console.log(`[DEBUG]: "SimpleSC" entry name`, entry.entryName);
|
||||||
|
});
|
||||||
|
zip.extractAllTo(tempDir, true);
|
||||||
|
await fs.copyFile(tempDll, pluginPath);
|
||||||
|
console.log(`[INFO]: "SimpleSC" unzip finished`);
|
||||||
|
} finally {
|
||||||
|
await fs.remove(tempDir);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// service chmod
|
||||||
|
const resolveServicePermission = async () => {
|
||||||
|
const serviceExecutables = [
|
||||||
|
"clash-verge-service",
|
||||||
|
"install-service",
|
||||||
|
"uninstall-service",
|
||||||
|
];
|
||||||
|
const resDir = path.join(cwd, "src-tauri/resources");
|
||||||
|
for (let f of serviceExecutables) {
|
||||||
|
const targetPath = path.join(resDir, f);
|
||||||
|
if (await fs.pathExists(targetPath)) {
|
||||||
|
execSync(`chmod 755 ${targetPath}`);
|
||||||
|
console.log(`[INFO]: "${targetPath}" chmod finished`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* main
|
||||||
|
*/
|
||||||
|
|
||||||
|
const SERVICE_URL = `https://github.com/clash-verge-rev/clash-verge-service/releases/download/${SIDECAR_HOST}`;
|
||||||
|
|
||||||
|
const resolveService = () => {
|
||||||
|
let ext = platform === "win32" ? ".exe" : "";
|
||||||
|
resolveResource({
|
||||||
|
file: "clash-verge-service" + ext,
|
||||||
|
downloadURL: `${SERVICE_URL}/clash-verge-service${ext}`,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const resolveInstall = () => {
|
||||||
|
let ext = platform === "win32" ? ".exe" : "";
|
||||||
|
resolveResource({
|
||||||
|
file: "install-service" + ext,
|
||||||
|
downloadURL: `${SERVICE_URL}/install-service${ext}`,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const resolveUninstall = () => {
|
||||||
|
let ext = platform === "win32" ? ".exe" : "";
|
||||||
|
resolveResource({
|
||||||
|
file: "uninstall-service" + ext,
|
||||||
|
downloadURL: `${SERVICE_URL}/uninstall-service${ext}`,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const resolveSetDnsScript = () =>
|
||||||
|
resolveResource({
|
||||||
|
file: "set_dns.sh",
|
||||||
|
downloadURL: `https://github.com/clash-verge-rev/set-dns-script/releases/download/script/set_dns.sh`,
|
||||||
|
});
|
||||||
|
const resolveUnSetDnsScript = () =>
|
||||||
|
resolveResource({
|
||||||
|
file: "unset_dns.sh",
|
||||||
|
downloadURL: `https://github.com/clash-verge-rev/set-dns-script/releases/download/script/unset_dns.sh`,
|
||||||
|
});
|
||||||
|
const resolveMmdb = () =>
|
||||||
|
resolveResource({
|
||||||
|
file: "Country.mmdb",
|
||||||
|
downloadURL: `https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/country.mmdb`,
|
||||||
|
});
|
||||||
|
const resolveGeosite = () =>
|
||||||
|
resolveResource({
|
||||||
|
file: "geosite.dat",
|
||||||
|
downloadURL: `https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geosite.dat`,
|
||||||
|
});
|
||||||
|
const resolveGeoIP = () =>
|
||||||
|
resolveResource({
|
||||||
|
file: "geoip.dat",
|
||||||
|
downloadURL: `https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.dat`,
|
||||||
|
});
|
||||||
|
const resolveEnableLoopback = () =>
|
||||||
|
resolveResource({
|
||||||
|
file: "enableLoopback.exe",
|
||||||
|
downloadURL: `https://github.com/Kuingsmile/uwp-tool/releases/download/latest/enableLoopback.exe`,
|
||||||
|
});
|
||||||
|
|
||||||
|
const tasks = [
|
||||||
|
// { name: "clash", func: resolveClash, retry: 5 },
|
||||||
|
{
|
||||||
|
name: "clash-meta-alpha",
|
||||||
|
func: () =>
|
||||||
|
getLatestAlphaVersion().then(() => resolveSidecar(clashMetaAlpha())),
|
||||||
|
retry: 5,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "clash-meta",
|
||||||
|
func: () =>
|
||||||
|
getLatestReleaseVersion().then(() => resolveSidecar(clashMeta())),
|
||||||
|
retry: 5,
|
||||||
|
},
|
||||||
|
{ name: "plugin", func: resolvePlugin, retry: 5, winOnly: true },
|
||||||
|
{ name: "service", func: resolveService, retry: 5 },
|
||||||
|
{ name: "install", func: resolveInstall, retry: 5 },
|
||||||
|
{ name: "uninstall", func: resolveUninstall, retry: 5 },
|
||||||
|
{ name: "set_dns_script", func: resolveSetDnsScript, retry: 5 },
|
||||||
|
{ name: "unset_dns_script", func: resolveUnSetDnsScript, retry: 5 },
|
||||||
|
{ name: "mmdb", func: resolveMmdb, retry: 5 },
|
||||||
|
{ name: "geosite", func: resolveGeosite, retry: 5 },
|
||||||
|
{ name: "geoip", func: resolveGeoIP, retry: 5 },
|
||||||
|
{
|
||||||
|
name: "enableLoopback",
|
||||||
|
func: resolveEnableLoopback,
|
||||||
|
retry: 5,
|
||||||
|
winOnly: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "service_chmod",
|
||||||
|
func: resolveServicePermission,
|
||||||
|
retry: 1,
|
||||||
|
unixOnly: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
async function runTask() {
|
||||||
|
const task = tasks.shift();
|
||||||
|
if (!task) return;
|
||||||
|
if (task.winOnly && platform !== "win32") return runTask();
|
||||||
|
if (task.linuxOnly && platform !== "linux") return runTask();
|
||||||
|
if (task.unixOnly && platform === "win32") return runTask();
|
||||||
|
|
||||||
|
for (let i = 0; i < task.retry; i++) {
|
||||||
|
try {
|
||||||
|
await task.func();
|
||||||
|
break;
|
||||||
|
} catch (err) {
|
||||||
|
console.error(`[ERROR]: task::${task.name} try ${i} ==`, err.message);
|
||||||
|
if (i === task.retry - 1) throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return runTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
runTask();
|
||||||
|
runTask();
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
import { exec } from "child_process";
|
|
||||||
import { promisify } from "util";
|
|
||||||
import fs from "fs/promises";
|
|
||||||
import path from "path";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 为Alpha版本重命名版本号
|
|
||||||
*/
|
|
||||||
const execPromise = promisify(exec);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 标准输出HEAD hash
|
|
||||||
*/
|
|
||||||
async function getLatestCommitHash() {
|
|
||||||
try {
|
|
||||||
const { stdout } = await execPromise("git rev-parse HEAD");
|
|
||||||
const commitHash = stdout.trim();
|
|
||||||
// 格式化,只截取前7位字符
|
|
||||||
const formathash = commitHash.substring(0, 7);
|
|
||||||
console.log(`Found the latest commit hash code: ${commitHash}`);
|
|
||||||
return formathash;
|
|
||||||
} catch (error) {
|
|
||||||
console.error("pnpm run fix-alpha-version ERROR", error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string 传入格式化后的hash
|
|
||||||
* 将新的版本号写入文件 package.json
|
|
||||||
*/
|
|
||||||
async function updatePackageVersion(newVersion) {
|
|
||||||
// 获取内容根目录
|
|
||||||
const _dirname = process.cwd();
|
|
||||||
const packageJsonPath = path.join(_dirname, "package.json");
|
|
||||||
try {
|
|
||||||
// 读取文件
|
|
||||||
const data = await fs.readFile(packageJsonPath, "utf8");
|
|
||||||
const packageJson = JSON.parse(data);
|
|
||||||
// 获取键值替换
|
|
||||||
let result = packageJson.version.replace("alpha", newVersion);
|
|
||||||
// 检查当前版本号是否已经包含了 alpha- 后缀
|
|
||||||
if (!packageJson.version.includes(`alpha-`)) {
|
|
||||||
// 如果只有 alpha 而没有 alpha-,则替换为 alpha-newVersion
|
|
||||||
result = packageJson.version.replace("alpha", `alpha-${newVersion}`);
|
|
||||||
} else {
|
|
||||||
// 如果已经是 alpha-xxx 格式,则更新 xxx 部分
|
|
||||||
result = packageJson.version.replace(
|
|
||||||
/alpha-[^-]*/,
|
|
||||||
`alpha-${newVersion}`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
console.log("[INFO]: Current version is: ", result);
|
|
||||||
packageJson.version = result;
|
|
||||||
// 写入版本号
|
|
||||||
await fs.writeFile(
|
|
||||||
packageJsonPath,
|
|
||||||
JSON.stringify(packageJson, null, 2),
|
|
||||||
"utf8",
|
|
||||||
);
|
|
||||||
console.log(`[INFO]: Alpha version update to: ${newVersion}`);
|
|
||||||
} catch (error) {
|
|
||||||
console.error("pnpm run fix-alpha-version ERROR", error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const newVersion = await getLatestCommitHash();
|
|
||||||
updatePackageVersion(newVersion).catch(console.error);
|
|
||||||
@@ -1,103 +0,0 @@
|
|||||||
import fs from "fs";
|
|
||||||
import fsp from "fs/promises";
|
|
||||||
import path from "path";
|
|
||||||
import AdmZip from "adm-zip";
|
|
||||||
import { createRequire } from "module";
|
|
||||||
import { getOctokit, context } from "@actions/github";
|
|
||||||
|
|
||||||
const target = process.argv.slice(2)[0];
|
|
||||||
const alpha = process.argv.slice(2)[1];
|
|
||||||
|
|
||||||
const ARCH_MAP = {
|
|
||||||
"x86_64-pc-windows-msvc": "x64",
|
|
||||||
"i686-pc-windows-msvc": "x86",
|
|
||||||
"aarch64-pc-windows-msvc": "arm64",
|
|
||||||
};
|
|
||||||
|
|
||||||
const PROCESS_MAP = {
|
|
||||||
x64: "x64",
|
|
||||||
ia32: "x86",
|
|
||||||
arm64: "arm64",
|
|
||||||
};
|
|
||||||
const arch = target ? ARCH_MAP[target] : PROCESS_MAP[process.arch];
|
|
||||||
/// Script for ci
|
|
||||||
/// 打包绿色版/便携版 (only Windows)
|
|
||||||
async function resolvePortable() {
|
|
||||||
if (process.platform !== "win32") return;
|
|
||||||
|
|
||||||
const releaseDir = target
|
|
||||||
? `./src-tauri/target/${target}/release`
|
|
||||||
: `./src-tauri/target/release`;
|
|
||||||
|
|
||||||
const configDir = path.join(releaseDir, ".config");
|
|
||||||
|
|
||||||
if (!fs.existsSync(releaseDir)) {
|
|
||||||
throw new Error("could not found the release dir");
|
|
||||||
}
|
|
||||||
|
|
||||||
await fsp.mkdir(configDir, { recursive: true });
|
|
||||||
if (!fs.existsSync(path.join(configDir, "PORTABLE"))) {
|
|
||||||
await fsp.writeFile(path.join(configDir, "PORTABLE"), "");
|
|
||||||
}
|
|
||||||
|
|
||||||
const zip = new AdmZip();
|
|
||||||
|
|
||||||
zip.addLocalFile(path.join(releaseDir, "Clash Verge.exe"));
|
|
||||||
zip.addLocalFile(path.join(releaseDir, "verge-mihomo.exe"));
|
|
||||||
zip.addLocalFile(path.join(releaseDir, "verge-mihomo-alpha.exe"));
|
|
||||||
zip.addLocalFolder(path.join(releaseDir, "resources"), "resources");
|
|
||||||
zip.addLocalFolder(
|
|
||||||
path.join(
|
|
||||||
releaseDir,
|
|
||||||
`Microsoft.WebView2.FixedVersionRuntime.109.0.1518.78.${arch}`,
|
|
||||||
),
|
|
||||||
`Microsoft.WebView2.FixedVersionRuntime.109.0.1518.78.${arch}`,
|
|
||||||
);
|
|
||||||
zip.addLocalFolder(configDir, ".config");
|
|
||||||
|
|
||||||
const require = createRequire(import.meta.url);
|
|
||||||
const packageJson = require("../package.json");
|
|
||||||
const { version } = packageJson;
|
|
||||||
|
|
||||||
const zipFile = `Clash.Verge_${version}_${arch}_fixed_webview2_portable.zip`;
|
|
||||||
zip.writeZip(zipFile);
|
|
||||||
|
|
||||||
console.log("[INFO]: create portable zip successfully");
|
|
||||||
|
|
||||||
// push release assets
|
|
||||||
if (process.env.GITHUB_TOKEN === undefined) {
|
|
||||||
throw new Error("GITHUB_TOKEN is required");
|
|
||||||
}
|
|
||||||
|
|
||||||
const options = { owner: context.repo.owner, repo: context.repo.repo };
|
|
||||||
const github = getOctokit(process.env.GITHUB_TOKEN);
|
|
||||||
const tag = alpha ? "alpha" : process.env.TAG_NAME || `v${version}`;
|
|
||||||
console.log("[INFO]: upload to ", tag);
|
|
||||||
|
|
||||||
const { data: release } = await github.rest.repos.getReleaseByTag({
|
|
||||||
...options,
|
|
||||||
tag,
|
|
||||||
});
|
|
||||||
|
|
||||||
let assets = release.assets.filter((x) => {
|
|
||||||
return x.name === zipFile;
|
|
||||||
});
|
|
||||||
if (assets.length > 0) {
|
|
||||||
let id = assets[0].id;
|
|
||||||
await github.rest.repos.deleteReleaseAsset({
|
|
||||||
...options,
|
|
||||||
asset_id: id,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(release.name);
|
|
||||||
|
|
||||||
await github.rest.repos.uploadReleaseAsset({
|
|
||||||
...options,
|
|
||||||
release_id: release.id,
|
|
||||||
name: zipFile,
|
|
||||||
data: zip.toBuffer(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
resolvePortable().catch(console.error);
|
|
||||||
@@ -1,20 +1,17 @@
|
|||||||
import fs from "fs";
|
import fs from "fs-extra";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import AdmZip from "adm-zip";
|
import AdmZip from "adm-zip";
|
||||||
import { createRequire } from "module";
|
import { createRequire } from "module";
|
||||||
import fsp from "fs/promises";
|
import { getOctokit, context } from "@actions/github";
|
||||||
|
|
||||||
const target = process.argv.slice(2)[0];
|
const target = process.argv.slice(2)[0];
|
||||||
|
const alpha = process.argv.slice(2)[1];
|
||||||
|
|
||||||
const ARCH_MAP = {
|
const ARCH_MAP = {
|
||||||
"x86_64-pc-windows-msvc": "x64",
|
"x86_64-pc-windows-msvc": "x64",
|
||||||
"aarch64-pc-windows-msvc": "arm64",
|
"aarch64-pc-windows-msvc": "arm64",
|
||||||
};
|
};
|
||||||
|
|
||||||
const PROCESS_MAP = {
|
|
||||||
x64: "x64",
|
|
||||||
arm64: "arm64",
|
|
||||||
};
|
|
||||||
const arch = target ? ARCH_MAP[target] : PROCESS_MAP[process.arch];
|
|
||||||
/// Script for ci
|
/// Script for ci
|
||||||
/// 打包绿色版/便携版 (only Windows)
|
/// 打包绿色版/便携版 (only Windows)
|
||||||
async function resolvePortable() {
|
async function resolvePortable() {
|
||||||
@@ -25,28 +22,64 @@ async function resolvePortable() {
|
|||||||
: `./src-tauri/target/release`;
|
: `./src-tauri/target/release`;
|
||||||
const configDir = path.join(releaseDir, ".config");
|
const configDir = path.join(releaseDir, ".config");
|
||||||
|
|
||||||
if (!fs.existsSync(releaseDir)) {
|
if (!(await fs.pathExists(releaseDir))) {
|
||||||
throw new Error("could not found the release dir");
|
throw new Error("could not found the release dir");
|
||||||
}
|
}
|
||||||
|
|
||||||
await fsp.mkdir(configDir, { recursive: true });
|
await fs.mkdir(configDir);
|
||||||
if (!fs.existsSync(path.join(configDir, "PORTABLE"))) {
|
await fs.createFile(path.join(configDir, "PORTABLE"));
|
||||||
await fsp.writeFile(path.join(configDir, "PORTABLE"), "");
|
|
||||||
}
|
|
||||||
const zip = new AdmZip();
|
const zip = new AdmZip();
|
||||||
|
|
||||||
zip.addLocalFile(path.join(releaseDir, "clash-verge.exe"));
|
zip.addLocalFile(path.join(releaseDir, "Clash Verge.exe"));
|
||||||
zip.addLocalFile(path.join(releaseDir, "verge-mihomo.exe"));
|
zip.addLocalFile(path.join(releaseDir, "clash-meta.exe"));
|
||||||
zip.addLocalFile(path.join(releaseDir, "verge-mihomo-alpha.exe"));
|
zip.addLocalFile(path.join(releaseDir, "clash-meta-alpha.exe"));
|
||||||
zip.addLocalFolder(path.join(releaseDir, "resources"), "resources");
|
zip.addLocalFolder(path.join(releaseDir, "resources"), "resources");
|
||||||
zip.addLocalFolder(configDir, ".config");
|
zip.addLocalFolder(configDir, ".config");
|
||||||
|
|
||||||
const require = createRequire(import.meta.url);
|
const require = createRequire(import.meta.url);
|
||||||
const packageJson = require("../package.json");
|
const packageJson = require("../package.json");
|
||||||
const { version } = packageJson;
|
const { version } = packageJson;
|
||||||
const zipFile = `Clash.Verge_${version}_${arch}_portable.zip`;
|
|
||||||
|
const zipFile = `Clash.Verge_${version}_${ARCH_MAP[target]}_portable.zip`;
|
||||||
zip.writeZip(zipFile);
|
zip.writeZip(zipFile);
|
||||||
|
|
||||||
console.log("[INFO]: create portable zip successfully");
|
console.log("[INFO]: create portable zip successfully");
|
||||||
|
|
||||||
|
// push release assets
|
||||||
|
if (process.env.GITHUB_TOKEN === undefined) {
|
||||||
|
throw new Error("GITHUB_TOKEN is required");
|
||||||
|
}
|
||||||
|
|
||||||
|
const options = { owner: context.repo.owner, repo: context.repo.repo };
|
||||||
|
const github = getOctokit(process.env.GITHUB_TOKEN);
|
||||||
|
const tag = alpha ? "alpha" : process.env.TAG_NAME || `v${version}`;
|
||||||
|
console.log("[INFO]: upload to ", tag);
|
||||||
|
|
||||||
|
const { data: release } = await github.rest.repos.getReleaseByTag({
|
||||||
|
...options,
|
||||||
|
tag,
|
||||||
|
});
|
||||||
|
|
||||||
|
let assets = release.assets.filter((x) => {
|
||||||
|
return x.name === zipFile;
|
||||||
|
});
|
||||||
|
if (assets.length > 0) {
|
||||||
|
let id = assets[0].id;
|
||||||
|
await github.rest.repos.deleteReleaseAsset({
|
||||||
|
...options,
|
||||||
|
asset_id: id,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(release.name);
|
||||||
|
|
||||||
|
await github.rest.repos.uploadReleaseAsset({
|
||||||
|
...options,
|
||||||
|
release_id: release.id,
|
||||||
|
name: zipFile,
|
||||||
|
data: zip.toBuffer(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
resolvePortable().catch(console.error);
|
resolvePortable().catch(console.error);
|
||||||
|
|||||||
@@ -1,741 +0,0 @@
|
|||||||
import AdmZip from "adm-zip";
|
|
||||||
import { execSync } from "child_process";
|
|
||||||
import { createHash } from "crypto";
|
|
||||||
import fs from "fs";
|
|
||||||
import fsp from "fs/promises";
|
|
||||||
import { glob } from "glob";
|
|
||||||
import { HttpsProxyAgent } from "https-proxy-agent";
|
|
||||||
import fetch from "node-fetch";
|
|
||||||
import path from "path";
|
|
||||||
import { extract } from "tar";
|
|
||||||
import zlib from "zlib";
|
|
||||||
import { log_debug, log_error, log_info, log_success } from "./utils.mjs";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prebuild script with optimization features:
|
|
||||||
* 1. Skip downloading mihomo core if it already exists (unless --force is used)
|
|
||||||
* 2. Cache version information for 1 hour to avoid repeated version checks
|
|
||||||
* 3. Use file hash to detect changes and skip unnecessary chmod/copy operations
|
|
||||||
* 4. Use --force or -f flag to force re-download and update all resources
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
const cwd = process.cwd();
|
|
||||||
const TEMP_DIR = path.join(cwd, "node_modules/.verge");
|
|
||||||
const FORCE = process.argv.includes("--force") || process.argv.includes("-f");
|
|
||||||
const VERSION_CACHE_FILE = path.join(TEMP_DIR, ".version_cache.json");
|
|
||||||
const HASH_CACHE_FILE = path.join(TEMP_DIR, ".hash_cache.json");
|
|
||||||
|
|
||||||
const PLATFORM_MAP = {
|
|
||||||
"x86_64-pc-windows-msvc": "win32",
|
|
||||||
"i686-pc-windows-msvc": "win32",
|
|
||||||
"aarch64-pc-windows-msvc": "win32",
|
|
||||||
"x86_64-apple-darwin": "darwin",
|
|
||||||
"aarch64-apple-darwin": "darwin",
|
|
||||||
"x86_64-unknown-linux-gnu": "linux",
|
|
||||||
"i686-unknown-linux-gnu": "linux",
|
|
||||||
"aarch64-unknown-linux-gnu": "linux",
|
|
||||||
"armv7-unknown-linux-gnueabihf": "linux",
|
|
||||||
"riscv64gc-unknown-linux-gnu": "linux",
|
|
||||||
"loongarch64-unknown-linux-gnu": "linux",
|
|
||||||
};
|
|
||||||
const ARCH_MAP = {
|
|
||||||
"x86_64-pc-windows-msvc": "x64",
|
|
||||||
"i686-pc-windows-msvc": "ia32",
|
|
||||||
"aarch64-pc-windows-msvc": "arm64",
|
|
||||||
"x86_64-apple-darwin": "x64",
|
|
||||||
"aarch64-apple-darwin": "arm64",
|
|
||||||
"x86_64-unknown-linux-gnu": "x64",
|
|
||||||
"i686-unknown-linux-gnu": "ia32",
|
|
||||||
"aarch64-unknown-linux-gnu": "arm64",
|
|
||||||
"armv7-unknown-linux-gnueabihf": "arm",
|
|
||||||
"riscv64gc-unknown-linux-gnu": "riscv64",
|
|
||||||
"loongarch64-unknown-linux-gnu": "loong64",
|
|
||||||
};
|
|
||||||
|
|
||||||
const arg1 = process.argv.slice(2)[0];
|
|
||||||
const arg2 = process.argv.slice(2)[1];
|
|
||||||
let target = arg1 === "--force" || arg1 === "-f" ? arg2 : arg1;
|
|
||||||
const { platform, arch } = target
|
|
||||||
? { platform: PLATFORM_MAP[target], arch: ARCH_MAP[target] }
|
|
||||||
: process;
|
|
||||||
|
|
||||||
const SIDECAR_HOST = target
|
|
||||||
? target
|
|
||||||
: execSync("rustc -vV")
|
|
||||||
.toString()
|
|
||||||
.match(/(?<=host: ).+(?=\s*)/g)[0];
|
|
||||||
|
|
||||||
// =======================
|
|
||||||
// Version Cache
|
|
||||||
// =======================
|
|
||||||
async function loadVersionCache() {
|
|
||||||
try {
|
|
||||||
if (fs.existsSync(VERSION_CACHE_FILE)) {
|
|
||||||
const data = await fsp.readFile(VERSION_CACHE_FILE, "utf-8");
|
|
||||||
return JSON.parse(data);
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
log_debug("Failed to load version cache:", err.message);
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
async function saveVersionCache(cache) {
|
|
||||||
try {
|
|
||||||
await fsp.mkdir(TEMP_DIR, { recursive: true });
|
|
||||||
await fsp.writeFile(VERSION_CACHE_FILE, JSON.stringify(cache, null, 2));
|
|
||||||
log_debug("Version cache saved");
|
|
||||||
} catch (err) {
|
|
||||||
log_debug("Failed to save version cache:", err.message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async function getCachedVersion(key) {
|
|
||||||
const cache = await loadVersionCache();
|
|
||||||
const cached = cache[key];
|
|
||||||
if (cached && Date.now() - cached.timestamp < 3600000) {
|
|
||||||
log_info(`Using cached version for ${key}: ${cached.version}`);
|
|
||||||
return cached.version;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
async function setCachedVersion(key, version) {
|
|
||||||
const cache = await loadVersionCache();
|
|
||||||
cache[key] = { version, timestamp: Date.now() };
|
|
||||||
await saveVersionCache(cache);
|
|
||||||
}
|
|
||||||
|
|
||||||
// =======================
|
|
||||||
// Hash Cache & File Hash
|
|
||||||
// =======================
|
|
||||||
async function calculateFileHash(filePath) {
|
|
||||||
try {
|
|
||||||
const fileBuffer = await fsp.readFile(filePath);
|
|
||||||
const hashSum = createHash("sha256");
|
|
||||||
hashSum.update(fileBuffer);
|
|
||||||
return hashSum.digest("hex");
|
|
||||||
} catch (err) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async function loadHashCache() {
|
|
||||||
try {
|
|
||||||
if (fs.existsSync(HASH_CACHE_FILE)) {
|
|
||||||
const data = await fsp.readFile(HASH_CACHE_FILE, "utf-8");
|
|
||||||
return JSON.parse(data);
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
log_debug("Failed to load hash cache:", err.message);
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
async function saveHashCache(cache) {
|
|
||||||
try {
|
|
||||||
await fsp.mkdir(TEMP_DIR, { recursive: true });
|
|
||||||
await fsp.writeFile(HASH_CACHE_FILE, JSON.stringify(cache, null, 2));
|
|
||||||
log_debug("Hash cache saved");
|
|
||||||
} catch (err) {
|
|
||||||
log_debug("Failed to save hash cache:", err.message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async function hasFileChanged(filePath, targetPath) {
|
|
||||||
if (FORCE) return true;
|
|
||||||
if (!fs.existsSync(targetPath)) return true;
|
|
||||||
const hashCache = await loadHashCache();
|
|
||||||
const sourceHash = await calculateFileHash(filePath);
|
|
||||||
const targetHash = await calculateFileHash(targetPath);
|
|
||||||
if (!sourceHash || !targetHash) return true;
|
|
||||||
const cacheKey = targetPath;
|
|
||||||
const cachedHash = hashCache[cacheKey];
|
|
||||||
if (cachedHash === sourceHash && sourceHash === targetHash) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
async function updateHashCache(targetPath) {
|
|
||||||
const hashCache = await loadHashCache();
|
|
||||||
const hash = await calculateFileHash(targetPath);
|
|
||||||
if (hash) {
|
|
||||||
hashCache[targetPath] = hash;
|
|
||||||
await saveHashCache(hashCache);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// =======================
|
|
||||||
// Meta maps (stable & alpha)
|
|
||||||
// =======================
|
|
||||||
const META_ALPHA_VERSION_URL =
|
|
||||||
"https://github.com/MetaCubeX/mihomo/releases/download/Prerelease-Alpha/version.txt";
|
|
||||||
const META_ALPHA_URL_PREFIX = `https://github.com/MetaCubeX/mihomo/releases/download/Prerelease-Alpha`;
|
|
||||||
let META_ALPHA_VERSION;
|
|
||||||
|
|
||||||
const META_VERSION_URL =
|
|
||||||
"https://github.com/MetaCubeX/mihomo/releases/latest/download/version.txt";
|
|
||||||
const META_URL_PREFIX = `https://github.com/MetaCubeX/mihomo/releases/download`;
|
|
||||||
let META_VERSION;
|
|
||||||
|
|
||||||
const META_ALPHA_MAP = {
|
|
||||||
"win32-x64": "mihomo-windows-amd64-v2",
|
|
||||||
"win32-ia32": "mihomo-windows-386",
|
|
||||||
"win32-arm64": "mihomo-windows-arm64",
|
|
||||||
"darwin-x64": "mihomo-darwin-amd64-v1-go122",
|
|
||||||
"darwin-arm64": "mihomo-darwin-arm64-go122",
|
|
||||||
"linux-x64": "mihomo-linux-amd64-v2",
|
|
||||||
"linux-ia32": "mihomo-linux-386",
|
|
||||||
"linux-arm64": "mihomo-linux-arm64",
|
|
||||||
"linux-arm": "mihomo-linux-armv7",
|
|
||||||
"linux-riscv64": "mihomo-linux-riscv64",
|
|
||||||
"linux-loong64": "mihomo-linux-loong64",
|
|
||||||
};
|
|
||||||
|
|
||||||
const META_MAP = {
|
|
||||||
"win32-x64": "mihomo-windows-amd64-v2",
|
|
||||||
"win32-ia32": "mihomo-windows-386",
|
|
||||||
"win32-arm64": "mihomo-windows-arm64",
|
|
||||||
"darwin-x64": "mihomo-darwin-amd64-v2-go122",
|
|
||||||
"darwin-arm64": "mihomo-darwin-arm64-go122",
|
|
||||||
"linux-x64": "mihomo-linux-amd64-v2",
|
|
||||||
"linux-ia32": "mihomo-linux-386",
|
|
||||||
"linux-arm64": "mihomo-linux-arm64",
|
|
||||||
"linux-arm": "mihomo-linux-armv7",
|
|
||||||
"linux-riscv64": "mihomo-linux-riscv64",
|
|
||||||
"linux-loong64": "mihomo-linux-loong64",
|
|
||||||
};
|
|
||||||
|
|
||||||
// =======================
|
|
||||||
// Fetch latest versions
|
|
||||||
// =======================
|
|
||||||
async function getLatestAlphaVersion() {
|
|
||||||
if (!FORCE) {
|
|
||||||
const cached = await getCachedVersion("META_ALPHA_VERSION");
|
|
||||||
if (cached) {
|
|
||||||
META_ALPHA_VERSION = cached;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const options = {};
|
|
||||||
const httpProxy =
|
|
||||||
process.env.HTTP_PROXY ||
|
|
||||||
process.env.http_proxy ||
|
|
||||||
process.env.HTTPS_PROXY ||
|
|
||||||
process.env.https_proxy;
|
|
||||||
if (httpProxy) options.agent = new HttpsProxyAgent(httpProxy);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await fetch(META_ALPHA_VERSION_URL, {
|
|
||||||
...options,
|
|
||||||
method: "GET",
|
|
||||||
});
|
|
||||||
if (!response.ok)
|
|
||||||
throw new Error(
|
|
||||||
`Failed to fetch ${META_ALPHA_VERSION_URL}: ${response.status}`,
|
|
||||||
);
|
|
||||||
META_ALPHA_VERSION = (await response.text()).trim();
|
|
||||||
log_info(`Latest alpha version: ${META_ALPHA_VERSION}`);
|
|
||||||
await setCachedVersion("META_ALPHA_VERSION", META_ALPHA_VERSION);
|
|
||||||
} catch (err) {
|
|
||||||
log_error("Error fetching latest alpha version:", err.message);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getLatestReleaseVersion() {
|
|
||||||
if (!FORCE) {
|
|
||||||
const cached = await getCachedVersion("META_VERSION");
|
|
||||||
if (cached) {
|
|
||||||
META_VERSION = cached;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const options = {};
|
|
||||||
const httpProxy =
|
|
||||||
process.env.HTTP_PROXY ||
|
|
||||||
process.env.http_proxy ||
|
|
||||||
process.env.HTTPS_PROXY ||
|
|
||||||
process.env.https_proxy;
|
|
||||||
if (httpProxy) options.agent = new HttpsProxyAgent(httpProxy);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await fetch(META_VERSION_URL, {
|
|
||||||
...options,
|
|
||||||
method: "GET",
|
|
||||||
});
|
|
||||||
if (!response.ok)
|
|
||||||
throw new Error(
|
|
||||||
`Failed to fetch ${META_VERSION_URL}: ${response.status}`,
|
|
||||||
);
|
|
||||||
META_VERSION = (await response.text()).trim();
|
|
||||||
log_info(`Latest release version: ${META_VERSION}`);
|
|
||||||
await setCachedVersion("META_VERSION", META_VERSION);
|
|
||||||
} catch (err) {
|
|
||||||
log_error("Error fetching latest release version:", err.message);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// =======================
|
|
||||||
// Validate availability
|
|
||||||
// =======================
|
|
||||||
if (!META_MAP[`${platform}-${arch}`]) {
|
|
||||||
throw new Error(`clash meta unsupported platform "${platform}-${arch}"`);
|
|
||||||
}
|
|
||||||
if (!META_ALPHA_MAP[`${platform}-${arch}`]) {
|
|
||||||
throw new Error(
|
|
||||||
`clash meta alpha unsupported platform "${platform}-${arch}"`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// =======================
|
|
||||||
// Build meta objects
|
|
||||||
// =======================
|
|
||||||
function clashMetaAlpha() {
|
|
||||||
const name = META_ALPHA_MAP[`${platform}-${arch}`];
|
|
||||||
const isWin = platform === "win32";
|
|
||||||
const urlExt = isWin ? "zip" : "gz";
|
|
||||||
return {
|
|
||||||
name: "verge-mihomo-alpha",
|
|
||||||
targetFile: `verge-mihomo-alpha-${SIDECAR_HOST}${isWin ? ".exe" : ""}`,
|
|
||||||
exeFile: `${name}${isWin ? ".exe" : ""}`,
|
|
||||||
zipFile: `${name}-${META_ALPHA_VERSION}.${urlExt}`,
|
|
||||||
downloadURL: `${META_ALPHA_URL_PREFIX}/${name}-${META_ALPHA_VERSION}.${urlExt}`,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function clashMeta() {
|
|
||||||
const name = META_MAP[`${platform}-${arch}`];
|
|
||||||
const isWin = platform === "win32";
|
|
||||||
const urlExt = isWin ? "zip" : "gz";
|
|
||||||
return {
|
|
||||||
name: "verge-mihomo",
|
|
||||||
targetFile: `verge-mihomo-${SIDECAR_HOST}${isWin ? ".exe" : ""}`,
|
|
||||||
exeFile: `${name}${isWin ? ".exe" : ""}`,
|
|
||||||
zipFile: `${name}-${META_VERSION}.${urlExt}`,
|
|
||||||
downloadURL: `${META_URL_PREFIX}/${META_VERSION}/${name}-${META_VERSION}.${urlExt}`,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// =======================
|
|
||||||
// download helper (增强:status + magic bytes)
|
|
||||||
// =======================
|
|
||||||
async function downloadFile(url, outPath) {
|
|
||||||
const options = {};
|
|
||||||
const httpProxy =
|
|
||||||
process.env.HTTP_PROXY ||
|
|
||||||
process.env.http_proxy ||
|
|
||||||
process.env.HTTPS_PROXY ||
|
|
||||||
process.env.https_proxy;
|
|
||||||
if (httpProxy) options.agent = new HttpsProxyAgent(httpProxy);
|
|
||||||
|
|
||||||
const response = await fetch(url, {
|
|
||||||
...options,
|
|
||||||
method: "GET",
|
|
||||||
headers: { "Content-Type": "application/octet-stream" },
|
|
||||||
});
|
|
||||||
if (!response.ok) {
|
|
||||||
const body = await response.text().catch(() => "");
|
|
||||||
// 将 body 写到文件以便排查(可通过临时目录查看)
|
|
||||||
await fsp.mkdir(path.dirname(outPath), { recursive: true });
|
|
||||||
await fsp.writeFile(outPath, body);
|
|
||||||
throw new Error(`Failed to download ${url}: status ${response.status}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const buf = Buffer.from(await response.arrayBuffer());
|
|
||||||
await fsp.mkdir(path.dirname(outPath), { recursive: true });
|
|
||||||
|
|
||||||
// 简单 magic 字节检查
|
|
||||||
if (url.endsWith(".gz") || url.endsWith(".tgz")) {
|
|
||||||
if (!(buf[0] === 0x1f && buf[1] === 0x8b)) {
|
|
||||||
await fsp.writeFile(outPath, buf);
|
|
||||||
throw new Error(
|
|
||||||
`Downloaded file for ${url} is not a valid gzip (magic mismatch).`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else if (url.endsWith(".zip")) {
|
|
||||||
if (!(buf[0] === 0x50 && buf[1] === 0x4b)) {
|
|
||||||
await fsp.writeFile(outPath, buf);
|
|
||||||
throw new Error(
|
|
||||||
`Downloaded file for ${url} is not a valid zip (magic mismatch).`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await fsp.writeFile(outPath, buf);
|
|
||||||
log_success(`download finished: ${url}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
// =======================
|
|
||||||
// resolveSidecar (支持 zip / tgz / gz)
|
|
||||||
// =======================
|
|
||||||
async function resolveSidecar(binInfo) {
|
|
||||||
const { name, targetFile, zipFile, exeFile, downloadURL } = binInfo;
|
|
||||||
const sidecarDir = path.join(cwd, "src-tauri", "sidecar");
|
|
||||||
const sidecarPath = path.join(sidecarDir, targetFile);
|
|
||||||
await fsp.mkdir(sidecarDir, { recursive: true });
|
|
||||||
|
|
||||||
if (!FORCE && fs.existsSync(sidecarPath)) {
|
|
||||||
log_success(`"${name}" already exists, skipping download`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const tempDir = path.join(TEMP_DIR, name);
|
|
||||||
const tempZip = path.join(tempDir, zipFile);
|
|
||||||
const tempExe = path.join(tempDir, exeFile);
|
|
||||||
await fsp.mkdir(tempDir, { recursive: true });
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (!fs.existsSync(tempZip)) {
|
|
||||||
await downloadFile(downloadURL, tempZip);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (zipFile.endsWith(".zip")) {
|
|
||||||
const zip = new AdmZip(tempZip);
|
|
||||||
zip.getEntries().forEach((entry) => {
|
|
||||||
log_debug(`"${name}" entry: ${entry.entryName}`);
|
|
||||||
});
|
|
||||||
zip.extractAllTo(tempDir, true);
|
|
||||||
// 尝试按 exeFile 重命名,否则找第一个可执行文件
|
|
||||||
if (fs.existsSync(tempExe)) {
|
|
||||||
await fsp.rename(tempExe, sidecarPath);
|
|
||||||
} else {
|
|
||||||
// 搜索候选
|
|
||||||
const files = await fsp.readdir(tempDir);
|
|
||||||
const candidate = files.find(
|
|
||||||
(f) =>
|
|
||||||
f === path.basename(exeFile) ||
|
|
||||||
f.endsWith(".exe") ||
|
|
||||||
!f.includes("."),
|
|
||||||
);
|
|
||||||
if (!candidate)
|
|
||||||
throw new Error(`Expected binary not found in ${tempDir}`);
|
|
||||||
await fsp.rename(path.join(tempDir, candidate), sidecarPath);
|
|
||||||
}
|
|
||||||
if (platform !== "win32") execSync(`chmod 755 ${sidecarPath}`);
|
|
||||||
log_success(`unzip finished: "${name}"`);
|
|
||||||
} else if (zipFile.endsWith(".tgz")) {
|
|
||||||
await extract({ cwd: tempDir, file: tempZip });
|
|
||||||
const files = await fsp.readdir(tempDir);
|
|
||||||
log_debug(`"${name}" extracted files:`, files);
|
|
||||||
// 优先寻找给定 exeFile 或已知前缀
|
|
||||||
let extracted = files.find(
|
|
||||||
(f) =>
|
|
||||||
f === path.basename(exeFile) ||
|
|
||||||
f.startsWith("虚空终端-") ||
|
|
||||||
!f.includes("."),
|
|
||||||
);
|
|
||||||
if (!extracted) extracted = files[0];
|
|
||||||
if (!extracted) throw new Error(`Expected file not found in ${tempDir}`);
|
|
||||||
await fsp.rename(path.join(tempDir, extracted), sidecarPath);
|
|
||||||
execSync(`chmod 755 ${sidecarPath}`);
|
|
||||||
log_success(`tgz processed: "${name}"`);
|
|
||||||
} else {
|
|
||||||
// .gz
|
|
||||||
const readStream = fs.createReadStream(tempZip);
|
|
||||||
const writeStream = fs.createWriteStream(sidecarPath);
|
|
||||||
await new Promise((resolve, reject) => {
|
|
||||||
readStream
|
|
||||||
.pipe(zlib.createGunzip())
|
|
||||||
.on("error", (e) => {
|
|
||||||
log_error(`gunzip error for ${name}:`, e.message);
|
|
||||||
reject(e);
|
|
||||||
})
|
|
||||||
.pipe(writeStream)
|
|
||||||
.on("finish", () => {
|
|
||||||
if (platform !== "win32") execSync(`chmod 755 ${sidecarPath}`);
|
|
||||||
resolve();
|
|
||||||
})
|
|
||||||
.on("error", (e) => {
|
|
||||||
log_error(`write stream error for ${name}:`, e.message);
|
|
||||||
reject(e);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
log_success(`gz binary processed: "${name}"`);
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
await fsp.rm(sidecarPath, { recursive: true, force: true });
|
|
||||||
throw err;
|
|
||||||
} finally {
|
|
||||||
await fsp.rm(tempDir, { recursive: true, force: true });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function resolveResource(binInfo) {
|
|
||||||
const { file, downloadURL, localPath } = binInfo;
|
|
||||||
const resDir = path.join(cwd, "src-tauri/resources");
|
|
||||||
const targetPath = path.join(resDir, file);
|
|
||||||
|
|
||||||
if (!FORCE && fs.existsSync(targetPath) && !downloadURL && !localPath) {
|
|
||||||
log_success(`"${file}" already exists, skipping`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (downloadURL) {
|
|
||||||
if (!FORCE && fs.existsSync(targetPath)) {
|
|
||||||
log_success(`"${file}" already exists, skipping download`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
await fsp.mkdir(resDir, { recursive: true });
|
|
||||||
await downloadFile(downloadURL, targetPath);
|
|
||||||
await updateHashCache(targetPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (localPath) {
|
|
||||||
if (!(await hasFileChanged(localPath, targetPath))) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
await fsp.mkdir(resDir, { recursive: true });
|
|
||||||
await fsp.copyFile(localPath, targetPath);
|
|
||||||
await updateHashCache(targetPath);
|
|
||||||
log_success(`Copied file: ${file}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
log_success(`${file} finished`);
|
|
||||||
}
|
|
||||||
|
|
||||||
// SimpleSC.dll (win plugin)
|
|
||||||
const resolvePlugin = async () => {
|
|
||||||
const url =
|
|
||||||
"https://nsis.sourceforge.io/mediawiki/images/e/ef/NSIS_Simple_Service_Plugin_Unicode_1.30.zip";
|
|
||||||
const tempDir = path.join(TEMP_DIR, "SimpleSC");
|
|
||||||
const tempZip = path.join(
|
|
||||||
tempDir,
|
|
||||||
"NSIS_Simple_Service_Plugin_Unicode_1.30.zip",
|
|
||||||
);
|
|
||||||
const tempDll = path.join(tempDir, "SimpleSC.dll");
|
|
||||||
const pluginDir = path.join(process.env.APPDATA || "", "Local/NSIS");
|
|
||||||
const pluginPath = path.join(pluginDir, "SimpleSC.dll");
|
|
||||||
await fsp.mkdir(pluginDir, { recursive: true });
|
|
||||||
await fsp.mkdir(tempDir, { recursive: true });
|
|
||||||
if (!FORCE && fs.existsSync(pluginPath)) return;
|
|
||||||
try {
|
|
||||||
if (!fs.existsSync(tempZip)) {
|
|
||||||
await downloadFile(url, tempZip);
|
|
||||||
}
|
|
||||||
const zip = new AdmZip(tempZip);
|
|
||||||
zip
|
|
||||||
.getEntries()
|
|
||||||
.forEach((entry) => log_debug(`"SimpleSC" entry`, entry.entryName));
|
|
||||||
zip.extractAllTo(tempDir, true);
|
|
||||||
if (fs.existsSync(tempDll)) {
|
|
||||||
await fsp.cp(tempDll, pluginPath, { recursive: true, force: true });
|
|
||||||
log_success(`unzip finished: "SimpleSC"`);
|
|
||||||
} else {
|
|
||||||
// 如果 dll 名称不同,尝试找到 dll
|
|
||||||
const files = await fsp.readdir(tempDir);
|
|
||||||
const dll = files.find((f) => f.toLowerCase().endsWith(".dll"));
|
|
||||||
if (dll) {
|
|
||||||
await fsp.cp(path.join(tempDir, dll), pluginPath, {
|
|
||||||
recursive: true,
|
|
||||||
force: true,
|
|
||||||
});
|
|
||||||
log_success(`unzip finished: "SimpleSC" (found ${dll})`);
|
|
||||||
} else {
|
|
||||||
throw new Error("SimpleSC.dll not found in zip");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
await fsp.rm(tempDir, { recursive: true, force: true });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// service chmod (保留并使用 glob)
|
|
||||||
const resolveServicePermission = async () => {
|
|
||||||
const serviceExecutables = [
|
|
||||||
"clash-verge-service*",
|
|
||||||
"clash-verge-service-install*",
|
|
||||||
"clash-verge-service-uninstall*",
|
|
||||||
];
|
|
||||||
const resDir = path.join(cwd, "src-tauri/resources");
|
|
||||||
const hashCache = await loadHashCache();
|
|
||||||
let hasChanges = false;
|
|
||||||
|
|
||||||
for (let f of serviceExecutables) {
|
|
||||||
const files = glob.sync(path.join(resDir, f));
|
|
||||||
for (let filePath of files) {
|
|
||||||
if (fs.existsSync(filePath)) {
|
|
||||||
const currentHash = await calculateFileHash(filePath);
|
|
||||||
const cacheKey = `${filePath}_chmod`;
|
|
||||||
if (!FORCE && hashCache[cacheKey] === currentHash) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
execSync(`chmod 755 ${filePath}`);
|
|
||||||
log_success(`chmod finished: "${filePath}"`);
|
|
||||||
} catch (e) {
|
|
||||||
log_error(`chmod failed for ${filePath}:`, e.message);
|
|
||||||
}
|
|
||||||
hashCache[cacheKey] = currentHash;
|
|
||||||
hasChanges = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasChanges) {
|
|
||||||
await saveHashCache(hashCache);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// resolve locales (从 src/locales 复制到 resources/locales,并使用 hash 检查)
|
|
||||||
async function resolveLocales() {
|
|
||||||
const srcLocalesDir = path.join(cwd, "src/locales");
|
|
||||||
const targetLocalesDir = path.join(cwd, "src-tauri/resources/locales");
|
|
||||||
|
|
||||||
try {
|
|
||||||
await fsp.mkdir(targetLocalesDir, { recursive: true });
|
|
||||||
const files = await fsp.readdir(srcLocalesDir);
|
|
||||||
for (const file of files) {
|
|
||||||
const srcPath = path.join(srcLocalesDir, file);
|
|
||||||
const targetPath = path.join(targetLocalesDir, file);
|
|
||||||
if (!(await hasFileChanged(srcPath, targetPath))) continue;
|
|
||||||
await fsp.copyFile(srcPath, targetPath);
|
|
||||||
await updateHashCache(targetPath);
|
|
||||||
log_success(`Copied locale file: ${file}`);
|
|
||||||
}
|
|
||||||
log_success("All locale files processed successfully");
|
|
||||||
} catch (err) {
|
|
||||||
log_error("Error copying locale files:", err.message);
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// =======================
|
|
||||||
// Other resource resolvers (service, mmdb, geosite, geoip, enableLoopback, sysproxy)
|
|
||||||
// =======================
|
|
||||||
const SERVICE_URL = `https://github.com/clash-verge-rev/clash-verge-service-ipc/releases/download/${SIDECAR_HOST}`;
|
|
||||||
const resolveService = () => {
|
|
||||||
let ext = platform === "win32" ? ".exe" : "";
|
|
||||||
let suffix = platform === "linux" ? "-" + SIDECAR_HOST : "";
|
|
||||||
return resolveResource({
|
|
||||||
file: "clash-verge-service" + suffix + ext,
|
|
||||||
downloadURL: `${SERVICE_URL}/clash-verge-service${ext}`,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
const resolveInstall = () => {
|
|
||||||
let ext = platform === "win32" ? ".exe" : "";
|
|
||||||
let suffix = platform === "linux" ? "-" + SIDECAR_HOST : "";
|
|
||||||
return resolveResource({
|
|
||||||
file: "clash-verge-service-install" + suffix + ext,
|
|
||||||
downloadURL: `${SERVICE_URL}/clash-verge-service-install${ext}`,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
const resolveUninstall = () => {
|
|
||||||
let ext = platform === "win32" ? ".exe" : "";
|
|
||||||
let suffix = platform === "linux" ? "-" + SIDECAR_HOST : "";
|
|
||||||
return resolveResource({
|
|
||||||
file: "clash-verge-service-uninstall" + suffix + ext,
|
|
||||||
downloadURL: `${SERVICE_URL}/clash-verge-service-uninstall${ext}`,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const resolveMmdb = () =>
|
|
||||||
resolveResource({
|
|
||||||
file: "Country.mmdb",
|
|
||||||
downloadURL: `https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/country.mmdb`,
|
|
||||||
});
|
|
||||||
const resolveGeosite = () =>
|
|
||||||
resolveResource({
|
|
||||||
file: "geosite.dat",
|
|
||||||
downloadURL: `https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geosite.dat`,
|
|
||||||
});
|
|
||||||
const resolveGeoIP = () =>
|
|
||||||
resolveResource({
|
|
||||||
file: "geoip.dat",
|
|
||||||
downloadURL: `https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.dat`,
|
|
||||||
});
|
|
||||||
const resolveEnableLoopback = () =>
|
|
||||||
resolveResource({
|
|
||||||
file: "enableLoopback.exe",
|
|
||||||
downloadURL: `https://github.com/Kuingsmile/uwp-tool/releases/download/latest/enableLoopback.exe`,
|
|
||||||
});
|
|
||||||
const resolveWinSysproxy = () =>
|
|
||||||
resolveResource({
|
|
||||||
file: "sysproxy.exe",
|
|
||||||
downloadURL: `https://github.com/clash-verge-rev/sysproxy/releases/download/${arch}/sysproxy.exe`,
|
|
||||||
});
|
|
||||||
|
|
||||||
const resolveSetDnsScript = () =>
|
|
||||||
resolveResource({
|
|
||||||
file: "set_dns.sh",
|
|
||||||
localPath: path.join(cwd, "scripts/set_dns.sh"),
|
|
||||||
});
|
|
||||||
const resolveUnSetDnsScript = () =>
|
|
||||||
resolveResource({
|
|
||||||
file: "unset_dns.sh",
|
|
||||||
localPath: path.join(cwd, "scripts/unset_dns.sh"),
|
|
||||||
});
|
|
||||||
|
|
||||||
// =======================
|
|
||||||
// Tasks
|
|
||||||
// =======================
|
|
||||||
const tasks = [
|
|
||||||
{
|
|
||||||
name: "verge-mihomo-alpha",
|
|
||||||
func: () =>
|
|
||||||
getLatestAlphaVersion().then(() => resolveSidecar(clashMetaAlpha())),
|
|
||||||
retry: 5,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "verge-mihomo",
|
|
||||||
func: () =>
|
|
||||||
getLatestReleaseVersion().then(() => resolveSidecar(clashMeta())),
|
|
||||||
retry: 5,
|
|
||||||
},
|
|
||||||
{ name: "plugin", func: resolvePlugin, retry: 5, winOnly: true },
|
|
||||||
{ name: "service", func: resolveService, retry: 5 },
|
|
||||||
{ name: "install", func: resolveInstall, retry: 5 },
|
|
||||||
{ name: "uninstall", func: resolveUninstall, retry: 5 },
|
|
||||||
{ name: "mmdb", func: resolveMmdb, retry: 5 },
|
|
||||||
{ name: "geosite", func: resolveGeosite, retry: 5 },
|
|
||||||
{ name: "geoip", func: resolveGeoIP, retry: 5 },
|
|
||||||
{
|
|
||||||
name: "enableLoopback",
|
|
||||||
func: resolveEnableLoopback,
|
|
||||||
retry: 5,
|
|
||||||
winOnly: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "service_chmod",
|
|
||||||
func: resolveServicePermission,
|
|
||||||
retry: 5,
|
|
||||||
unixOnly: platform === "linux" || platform === "darwin",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "windows-sysproxy",
|
|
||||||
func: resolveWinSysproxy,
|
|
||||||
retry: 5,
|
|
||||||
winOnly: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "set_dns_script",
|
|
||||||
func: resolveSetDnsScript,
|
|
||||||
retry: 5,
|
|
||||||
macosOnly: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "unset_dns_script",
|
|
||||||
func: resolveUnSetDnsScript,
|
|
||||||
retry: 5,
|
|
||||||
macosOnly: true,
|
|
||||||
},
|
|
||||||
{ name: "locales", func: resolveLocales, retry: 2 },
|
|
||||||
];
|
|
||||||
|
|
||||||
async function runTask() {
|
|
||||||
const task = tasks.shift();
|
|
||||||
if (!task) return;
|
|
||||||
if (task.unixOnly && platform === "win32") return runTask();
|
|
||||||
if (task.winOnly && platform !== "win32") return runTask();
|
|
||||||
if (task.macosOnly && platform !== "darwin") return runTask();
|
|
||||||
if (task.linuxOnly && platform !== "linux") return runTask();
|
|
||||||
|
|
||||||
for (let i = 0; i < task.retry; i++) {
|
|
||||||
try {
|
|
||||||
await task.func();
|
|
||||||
break;
|
|
||||||
} catch (err) {
|
|
||||||
log_error(`task::${task.name} try ${i} ==`, err.message);
|
|
||||||
if (i === task.retry - 1) throw err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return runTask();
|
|
||||||
}
|
|
||||||
|
|
||||||
runTask();
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
// scripts/publish-version.mjs
|
|
||||||
import { spawn } from "child_process";
|
|
||||||
import { existsSync } from "fs";
|
|
||||||
import path from "path";
|
|
||||||
|
|
||||||
const rootDir = process.cwd();
|
|
||||||
const scriptPath = path.join(rootDir, "scripts", "release-version.mjs");
|
|
||||||
|
|
||||||
if (!existsSync(scriptPath)) {
|
|
||||||
console.error("release-version.mjs not found!");
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
const versionArg = process.argv[2];
|
|
||||||
if (!versionArg) {
|
|
||||||
console.error("Usage: pnpm publish-version <version>");
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1. 调用 release-version.mjs
|
|
||||||
const runRelease = () =>
|
|
||||||
new Promise((resolve, reject) => {
|
|
||||||
const child = spawn("node", [scriptPath, versionArg], { stdio: "inherit" });
|
|
||||||
child.on("exit", (code) => {
|
|
||||||
if (code === 0) resolve();
|
|
||||||
else reject(new Error("release-version failed"));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// 2. 判断是否需要打 tag
|
|
||||||
function isSemver(version) {
|
|
||||||
return /^v?\d+\.\d+\.\d+(-[0-9A-Za-z-.]+)?$/.test(version);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function run() {
|
|
||||||
await runRelease();
|
|
||||||
|
|
||||||
let tag = null;
|
|
||||||
if (versionArg === "alpha") {
|
|
||||||
// 读取 package.json 里的主版本
|
|
||||||
const pkg = await import(path.join(rootDir, "package.json"), {
|
|
||||||
assert: { type: "json" },
|
|
||||||
});
|
|
||||||
tag = `v${pkg.default.version}-alpha`;
|
|
||||||
} else if (isSemver(versionArg)) {
|
|
||||||
// 1.2.3 或 v1.2.3
|
|
||||||
tag = versionArg.startsWith("v") ? versionArg : `v${versionArg}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tag) {
|
|
||||||
// 打 tag 并推送
|
|
||||||
const { execSync } = await import("child_process");
|
|
||||||
try {
|
|
||||||
execSync(`git tag ${tag}`, { stdio: "inherit" });
|
|
||||||
execSync(`git push origin ${tag}`, { stdio: "inherit" });
|
|
||||||
console.log(`[INFO]: Git tag ${tag} created and pushed.`);
|
|
||||||
} catch {
|
|
||||||
console.error(`[ERROR]: Failed to create or push git tag: ${tag}`);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
console.log("[INFO]: No git tag created for this version.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
run();
|
|
||||||
@@ -1,314 +0,0 @@
|
|||||||
/**
|
|
||||||
* CLI tool to update version numbers in package.json, src-tauri/Cargo.toml, and src-tauri/tauri.conf.json.
|
|
||||||
*
|
|
||||||
* Usage:
|
|
||||||
* pnpm release-version <version>
|
|
||||||
*
|
|
||||||
* <version> can be:
|
|
||||||
* - A full semver version (e.g., 1.2.3, v1.2.3, 1.2.3-beta, v1.2.3+build)
|
|
||||||
* - A tag: "alpha", "beta", "rc", "autobuild", "autobuild-latest", or "deploytest"
|
|
||||||
* - "alpha", "beta", "rc": Appends the tag to the current base version (e.g., 1.2.3-beta)
|
|
||||||
* - "autobuild": Appends a timestamped autobuild tag (e.g., 1.2.3+autobuild.2406101530)
|
|
||||||
* - "autobuild-latest": Appends an autobuild tag with latest Tauri commit (e.g., 1.2.3+autobuild.0614.a1b2c3d)
|
|
||||||
* - "deploytest": Appends a timestamped deploytest tag (e.g., 1.2.3+deploytest.2406101530)
|
|
||||||
*
|
|
||||||
* Examples:
|
|
||||||
* pnpm release-version 1.2.3
|
|
||||||
* pnpm release-version v1.2.3-beta
|
|
||||||
* pnpm release-version beta
|
|
||||||
* pnpm release-version autobuild
|
|
||||||
* pnpm release-version autobuild-latest
|
|
||||||
* pnpm release-version deploytest
|
|
||||||
*
|
|
||||||
* The script will:
|
|
||||||
* - Validate and normalize the version argument
|
|
||||||
* - Update the version field in package.json
|
|
||||||
* - Update the version field in src-tauri/Cargo.toml
|
|
||||||
* - Update the version field in src-tauri/tauri.conf.json
|
|
||||||
*
|
|
||||||
* Errors are logged and the process exits with code 1 on failure.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { execSync } from "child_process";
|
|
||||||
import { program } from "commander";
|
|
||||||
import fs from "fs/promises";
|
|
||||||
import path from "path";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取当前 git 短 commit hash
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
function getGitShortCommit() {
|
|
||||||
try {
|
|
||||||
return execSync("git rev-parse --short HEAD").toString().trim();
|
|
||||||
} catch {
|
|
||||||
console.warn("[WARN]: Failed to get git short commit, fallback to 'nogit'");
|
|
||||||
return "nogit";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取最新 Tauri 相关提交的短 hash
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
function getLatestTauriCommit() {
|
|
||||||
try {
|
|
||||||
const fullHash = execSync(
|
|
||||||
"bash ./scripts-workflow/get_latest_tauri_commit.bash",
|
|
||||||
)
|
|
||||||
.toString()
|
|
||||||
.trim();
|
|
||||||
const shortHash = execSync(`git rev-parse --short ${fullHash}`)
|
|
||||||
.toString()
|
|
||||||
.trim();
|
|
||||||
console.log(`[INFO]: Latest Tauri-related commit: ${shortHash}`);
|
|
||||||
return shortHash;
|
|
||||||
} catch (error) {
|
|
||||||
console.warn(
|
|
||||||
"[WARN]: Failed to get latest Tauri commit, fallback to current git short commit",
|
|
||||||
);
|
|
||||||
console.warn(`[WARN]: Error details: ${error.message}`);
|
|
||||||
return getGitShortCommit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 生成短时间戳(格式:MMDD)或带 commit(格式:MMDD.cc39b27)
|
|
||||||
* 使用 Asia/Shanghai 时区
|
|
||||||
* @param {boolean} withCommit 是否带 commit
|
|
||||||
* @param {boolean} useTauriCommit 是否使用 Tauri 相关的 commit(仅当 withCommit 为 true 时有效)
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
function generateShortTimestamp(withCommit = false, useTauriCommit = false) {
|
|
||||||
const now = new Date();
|
|
||||||
|
|
||||||
const formatter = new Intl.DateTimeFormat("en-CA", {
|
|
||||||
timeZone: "Asia/Shanghai",
|
|
||||||
month: "2-digit",
|
|
||||||
day: "2-digit",
|
|
||||||
});
|
|
||||||
|
|
||||||
const parts = formatter.formatToParts(now);
|
|
||||||
const month = parts.find((part) => part.type === "month").value;
|
|
||||||
const day = parts.find((part) => part.type === "day").value;
|
|
||||||
|
|
||||||
if (withCommit) {
|
|
||||||
const gitShort = useTauriCommit
|
|
||||||
? getLatestTauriCommit()
|
|
||||||
: getGitShortCommit();
|
|
||||||
return `${month}${day}.${gitShort}`;
|
|
||||||
}
|
|
||||||
return `${month}${day}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 验证版本号格式
|
|
||||||
* @param {string} version
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
function isValidVersion(version) {
|
|
||||||
return /^v?\d+\.\d+\.\d+(-(alpha|beta|rc)(\.\d+)?)?(\+[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*)?$/i.test(
|
|
||||||
version,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 标准化版本号
|
|
||||||
* @param {string} version
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
function normalizeVersion(version) {
|
|
||||||
return version.startsWith("v") ? version : `v${version}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 提取基础版本号(去掉所有 -tag 和 +build 部分)
|
|
||||||
* @param {string} version
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
function getBaseVersion(version) {
|
|
||||||
let base = version.replace(/-(alpha|beta|rc)(\.\d+)?/i, "");
|
|
||||||
base = base.replace(/\+[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*/g, "");
|
|
||||||
return base;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新 package.json 版本号
|
|
||||||
* @param {string} newVersion
|
|
||||||
*/
|
|
||||||
async function updatePackageVersion(newVersion) {
|
|
||||||
const _dirname = process.cwd();
|
|
||||||
const packageJsonPath = path.join(_dirname, "package.json");
|
|
||||||
try {
|
|
||||||
const data = await fs.readFile(packageJsonPath, "utf8");
|
|
||||||
const packageJson = JSON.parse(data);
|
|
||||||
|
|
||||||
console.log(
|
|
||||||
"[INFO]: Current package.json version is: ",
|
|
||||||
packageJson.version,
|
|
||||||
);
|
|
||||||
packageJson.version = newVersion.startsWith("v")
|
|
||||||
? newVersion.slice(1)
|
|
||||||
: newVersion;
|
|
||||||
await fs.writeFile(
|
|
||||||
packageJsonPath,
|
|
||||||
JSON.stringify(packageJson, null, 2),
|
|
||||||
"utf8",
|
|
||||||
);
|
|
||||||
console.log(
|
|
||||||
`[INFO]: package.json version updated to: ${packageJson.version}`,
|
|
||||||
);
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error updating package.json version:", error);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新 Cargo.toml 版本号
|
|
||||||
* @param {string} newVersion
|
|
||||||
*/
|
|
||||||
async function updateCargoVersion(newVersion) {
|
|
||||||
const _dirname = process.cwd();
|
|
||||||
const cargoTomlPath = path.join(_dirname, "src-tauri", "Cargo.toml");
|
|
||||||
try {
|
|
||||||
const data = await fs.readFile(cargoTomlPath, "utf8");
|
|
||||||
const lines = data.split("\n");
|
|
||||||
const versionWithoutV = newVersion.startsWith("v")
|
|
||||||
? newVersion.slice(1)
|
|
||||||
: newVersion;
|
|
||||||
|
|
||||||
const updatedLines = lines.map((line) => {
|
|
||||||
if (line.trim().startsWith("version =")) {
|
|
||||||
return line.replace(
|
|
||||||
/version\s*=\s*"[^"]+"/,
|
|
||||||
`version = "${versionWithoutV}"`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return line;
|
|
||||||
});
|
|
||||||
|
|
||||||
await fs.writeFile(cargoTomlPath, updatedLines.join("\n"), "utf8");
|
|
||||||
console.log(`[INFO]: Cargo.toml version updated to: ${versionWithoutV}`);
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error updating Cargo.toml version:", error);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新 tauri.conf.json 版本号
|
|
||||||
* @param {string} newVersion
|
|
||||||
*/
|
|
||||||
async function updateTauriConfigVersion(newVersion) {
|
|
||||||
const _dirname = process.cwd();
|
|
||||||
const tauriConfigPath = path.join(_dirname, "src-tauri", "tauri.conf.json");
|
|
||||||
try {
|
|
||||||
const data = await fs.readFile(tauriConfigPath, "utf8");
|
|
||||||
const tauriConfig = JSON.parse(data);
|
|
||||||
const versionWithoutV = newVersion.startsWith("v")
|
|
||||||
? newVersion.slice(1)
|
|
||||||
: newVersion;
|
|
||||||
|
|
||||||
console.log(
|
|
||||||
"[INFO]: Current tauri.conf.json version is: ",
|
|
||||||
tauriConfig.version,
|
|
||||||
);
|
|
||||||
|
|
||||||
// 使用完整版本信息,包含build metadata
|
|
||||||
tauriConfig.version = versionWithoutV;
|
|
||||||
|
|
||||||
await fs.writeFile(
|
|
||||||
tauriConfigPath,
|
|
||||||
JSON.stringify(tauriConfig, null, 2),
|
|
||||||
"utf8",
|
|
||||||
);
|
|
||||||
console.log(
|
|
||||||
`[INFO]: tauri.conf.json version updated to: ${versionWithoutV}`,
|
|
||||||
);
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error updating tauri.conf.json version:", error);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取当前版本号
|
|
||||||
*/
|
|
||||||
async function getCurrentVersion() {
|
|
||||||
const _dirname = process.cwd();
|
|
||||||
const packageJsonPath = path.join(_dirname, "package.json");
|
|
||||||
try {
|
|
||||||
const data = await fs.readFile(packageJsonPath, "utf8");
|
|
||||||
const packageJson = JSON.parse(data);
|
|
||||||
return packageJson.version;
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error getting current version:", error);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 主函数
|
|
||||||
*/
|
|
||||||
async function main(versionArg) {
|
|
||||||
if (!versionArg) {
|
|
||||||
console.error("Error: Version argument is required");
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
let newVersion;
|
|
||||||
const validTags = [
|
|
||||||
"alpha",
|
|
||||||
"beta",
|
|
||||||
"rc",
|
|
||||||
"autobuild",
|
|
||||||
"autobuild-latest",
|
|
||||||
"deploytest",
|
|
||||||
];
|
|
||||||
|
|
||||||
if (validTags.includes(versionArg.toLowerCase())) {
|
|
||||||
const currentVersion = await getCurrentVersion();
|
|
||||||
const baseVersion = getBaseVersion(currentVersion);
|
|
||||||
|
|
||||||
if (versionArg.toLowerCase() === "autobuild") {
|
|
||||||
// 格式: 2.3.0+autobuild.1004.cc39b27
|
|
||||||
// 使用 Tauri 相关的最新 commit hash
|
|
||||||
newVersion = `${baseVersion}+autobuild.${generateShortTimestamp(true, true)}`;
|
|
||||||
} else if (versionArg.toLowerCase() === "autobuild-latest") {
|
|
||||||
// 格式: 2.3.0+autobuild.1004.a1b2c3d (使用最新 Tauri 提交)
|
|
||||||
const latestTauriCommit = getLatestTauriCommit();
|
|
||||||
newVersion = `${baseVersion}+autobuild.${generateShortTimestamp()}.${latestTauriCommit}`;
|
|
||||||
} else if (versionArg.toLowerCase() === "deploytest") {
|
|
||||||
// 格式: 2.3.0+deploytest.1004.cc39b27
|
|
||||||
// 使用 Tauri 相关的最新 commit hash
|
|
||||||
newVersion = `${baseVersion}+deploytest.${generateShortTimestamp(true, true)}`;
|
|
||||||
} else {
|
|
||||||
newVersion = `${baseVersion}-${versionArg.toLowerCase()}`;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!isValidVersion(versionArg)) {
|
|
||||||
console.error("Error: Invalid version format");
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
newVersion = normalizeVersion(versionArg);
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(`[INFO]: Updating versions to: ${newVersion}`);
|
|
||||||
await updatePackageVersion(newVersion);
|
|
||||||
await updateCargoVersion(newVersion);
|
|
||||||
await updateTauriConfigVersion(newVersion);
|
|
||||||
console.log("[SUCCESS]: All version updates completed successfully!");
|
|
||||||
} catch (error) {
|
|
||||||
console.error("[ERROR]: Failed to update versions:", error);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
program
|
|
||||||
.name("pnpm release-version")
|
|
||||||
.description("Update project version numbers")
|
|
||||||
.argument("<version>", "version tag or full version")
|
|
||||||
.action(main)
|
|
||||||
.parse(process.argv);
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# 验证IPv4地址格式
|
|
||||||
function is_valid_ipv4() {
|
|
||||||
local ip=$1
|
|
||||||
local IFS='.'
|
|
||||||
local -a octets
|
|
||||||
|
|
||||||
[[ ! $ip =~ ^([0-9]+\.){3}[0-9]+$ ]] && return 1
|
|
||||||
read -r -a octets <<<"$ip"
|
|
||||||
[ "${#octets[@]}" -ne 4 ] && return 1
|
|
||||||
|
|
||||||
for octet in "${octets[@]}"; do
|
|
||||||
if ! [[ "$octet" =~ ^[0-9]+$ ]] || ((octet < 0 || octet > 255)); then
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
# 验证IPv6地址格式
|
|
||||||
function is_valid_ipv6() {
|
|
||||||
local ip=$1
|
|
||||||
if [[ ! $ip =~ ^([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}$ ]] &&
|
|
||||||
[[ ! $ip =~ ^(([0-9a-fA-F]{0,4}:){0,7}:|(:[0-9a-fA-F]{0,4}:){0,6}:[0-9a-fA-F]{0,4})$ ]]; then
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
# 验证IP地址是否为有效的IPv4或IPv6
|
|
||||||
function is_valid_ip() {
|
|
||||||
is_valid_ipv4 "$1" || is_valid_ipv6 "$1"
|
|
||||||
}
|
|
||||||
|
|
||||||
# 检查参数
|
|
||||||
[ $# -lt 1 ] && echo "Usage: $0 <IP address>" && exit 1
|
|
||||||
! is_valid_ip "$1" && echo "$1 is not a valid IP address." && exit 1
|
|
||||||
|
|
||||||
# 获取网络接口和硬件端口
|
|
||||||
nic=$(route -n get default | grep "interface" | awk '{print $2}')
|
|
||||||
hardware_port=$(networksetup -listallhardwareports | awk -v dev="$nic" '
|
|
||||||
/Hardware Port:/{port=$0; gsub("Hardware Port: ", "", port)}
|
|
||||||
/Device: /{if ($2 == dev) {print port; exit}}
|
|
||||||
')
|
|
||||||
|
|
||||||
# 获取当前DNS设置
|
|
||||||
original_dns=$(networksetup -getdnsservers "$hardware_port")
|
|
||||||
|
|
||||||
# 检查当前DNS设置是否有效
|
|
||||||
is_valid_dns=false
|
|
||||||
for ip in $original_dns; do
|
|
||||||
ip=$(echo "$ip" | tr -d '[:space:]')
|
|
||||||
if [ -n "$ip" ] && (is_valid_ipv4 "$ip" || is_valid_ipv6 "$ip"); then
|
|
||||||
is_valid_dns=true
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
# 更新DNS设置
|
|
||||||
if [ "$is_valid_dns" = false ]; then
|
|
||||||
echo "empty" >.original_dns.txt
|
|
||||||
else
|
|
||||||
echo "$original_dns" >.original_dns.txt
|
|
||||||
fi
|
|
||||||
networksetup -setdnsservers "$hardware_port" "$1"
|
|
||||||
@@ -1,123 +0,0 @@
|
|||||||
import axios from "axios";
|
|
||||||
import { readFileSync } from "fs";
|
|
||||||
import { log_error, log_info, log_success } from "./utils.mjs";
|
|
||||||
|
|
||||||
const CHAT_ID_RELEASE = "@clash_verge_re"; // 正式发布频道
|
|
||||||
const CHAT_ID_TEST = "@vergetest"; // 测试频道
|
|
||||||
|
|
||||||
async function sendTelegramNotification() {
|
|
||||||
if (!process.env.TELEGRAM_BOT_TOKEN) {
|
|
||||||
throw new Error("TELEGRAM_BOT_TOKEN is required");
|
|
||||||
}
|
|
||||||
|
|
||||||
const version =
|
|
||||||
process.env.VERSION ||
|
|
||||||
(() => {
|
|
||||||
const pkg = readFileSync("package.json", "utf-8");
|
|
||||||
return JSON.parse(pkg).version;
|
|
||||||
})();
|
|
||||||
|
|
||||||
const downloadUrl =
|
|
||||||
process.env.DOWNLOAD_URL ||
|
|
||||||
`https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v${version}`;
|
|
||||||
|
|
||||||
const isAutobuild =
|
|
||||||
process.env.BUILD_TYPE === "autobuild" || version.includes("autobuild");
|
|
||||||
const chatId = isAutobuild ? CHAT_ID_TEST : CHAT_ID_RELEASE;
|
|
||||||
const buildType = isAutobuild ? "滚动更新版" : "正式版";
|
|
||||||
|
|
||||||
log_info(`Preparing Telegram notification for ${buildType} ${version}`);
|
|
||||||
log_info(`Target channel: ${chatId}`);
|
|
||||||
log_info(`Download URL: ${downloadUrl}`);
|
|
||||||
|
|
||||||
// 读取发布说明和下载地址
|
|
||||||
let releaseContent = "";
|
|
||||||
try {
|
|
||||||
releaseContent = readFileSync("release.txt", "utf-8");
|
|
||||||
log_info("成功读取 release.txt 文件");
|
|
||||||
} catch (error) {
|
|
||||||
log_error("无法读取 release.txt,使用默认发布说明", error);
|
|
||||||
releaseContent = "更多新功能现已支持,详细更新日志请查看发布页面。";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Markdown 转换为 HTML
|
|
||||||
function convertMarkdownToTelegramHTML(content) {
|
|
||||||
return content
|
|
||||||
.split("\n")
|
|
||||||
.map((line) => {
|
|
||||||
if (line.trim().length === 0) {
|
|
||||||
return "";
|
|
||||||
} else if (line.startsWith("## ")) {
|
|
||||||
return `<b>${line.replace("## ", "")}</b>`;
|
|
||||||
} else if (line.startsWith("### ")) {
|
|
||||||
return `<b>${line.replace("### ", "")}</b>`;
|
|
||||||
} else if (line.startsWith("#### ")) {
|
|
||||||
return `<b>${line.replace("#### ", "")}</b>`;
|
|
||||||
} else {
|
|
||||||
let processedLine = line.replace(
|
|
||||||
/\[([^\]]+)\]\(([^)]+)\)/g,
|
|
||||||
(match, text, url) => {
|
|
||||||
const encodedUrl = encodeURI(url);
|
|
||||||
return `<a href="${encodedUrl}">${text}</a>`;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
processedLine = processedLine.replace(
|
|
||||||
/\*\*([^*]+)\*\*/g,
|
|
||||||
"<b>$1</b>",
|
|
||||||
);
|
|
||||||
return processedLine;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.join("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
function normalizeDetailsTags(content) {
|
|
||||||
return content
|
|
||||||
.replace(
|
|
||||||
/<summary>\s*<strong>\s*(.*?)\s*<\/strong>\s*<\/summary>/g,
|
|
||||||
"\n<b>$1</b>\n",
|
|
||||||
)
|
|
||||||
.replace(/<summary>\s*(.*?)\s*<\/summary>/g, "\n<b>$1</b>\n")
|
|
||||||
.replace(/<\/?details>/g, "")
|
|
||||||
.replace(/<\/?strong>/g, (m) => (m === "</strong>" ? "</b>" : "<b>"))
|
|
||||||
.replace(/<br\s*\/?>/g, "\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
releaseContent = normalizeDetailsTags(releaseContent);
|
|
||||||
const formattedContent = convertMarkdownToTelegramHTML(releaseContent);
|
|
||||||
|
|
||||||
const releaseTitle = isAutobuild ? "滚动更新版发布" : "正式发布";
|
|
||||||
const encodedVersion = encodeURIComponent(version);
|
|
||||||
const content = `<b>🎉 <a href="https://github.com/clash-verge-rev/clash-verge-rev/releases/tag/autobuild">Clash Verge Rev v${version}</a> ${releaseTitle}</b>\n\n${formattedContent}`;
|
|
||||||
|
|
||||||
// 发送到 Telegram
|
|
||||||
try {
|
|
||||||
await axios.post(
|
|
||||||
`https://api.telegram.org/bot${process.env.TELEGRAM_BOT_TOKEN}/sendMessage`,
|
|
||||||
{
|
|
||||||
chat_id: chatId,
|
|
||||||
text: content,
|
|
||||||
link_preview_options: {
|
|
||||||
is_disabled: false,
|
|
||||||
url: `https://github.com/clash-verge-rev/clash-verge-rev/releases/tag/v${encodedVersion}`,
|
|
||||||
prefer_large_media: true,
|
|
||||||
},
|
|
||||||
parse_mode: "HTML",
|
|
||||||
},
|
|
||||||
);
|
|
||||||
log_success(`✅ Telegram 通知发送成功到 ${chatId}`);
|
|
||||||
} catch (error) {
|
|
||||||
log_error(
|
|
||||||
`❌ Telegram 通知发送失败到 ${chatId}:`,
|
|
||||||
error.response?.data || error.message,
|
|
||||||
error,
|
|
||||||
);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 执行函数
|
|
||||||
sendTelegramNotification().catch((error) => {
|
|
||||||
log_error("脚本执行失败:", error);
|
|
||||||
process.exit(1);
|
|
||||||
});
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
nic=$(route -n get default | grep "interface" | awk '{print $2}')
|
|
||||||
|
|
||||||
hardware_port=$(networksetup -listallhardwareports | awk -v dev="$nic" '
|
|
||||||
/Hardware Port:/{
|
|
||||||
port=$0; gsub("Hardware Port: ", "", port)
|
|
||||||
}
|
|
||||||
/Device: /{
|
|
||||||
if ($2 == dev) {
|
|
||||||
print port;
|
|
||||||
exit
|
|
||||||
}
|
|
||||||
}
|
|
||||||
')
|
|
||||||
|
|
||||||
if [ -f .original_dns.txt ]; then
|
|
||||||
original_dns=$(cat .original_dns.txt)
|
|
||||||
networksetup -setdnsservers "$hardware_port" $original_dns
|
|
||||||
rm -rf .original_dns.txt
|
|
||||||
fi
|
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
import fs from "fs";
|
import fs from "fs-extra";
|
||||||
import fsp from "fs/promises";
|
|
||||||
import path from "path";
|
import path from "path";
|
||||||
|
|
||||||
const UPDATE_LOG = "UPDATELOG.md";
|
const UPDATE_LOG = "UPDATELOG.md";
|
||||||
@@ -8,16 +7,16 @@ const UPDATE_LOG = "UPDATELOG.md";
|
|||||||
export async function resolveUpdateLog(tag) {
|
export async function resolveUpdateLog(tag) {
|
||||||
const cwd = process.cwd();
|
const cwd = process.cwd();
|
||||||
|
|
||||||
const reTitle = /^## v[\d.]+/;
|
const reTitle = /^## v[\d\.]+/;
|
||||||
const reEnd = /^---/;
|
const reEnd = /^---/;
|
||||||
|
|
||||||
const file = path.join(cwd, UPDATE_LOG);
|
const file = path.join(cwd, UPDATE_LOG);
|
||||||
|
|
||||||
if (!fs.existsSync(file)) {
|
if (!(await fs.pathExists(file))) {
|
||||||
throw new Error("could not found UPDATELOG.md");
|
throw new Error("could not found UPDATELOG.md");
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = await fsp.readFile(file, "utf-8");
|
const data = await fs.readFile(file).then((d) => d.toString("utf8"));
|
||||||
|
|
||||||
const map = {};
|
const map = {};
|
||||||
let p = "";
|
let p = "";
|
||||||
@@ -43,42 +42,3 @@ export async function resolveUpdateLog(tag) {
|
|||||||
|
|
||||||
return map[tag].join("\n").trim();
|
return map[tag].join("\n").trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function resolveUpdateLogDefault() {
|
|
||||||
const cwd = process.cwd();
|
|
||||||
const file = path.join(cwd, UPDATE_LOG);
|
|
||||||
|
|
||||||
if (!fs.existsSync(file)) {
|
|
||||||
throw new Error("could not found UPDATELOG.md");
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = await fsp.readFile(file, "utf-8");
|
|
||||||
|
|
||||||
const reTitle = /^## v[\d.]+/;
|
|
||||||
const reEnd = /^---/;
|
|
||||||
|
|
||||||
let isCapturing = false;
|
|
||||||
let content = [];
|
|
||||||
let firstTag = "";
|
|
||||||
|
|
||||||
for (const line of data.split("\n")) {
|
|
||||||
if (reTitle.test(line) && !isCapturing) {
|
|
||||||
isCapturing = true;
|
|
||||||
firstTag = line.slice(3).trim();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isCapturing) {
|
|
||||||
if (reEnd.test(line)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
content.push(line);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!firstTag) {
|
|
||||||
throw new Error("could not found any version tag in UPDATELOG.md");
|
|
||||||
}
|
|
||||||
|
|
||||||
return content.join("\n").trim();
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,157 +0,0 @@
|
|||||||
import fetch from "node-fetch";
|
|
||||||
import { getOctokit, context } from "@actions/github";
|
|
||||||
import { resolveUpdateLog } from "./updatelog.mjs";
|
|
||||||
|
|
||||||
const UPDATE_TAG_NAME = "updater";
|
|
||||||
const UPDATE_JSON_FILE = "update-fixed-webview2.json";
|
|
||||||
const UPDATE_JSON_PROXY = "update-fixed-webview2-proxy.json";
|
|
||||||
|
|
||||||
/// generate update.json
|
|
||||||
/// upload to update tag's release asset
|
|
||||||
async function resolveUpdater() {
|
|
||||||
if (process.env.GITHUB_TOKEN === undefined) {
|
|
||||||
throw new Error("GITHUB_TOKEN is required");
|
|
||||||
}
|
|
||||||
|
|
||||||
const options = { owner: context.repo.owner, repo: context.repo.repo };
|
|
||||||
const github = getOctokit(process.env.GITHUB_TOKEN);
|
|
||||||
|
|
||||||
const { data: tags } = await github.rest.repos.listTags({
|
|
||||||
...options,
|
|
||||||
per_page: 10,
|
|
||||||
page: 1,
|
|
||||||
});
|
|
||||||
|
|
||||||
// get the latest publish tag
|
|
||||||
const tag = tags.find((t) => t.name.startsWith("v"));
|
|
||||||
|
|
||||||
console.log(tag);
|
|
||||||
console.log();
|
|
||||||
|
|
||||||
const { data: latestRelease } = await github.rest.repos.getReleaseByTag({
|
|
||||||
...options,
|
|
||||||
tag: tag.name,
|
|
||||||
});
|
|
||||||
|
|
||||||
const updateData = {
|
|
||||||
name: tag.name,
|
|
||||||
notes: await resolveUpdateLog(tag.name), // use updatelog.md
|
|
||||||
pub_date: new Date().toISOString(),
|
|
||||||
platforms: {
|
|
||||||
"windows-x86_64": { signature: "", url: "" },
|
|
||||||
"windows-aarch64": { signature: "", url: "" },
|
|
||||||
"windows-x86": { signature: "", url: "" },
|
|
||||||
"windows-i686": { signature: "", url: "" },
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const promises = latestRelease.assets.map(async (asset) => {
|
|
||||||
const { name, browser_download_url } = asset;
|
|
||||||
|
|
||||||
// win64 url
|
|
||||||
if (name.endsWith("x64_fixed_webview2-setup.nsis.zip")) {
|
|
||||||
updateData.platforms["windows-x86_64"].url = browser_download_url;
|
|
||||||
}
|
|
||||||
// win64 signature
|
|
||||||
if (name.endsWith("x64_fixed_webview2-setup.nsis.zip.sig")) {
|
|
||||||
const sig = await getSignature(browser_download_url);
|
|
||||||
updateData.platforms["windows-x86_64"].signature = sig;
|
|
||||||
}
|
|
||||||
|
|
||||||
// win32 url
|
|
||||||
if (name.endsWith("x86_fixed_webview2-setup.nsis.zip")) {
|
|
||||||
updateData.platforms["windows-x86"].url = browser_download_url;
|
|
||||||
updateData.platforms["windows-i686"].url = browser_download_url;
|
|
||||||
}
|
|
||||||
// win32 signature
|
|
||||||
if (name.endsWith("x86_fixed_webview2-setup.nsis.zip.sig")) {
|
|
||||||
const sig = await getSignature(browser_download_url);
|
|
||||||
updateData.platforms["windows-x86"].signature = sig;
|
|
||||||
updateData.platforms["windows-i686"].signature = sig;
|
|
||||||
}
|
|
||||||
|
|
||||||
// win arm url
|
|
||||||
if (name.endsWith("arm64_fixed_webview2-setup.nsis.zip")) {
|
|
||||||
updateData.platforms["windows-aarch64"].url = browser_download_url;
|
|
||||||
}
|
|
||||||
// win arm signature
|
|
||||||
if (name.endsWith("arm64_fixed_webview2-setup.nsis.zip.sig")) {
|
|
||||||
const sig = await getSignature(browser_download_url);
|
|
||||||
updateData.platforms["windows-aarch64"].signature = sig;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
await Promise.allSettled(promises);
|
|
||||||
console.log(updateData);
|
|
||||||
|
|
||||||
// maybe should test the signature as well
|
|
||||||
// delete the null field
|
|
||||||
Object.entries(updateData.platforms).forEach(([key, value]) => {
|
|
||||||
if (!value.url) {
|
|
||||||
console.log(`[Error]: failed to parse release for "${key}"`);
|
|
||||||
delete updateData.platforms[key];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 生成一个代理github的更新文件
|
|
||||||
// 使用 https://hub.fastgit.xyz/ 做github资源的加速
|
|
||||||
const updateDataNew = JSON.parse(JSON.stringify(updateData));
|
|
||||||
|
|
||||||
Object.entries(updateDataNew.platforms).forEach(([key, value]) => {
|
|
||||||
if (value.url) {
|
|
||||||
updateDataNew.platforms[key].url =
|
|
||||||
"https://download.clashverge.dev/" + value.url;
|
|
||||||
} else {
|
|
||||||
console.log(`[Error]: updateDataNew.platforms.${key} is null`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// update the update.json
|
|
||||||
const { data: updateRelease } = await github.rest.repos.getReleaseByTag({
|
|
||||||
...options,
|
|
||||||
tag: UPDATE_TAG_NAME,
|
|
||||||
});
|
|
||||||
|
|
||||||
// delete the old assets
|
|
||||||
for (let asset of updateRelease.assets) {
|
|
||||||
if (asset.name === UPDATE_JSON_FILE) {
|
|
||||||
await github.rest.repos.deleteReleaseAsset({
|
|
||||||
...options,
|
|
||||||
asset_id: asset.id,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (asset.name === UPDATE_JSON_PROXY) {
|
|
||||||
await github.rest.repos
|
|
||||||
.deleteReleaseAsset({ ...options, asset_id: asset.id })
|
|
||||||
.catch(console.error); // do not break the pipeline
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// upload new assets
|
|
||||||
await github.rest.repos.uploadReleaseAsset({
|
|
||||||
...options,
|
|
||||||
release_id: updateRelease.id,
|
|
||||||
name: UPDATE_JSON_FILE,
|
|
||||||
data: JSON.stringify(updateData, null, 2),
|
|
||||||
});
|
|
||||||
|
|
||||||
await github.rest.repos.uploadReleaseAsset({
|
|
||||||
...options,
|
|
||||||
release_id: updateRelease.id,
|
|
||||||
name: UPDATE_JSON_PROXY,
|
|
||||||
data: JSON.stringify(updateDataNew, null, 2),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the signature file content
|
|
||||||
async function getSignature(url) {
|
|
||||||
const response = await fetch(url, {
|
|
||||||
method: "GET",
|
|
||||||
headers: { "Content-Type": "application/octet-stream" },
|
|
||||||
});
|
|
||||||
|
|
||||||
return response.text();
|
|
||||||
}
|
|
||||||
|
|
||||||
resolveUpdater().catch(console.error);
|
|
||||||
@@ -1,15 +1,10 @@
|
|||||||
import fetch from "node-fetch";
|
import fetch from "node-fetch";
|
||||||
import { getOctokit, context } from "@actions/github";
|
import { getOctokit, context } from "@actions/github";
|
||||||
import { resolveUpdateLog, resolveUpdateLogDefault } from "./updatelog.mjs";
|
import { resolveUpdateLog } from "./updatelog.mjs";
|
||||||
|
|
||||||
// Add stable update JSON filenames
|
|
||||||
const UPDATE_TAG_NAME = "updater";
|
const UPDATE_TAG_NAME = "updater";
|
||||||
const UPDATE_JSON_FILE = "update.json";
|
const UPDATE_JSON_FILE = "update.json";
|
||||||
const UPDATE_JSON_PROXY = "update-proxy.json";
|
const UPDATE_JSON_PROXY = "update-proxy.json";
|
||||||
// Add alpha update JSON filenames
|
|
||||||
const ALPHA_TAG_NAME = "updater-alpha";
|
|
||||||
const ALPHA_UPDATE_JSON_FILE = "update.json";
|
|
||||||
const ALPHA_UPDATE_JSON_PROXY = "update-proxy.json";
|
|
||||||
|
|
||||||
/// generate update.json
|
/// generate update.json
|
||||||
/// upload to update tag's release asset
|
/// upload to update tag's release asset
|
||||||
@@ -21,293 +16,171 @@ async function resolveUpdater() {
|
|||||||
const options = { owner: context.repo.owner, repo: context.repo.repo };
|
const options = { owner: context.repo.owner, repo: context.repo.repo };
|
||||||
const github = getOctokit(process.env.GITHUB_TOKEN);
|
const github = getOctokit(process.env.GITHUB_TOKEN);
|
||||||
|
|
||||||
// Fetch all tags using pagination
|
const { data: tags } = await github.rest.repos.listTags({
|
||||||
let allTags = [];
|
...options,
|
||||||
let page = 1;
|
per_page: 10,
|
||||||
const perPage = 100;
|
page: 1,
|
||||||
|
});
|
||||||
|
|
||||||
while (true) {
|
// get the latest publish tag
|
||||||
const { data: pageTags } = await github.rest.repos.listTags({
|
const tag = tags.find((t) => t.name.startsWith("v"));
|
||||||
...options,
|
|
||||||
per_page: perPage,
|
|
||||||
page: page,
|
|
||||||
});
|
|
||||||
|
|
||||||
allTags = allTags.concat(pageTags);
|
console.log(tag);
|
||||||
|
|
||||||
// Break if we received fewer tags than requested (last page)
|
|
||||||
if (pageTags.length < perPage) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
page++;
|
|
||||||
}
|
|
||||||
|
|
||||||
const tags = allTags;
|
|
||||||
console.log(`Retrieved ${tags.length} tags in total`);
|
|
||||||
|
|
||||||
// More flexible tag detection with regex patterns
|
|
||||||
const stableTagRegex = /^v\d+\.\d+\.\d+$/; // Matches vX.Y.Z format
|
|
||||||
// const preReleaseRegex = /^v\d+\.\d+\.\d+-(alpha|beta|rc|pre)/i; // Matches vX.Y.Z-alpha/beta/rc format
|
|
||||||
const preReleaseRegex = /^(alpha|beta|rc|pre)$/i; // Matches exact alpha/beta/rc/pre tags
|
|
||||||
|
|
||||||
// Get the latest stable tag and pre-release tag
|
|
||||||
const stableTag = tags.find((t) => stableTagRegex.test(t.name));
|
|
||||||
const preReleaseTag = tags.find((t) => preReleaseRegex.test(t.name));
|
|
||||||
|
|
||||||
console.log("All tags:", tags.map((t) => t.name).join(", "));
|
|
||||||
console.log("Stable tag:", stableTag ? stableTag.name : "None found");
|
|
||||||
console.log(
|
|
||||||
"Pre-release tag:",
|
|
||||||
preReleaseTag ? preReleaseTag.name : "None found",
|
|
||||||
);
|
|
||||||
console.log();
|
console.log();
|
||||||
|
|
||||||
// Process stable release
|
const { data: latestRelease } = await github.rest.repos.getReleaseByTag({
|
||||||
if (stableTag) {
|
...options,
|
||||||
await processRelease(github, options, stableTag, false);
|
tag: tag.name,
|
||||||
}
|
});
|
||||||
|
|
||||||
// Process pre-release if found
|
const updateData = {
|
||||||
if (preReleaseTag) {
|
name: tag.name,
|
||||||
await processRelease(github, options, preReleaseTag, true);
|
notes: await resolveUpdateLog(tag.name), // use updatelog.md
|
||||||
}
|
pub_date: new Date().toISOString(),
|
||||||
}
|
platforms: {
|
||||||
|
win64: { signature: "", url: "" }, // compatible with older formats
|
||||||
|
linux: { signature: "", url: "" }, // compatible with older formats
|
||||||
|
darwin: { signature: "", url: "" }, // compatible with older formats
|
||||||
|
"darwin-aarch64": { signature: "", url: "" },
|
||||||
|
"darwin-intel": { signature: "", url: "" },
|
||||||
|
"darwin-x86_64": { signature: "", url: "" },
|
||||||
|
"linux-x86_64": { signature: "", url: "" },
|
||||||
|
"linux-aarch64": { signature: "", url: "" },
|
||||||
|
"linux-armv7": { signature: "", url: "" },
|
||||||
|
"windows-x86_64": { signature: "", url: "" },
|
||||||
|
"windows-aarch64": { signature: "", url: "" },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
// Process a release (stable or alpha) and generate update files
|
const promises = latestRelease.assets.map(async (asset) => {
|
||||||
async function processRelease(github, options, tag, isAlpha) {
|
const { name, browser_download_url } = asset;
|
||||||
if (!tag) return;
|
|
||||||
|
|
||||||
try {
|
// win64 url
|
||||||
const { data: release } = await github.rest.repos.getReleaseByTag({
|
if (name.endsWith("x64-setup.nsis.zip")) {
|
||||||
...options,
|
updateData.platforms.win64.url = browser_download_url;
|
||||||
tag: tag.name,
|
updateData.platforms["windows-x86_64"].url = browser_download_url;
|
||||||
});
|
|
||||||
|
|
||||||
const updateData = {
|
|
||||||
name: tag.name,
|
|
||||||
notes: await resolveUpdateLog(tag.name).catch(() =>
|
|
||||||
resolveUpdateLogDefault().catch(() => "No changelog available"),
|
|
||||||
),
|
|
||||||
pub_date: new Date().toISOString(),
|
|
||||||
platforms: {
|
|
||||||
win64: { signature: "", url: "" }, // compatible with older formats
|
|
||||||
linux: { signature: "", url: "" }, // compatible with older formats
|
|
||||||
darwin: { signature: "", url: "" }, // compatible with older formats
|
|
||||||
"darwin-aarch64": { signature: "", url: "" },
|
|
||||||
"darwin-intel": { signature: "", url: "" },
|
|
||||||
"darwin-x86_64": { signature: "", url: "" },
|
|
||||||
"linux-x86_64": { signature: "", url: "" },
|
|
||||||
"linux-x86": { signature: "", url: "" },
|
|
||||||
"linux-i686": { signature: "", url: "" },
|
|
||||||
"linux-aarch64": { signature: "", url: "" },
|
|
||||||
"linux-armv7": { signature: "", url: "" },
|
|
||||||
"windows-x86_64": { signature: "", url: "" },
|
|
||||||
"windows-aarch64": { signature: "", url: "" },
|
|
||||||
"windows-x86": { signature: "", url: "" },
|
|
||||||
"windows-i686": { signature: "", url: "" },
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const promises = release.assets.map(async (asset) => {
|
|
||||||
const { name, browser_download_url } = asset;
|
|
||||||
|
|
||||||
// Process all the platform URL and signature data
|
|
||||||
// win64 url
|
|
||||||
if (name.endsWith("x64-setup.exe")) {
|
|
||||||
updateData.platforms.win64.url = browser_download_url;
|
|
||||||
updateData.platforms["windows-x86_64"].url = browser_download_url;
|
|
||||||
}
|
|
||||||
// win64 signature
|
|
||||||
if (name.endsWith("x64-setup.exe.sig")) {
|
|
||||||
const sig = await getSignature(browser_download_url);
|
|
||||||
updateData.platforms.win64.signature = sig;
|
|
||||||
updateData.platforms["windows-x86_64"].signature = sig;
|
|
||||||
}
|
|
||||||
|
|
||||||
// win32 url
|
|
||||||
if (name.endsWith("x86-setup.exe")) {
|
|
||||||
updateData.platforms["windows-x86"].url = browser_download_url;
|
|
||||||
updateData.platforms["windows-i686"].url = browser_download_url;
|
|
||||||
}
|
|
||||||
// win32 signature
|
|
||||||
if (name.endsWith("x86-setup.exe.sig")) {
|
|
||||||
const sig = await getSignature(browser_download_url);
|
|
||||||
updateData.platforms["windows-x86"].signature = sig;
|
|
||||||
updateData.platforms["windows-i686"].signature = sig;
|
|
||||||
}
|
|
||||||
|
|
||||||
// win arm url
|
|
||||||
if (name.endsWith("arm64-setup.exe")) {
|
|
||||||
updateData.platforms["windows-aarch64"].url = browser_download_url;
|
|
||||||
}
|
|
||||||
// win arm signature
|
|
||||||
if (name.endsWith("arm64-setup.exe.sig")) {
|
|
||||||
const sig = await getSignature(browser_download_url);
|
|
||||||
updateData.platforms["windows-aarch64"].signature = sig;
|
|
||||||
}
|
|
||||||
|
|
||||||
// darwin url (intel)
|
|
||||||
if (name.endsWith(".app.tar.gz") && !name.includes("aarch")) {
|
|
||||||
updateData.platforms.darwin.url = browser_download_url;
|
|
||||||
updateData.platforms["darwin-intel"].url = browser_download_url;
|
|
||||||
updateData.platforms["darwin-x86_64"].url = browser_download_url;
|
|
||||||
}
|
|
||||||
// darwin signature (intel)
|
|
||||||
if (name.endsWith(".app.tar.gz.sig") && !name.includes("aarch")) {
|
|
||||||
const sig = await getSignature(browser_download_url);
|
|
||||||
updateData.platforms.darwin.signature = sig;
|
|
||||||
updateData.platforms["darwin-intel"].signature = sig;
|
|
||||||
updateData.platforms["darwin-x86_64"].signature = sig;
|
|
||||||
}
|
|
||||||
|
|
||||||
// darwin url (aarch)
|
|
||||||
if (name.endsWith("aarch64.app.tar.gz")) {
|
|
||||||
updateData.platforms["darwin-aarch64"].url = browser_download_url;
|
|
||||||
// 使linux可以检查更新
|
|
||||||
updateData.platforms.linux.url = browser_download_url;
|
|
||||||
updateData.platforms["linux-x86_64"].url = browser_download_url;
|
|
||||||
updateData.platforms["linux-x86"].url = browser_download_url;
|
|
||||||
updateData.platforms["linux-i686"].url = browser_download_url;
|
|
||||||
updateData.platforms["linux-aarch64"].url = browser_download_url;
|
|
||||||
updateData.platforms["linux-armv7"].url = browser_download_url;
|
|
||||||
}
|
|
||||||
// darwin signature (aarch)
|
|
||||||
if (name.endsWith("aarch64.app.tar.gz.sig")) {
|
|
||||||
const sig = await getSignature(browser_download_url);
|
|
||||||
updateData.platforms["darwin-aarch64"].signature = sig;
|
|
||||||
updateData.platforms.linux.signature = sig;
|
|
||||||
updateData.platforms["linux-x86_64"].signature = sig;
|
|
||||||
updateData.platforms["linux-x86"].url = browser_download_url;
|
|
||||||
updateData.platforms["linux-i686"].url = browser_download_url;
|
|
||||||
updateData.platforms["linux-aarch64"].signature = sig;
|
|
||||||
updateData.platforms["linux-armv7"].signature = sig;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
await Promise.allSettled(promises);
|
|
||||||
console.log(updateData);
|
|
||||||
|
|
||||||
// maybe should test the signature as well
|
|
||||||
// delete the null field
|
|
||||||
Object.entries(updateData.platforms).forEach(([key, value]) => {
|
|
||||||
if (!value.url) {
|
|
||||||
console.log(`[Error]: failed to parse release for "${key}"`);
|
|
||||||
delete updateData.platforms[key];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Generate a proxy update file for accelerated GitHub resources
|
|
||||||
const updateDataNew = JSON.parse(JSON.stringify(updateData));
|
|
||||||
|
|
||||||
Object.entries(updateDataNew.platforms).forEach(([key, value]) => {
|
|
||||||
if (value.url) {
|
|
||||||
updateDataNew.platforms[key].url =
|
|
||||||
"https://download.clashverge.dev/" + value.url;
|
|
||||||
} else {
|
|
||||||
console.log(`[Error]: updateDataNew.platforms.${key} is null`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Get the appropriate updater release based on isAlpha flag
|
|
||||||
const releaseTag = isAlpha ? ALPHA_TAG_NAME : UPDATE_TAG_NAME;
|
|
||||||
console.log(
|
|
||||||
`Processing ${isAlpha ? "alpha" : "stable"} release:`,
|
|
||||||
releaseTag,
|
|
||||||
);
|
|
||||||
|
|
||||||
try {
|
|
||||||
let updateRelease;
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Try to get the existing release
|
|
||||||
const response = await github.rest.repos.getReleaseByTag({
|
|
||||||
...options,
|
|
||||||
tag: releaseTag,
|
|
||||||
});
|
|
||||||
updateRelease = response.data;
|
|
||||||
console.log(
|
|
||||||
`Found existing ${releaseTag} release with ID: ${updateRelease.id}`,
|
|
||||||
);
|
|
||||||
} catch (error) {
|
|
||||||
// If release doesn't exist, create it
|
|
||||||
if (error.status === 404) {
|
|
||||||
console.log(
|
|
||||||
`Release with tag ${releaseTag} not found, creating new release...`,
|
|
||||||
);
|
|
||||||
const createResponse = await github.rest.repos.createRelease({
|
|
||||||
...options,
|
|
||||||
tag_name: releaseTag,
|
|
||||||
name: isAlpha
|
|
||||||
? "Auto-update Alpha Channel"
|
|
||||||
: "Auto-update Stable Channel",
|
|
||||||
body: `This release contains the update information for ${isAlpha ? "alpha" : "stable"} channel.`,
|
|
||||||
prerelease: isAlpha,
|
|
||||||
});
|
|
||||||
updateRelease = createResponse.data;
|
|
||||||
console.log(
|
|
||||||
`Created new ${releaseTag} release with ID: ${updateRelease.id}`,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// If it's another error, throw it
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// File names based on release type
|
|
||||||
const jsonFile = isAlpha ? ALPHA_UPDATE_JSON_FILE : UPDATE_JSON_FILE;
|
|
||||||
const proxyFile = isAlpha ? ALPHA_UPDATE_JSON_PROXY : UPDATE_JSON_PROXY;
|
|
||||||
|
|
||||||
// Delete existing assets with these names
|
|
||||||
for (let asset of updateRelease.assets) {
|
|
||||||
if (asset.name === jsonFile) {
|
|
||||||
await github.rest.repos.deleteReleaseAsset({
|
|
||||||
...options,
|
|
||||||
asset_id: asset.id,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (asset.name === proxyFile) {
|
|
||||||
await github.rest.repos
|
|
||||||
.deleteReleaseAsset({ ...options, asset_id: asset.id })
|
|
||||||
.catch(console.error); // do not break the pipeline
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Upload new assets
|
|
||||||
await github.rest.repos.uploadReleaseAsset({
|
|
||||||
...options,
|
|
||||||
release_id: updateRelease.id,
|
|
||||||
name: jsonFile,
|
|
||||||
data: JSON.stringify(updateData, null, 2),
|
|
||||||
});
|
|
||||||
|
|
||||||
await github.rest.repos.uploadReleaseAsset({
|
|
||||||
...options,
|
|
||||||
release_id: updateRelease.id,
|
|
||||||
name: proxyFile,
|
|
||||||
data: JSON.stringify(updateDataNew, null, 2),
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log(
|
|
||||||
`Successfully uploaded ${isAlpha ? "alpha" : "stable"} update files to ${releaseTag}`,
|
|
||||||
);
|
|
||||||
} catch (error) {
|
|
||||||
console.error(
|
|
||||||
`Failed to process ${isAlpha ? "alpha" : "stable"} release:`,
|
|
||||||
error.message,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
// win64 signature
|
||||||
if (error.status === 404) {
|
if (name.endsWith("x64-setup.nsis.zip.sig")) {
|
||||||
console.log(`Release not found for tag: ${tag.name}, skipping...`);
|
const sig = await getSignature(browser_download_url);
|
||||||
|
updateData.platforms.win64.signature = sig;
|
||||||
|
updateData.platforms["windows-x86_64"].signature = sig;
|
||||||
|
}
|
||||||
|
|
||||||
|
// win arm url
|
||||||
|
if (name.endsWith("arm64-setup.nsis.zip")) {
|
||||||
|
updateData.platforms["windows-aarch64"].url = browser_download_url;
|
||||||
|
}
|
||||||
|
// win arm signature
|
||||||
|
if (name.endsWith("arm64-setup.nsis.zip.sig")) {
|
||||||
|
const sig = await getSignature(browser_download_url);
|
||||||
|
updateData.platforms["windows-aarch64"].signature = sig;
|
||||||
|
}
|
||||||
|
|
||||||
|
// darwin url (intel)
|
||||||
|
if (name.endsWith(".app.tar.gz") && !name.includes("aarch")) {
|
||||||
|
updateData.platforms.darwin.url = browser_download_url;
|
||||||
|
updateData.platforms["darwin-intel"].url = browser_download_url;
|
||||||
|
updateData.platforms["darwin-x86_64"].url = browser_download_url;
|
||||||
|
}
|
||||||
|
// darwin signature (intel)
|
||||||
|
if (name.endsWith(".app.tar.gz.sig") && !name.includes("aarch")) {
|
||||||
|
const sig = await getSignature(browser_download_url);
|
||||||
|
updateData.platforms.darwin.signature = sig;
|
||||||
|
updateData.platforms["darwin-intel"].signature = sig;
|
||||||
|
updateData.platforms["darwin-x86_64"].signature = sig;
|
||||||
|
}
|
||||||
|
|
||||||
|
// darwin url (aarch)
|
||||||
|
if (name.endsWith("aarch64.app.tar.gz")) {
|
||||||
|
updateData.platforms["darwin-aarch64"].url = browser_download_url;
|
||||||
|
}
|
||||||
|
// darwin signature (aarch)
|
||||||
|
if (name.endsWith("aarch64.app.tar.gz.sig")) {
|
||||||
|
const sig = await getSignature(browser_download_url);
|
||||||
|
updateData.platforms["darwin-aarch64"].signature = sig;
|
||||||
|
}
|
||||||
|
|
||||||
|
// linux x64 url
|
||||||
|
if (name.endsWith("amd64.AppImage.tar.gz")) {
|
||||||
|
updateData.platforms.linux.url = browser_download_url;
|
||||||
|
updateData.platforms["linux-x86_64"].url = browser_download_url;
|
||||||
|
// 暂时使用x64版本的url和sig,使得可以检查更新,但aarch64版本还不支持构建appimage
|
||||||
|
updateData.platforms["linux-aarch64"].url = browser_download_url;
|
||||||
|
updateData.platforms["linux-armv7"].url = browser_download_url;
|
||||||
|
}
|
||||||
|
// linux x64 signature
|
||||||
|
if (name.endsWith("amd64.AppImage.tar.gz.sig")) {
|
||||||
|
const sig = await getSignature(browser_download_url);
|
||||||
|
updateData.platforms.linux.signature = sig;
|
||||||
|
updateData.platforms["linux-x86_64"].signature = sig;
|
||||||
|
// 暂时使用x64版本的url和sig,使得可以检查更新,但aarch64版本还不支持构建appimage
|
||||||
|
updateData.platforms["linux-aarch64"].signature = sig;
|
||||||
|
updateData.platforms["linux-armv7"].signature = sig;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
await Promise.allSettled(promises);
|
||||||
|
console.log(updateData);
|
||||||
|
|
||||||
|
// maybe should test the signature as well
|
||||||
|
// delete the null field
|
||||||
|
Object.entries(updateData.platforms).forEach(([key, value]) => {
|
||||||
|
if (!value.url) {
|
||||||
|
console.log(`[Error]: failed to parse release for "${key}"`);
|
||||||
|
delete updateData.platforms[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 生成一个代理github的更新文件
|
||||||
|
// 使用 https://hub.fastgit.xyz/ 做github资源的加速
|
||||||
|
const updateDataNew = JSON.parse(JSON.stringify(updateData));
|
||||||
|
|
||||||
|
Object.entries(updateDataNew.platforms).forEach(([key, value]) => {
|
||||||
|
if (value.url) {
|
||||||
|
updateDataNew.platforms[key].url =
|
||||||
|
"https://mirror.ghproxy.com/" + value.url;
|
||||||
} else {
|
} else {
|
||||||
console.error(
|
console.log(`[Error]: updateDataNew.platforms.${key} is null`);
|
||||||
`Failed to get release for tag: ${tag.name}`,
|
}
|
||||||
error.message,
|
});
|
||||||
);
|
|
||||||
|
// update the update.json
|
||||||
|
const { data: updateRelease } = await github.rest.repos.getReleaseByTag({
|
||||||
|
...options,
|
||||||
|
tag: UPDATE_TAG_NAME,
|
||||||
|
});
|
||||||
|
|
||||||
|
// delete the old assets
|
||||||
|
for (let asset of updateRelease.assets) {
|
||||||
|
if (asset.name === UPDATE_JSON_FILE) {
|
||||||
|
await github.rest.repos.deleteReleaseAsset({
|
||||||
|
...options,
|
||||||
|
asset_id: asset.id,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (asset.name === UPDATE_JSON_PROXY) {
|
||||||
|
await github.rest.repos
|
||||||
|
.deleteReleaseAsset({ ...options, asset_id: asset.id })
|
||||||
|
.catch(console.error); // do not break the pipeline
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// upload new assets
|
||||||
|
await github.rest.repos.uploadReleaseAsset({
|
||||||
|
...options,
|
||||||
|
release_id: updateRelease.id,
|
||||||
|
name: UPDATE_JSON_FILE,
|
||||||
|
data: JSON.stringify(updateData, null, 2),
|
||||||
|
});
|
||||||
|
|
||||||
|
await github.rest.repos.uploadReleaseAsset({
|
||||||
|
...options,
|
||||||
|
release_id: updateRelease.id,
|
||||||
|
name: UPDATE_JSON_PROXY,
|
||||||
|
data: JSON.stringify(updateDataNew, null, 2),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the signature file content
|
// get the signature file content
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
import clc from "cli-color";
|
|
||||||
|
|
||||||
export const log_success = (msg, ...optionalParams) =>
|
|
||||||
console.log(clc.green(msg), ...optionalParams);
|
|
||||||
export const log_error = (msg, ...optionalParams) =>
|
|
||||||
console.log(clc.red(msg), ...optionalParams);
|
|
||||||
export const log_info = (msg, ...optionalParams) =>
|
|
||||||
console.log(clc.bgBlue(msg), ...optionalParams);
|
|
||||||
var debugMsg = clc.xterm(245);
|
|
||||||
export const log_debug = (msg, ...optionalParams) =>
|
|
||||||
console.log(debugMsg(msg), ...optionalParams);
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
avoid-breaking-exported-api = true
|
|
||||||
cognitive-complexity-threshold = 25
|
|
||||||
2
src-tauri/.gitignore
vendored
@@ -1,8 +1,6 @@
|
|||||||
# Generated by Cargo
|
# Generated by Cargo
|
||||||
# will have compiled files and executables
|
# will have compiled files and executables
|
||||||
/target/
|
/target/
|
||||||
gen/
|
|
||||||
WixTools
|
WixTools
|
||||||
resources
|
resources
|
||||||
sidecar
|
sidecar
|
||||||
|
|
||||||
|
|||||||
7303
src-tauri/Cargo.lock
generated
231
src-tauri/Cargo.toml
Executable file → Normal file
@@ -1,227 +1,60 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "clash-verge"
|
name = "clash-verge"
|
||||||
version = "2.4.3"
|
version = "1.6.1"
|
||||||
description = "clash verge"
|
description = "clash verge"
|
||||||
authors = ["zzzgydi", "Tunglies", "wonfen", "MystiPanda"]
|
authors = ["zzzgydi", "wonfen", "MystiPanda"]
|
||||||
license = "GPL-3.0-only"
|
license = "GPL-3.0-only"
|
||||||
repository = "https://github.com/clash-verge-rev/clash-verge-rev.git"
|
repository = "https://github.com/clash-verge-rev/clash-verge-rev.git"
|
||||||
default-run = "clash-verge"
|
default-run = "clash-verge"
|
||||||
edition = "2024"
|
edition = "2021"
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
|
|
||||||
[package.metadata.bundle]
|
|
||||||
identifier = "io.github.clash-verge-rev.clash-verge-rev"
|
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
tauri-build = { version = "2.5.1", features = [] }
|
tauri-build = { version = "1", features = [] }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
warp = { version = "0.4.2", features = ["server"] }
|
warp = "0.3"
|
||||||
anyhow = "1.0.100"
|
anyhow = "1.0"
|
||||||
open = "5.3.2"
|
dirs = "5.0"
|
||||||
log = "0.4.28"
|
open = "5.0"
|
||||||
dunce = "1.0.5"
|
log = "0.4"
|
||||||
|
dunce = "1.0"
|
||||||
|
log4rs = "1"
|
||||||
nanoid = "0.4"
|
nanoid = "0.4"
|
||||||
chrono = "0.4.42"
|
chrono = "0.4"
|
||||||
sysinfo = { version = "0.37.2", features = ["network", "system"] }
|
sysinfo = "0.30"
|
||||||
boa_engine = "0.21.0"
|
boa_engine = "0.18"
|
||||||
serde_json = "1.0.145"
|
serde_json = "1.0"
|
||||||
serde_yaml_ng = "0.10.0"
|
serde_yaml = "0.9"
|
||||||
once_cell = "1.21.3"
|
once_cell = "1.18"
|
||||||
port_scanner = "0.1.5"
|
port_scanner = "0.1.5"
|
||||||
delay_timer = "0.11.6"
|
delay_timer = "0.11.5"
|
||||||
parking_lot = "0.12.5"
|
parking_lot = "0.12"
|
||||||
percent-encoding = "2.3.2"
|
percent-encoding = "2.3.1"
|
||||||
tokio = { version = "1.48.0", features = [
|
window-shadows = { version = "0.2" }
|
||||||
"rt-multi-thread",
|
tokio = { version = "1", features = ["full"] }
|
||||||
"macros",
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
"time",
|
reqwest = { version = "0.12", features = ["json", "rustls-tls"] }
|
||||||
"sync",
|
sysproxy = { git="https://github.com/zzzgydi/sysproxy-rs", branch = "main" }
|
||||||
] }
|
auto-launch = { git="https://github.com/zzzgydi/auto-launch", branch = "main" }
|
||||||
serde = { version = "1.0.228", features = ["derive"] }
|
tauri = { version = "1.6", features = [ "fs-read-file", "fs-exists", "path-all", "protocol-asset", "dialog-open", "notification-all", "icon-png", "icon-ico", "clipboard-all", "global-shortcut-all", "process-all", "shell-all", "system-tray", "updater", "window-all", "devtools"] }
|
||||||
reqwest = { version = "0.12.24", features = ["json", "cookies"] }
|
|
||||||
regex = "1.12.2"
|
|
||||||
sysproxy = { git = "https://github.com/clash-verge-rev/sysproxy-rs" }
|
|
||||||
tauri = { version = "2.9.2", features = [
|
|
||||||
"protocol-asset",
|
|
||||||
"devtools",
|
|
||||||
"tray-icon",
|
|
||||||
"image-ico",
|
|
||||||
"image-png",
|
|
||||||
] }
|
|
||||||
network-interface = { version = "2.0.3", features = ["serde"] }
|
|
||||||
tauri-plugin-shell = "2.3.3"
|
|
||||||
tauri-plugin-dialog = "2.4.2"
|
|
||||||
tauri-plugin-fs = "2.4.4"
|
|
||||||
tauri-plugin-process = "2.3.1"
|
|
||||||
tauri-plugin-clipboard-manager = "2.3.2"
|
|
||||||
tauri-plugin-deep-link = "2.4.5"
|
|
||||||
tauri-plugin-window-state = "2.4.1"
|
|
||||||
zip = "6.0.0"
|
|
||||||
reqwest_dav = "0.2.2"
|
|
||||||
aes-gcm = { version = "0.10.3", features = ["std"] }
|
|
||||||
base64 = "0.22.1"
|
|
||||||
getrandom = "0.3.4"
|
|
||||||
futures = "0.3.31"
|
|
||||||
sys-locale = "0.3.2"
|
|
||||||
libc = "0.2.177"
|
|
||||||
gethostname = "1.1.0"
|
|
||||||
scopeguard = "1.2.0"
|
|
||||||
tauri-plugin-notification = "2.3.3"
|
|
||||||
tokio-stream = "0.1.17"
|
|
||||||
isahc = { version = "1.7.2", default-features = false, features = [
|
|
||||||
"text-decoding",
|
|
||||||
"parking_lot",
|
|
||||||
] }
|
|
||||||
backoff = { version = "0.4.0", features = ["tokio"] }
|
|
||||||
compact_str = { version = "0.9.0", features = ["serde"] }
|
|
||||||
tauri-plugin-http = "2.5.4"
|
|
||||||
flexi_logger = "0.31.7"
|
|
||||||
console-subscriber = { version = "0.5.0", optional = true }
|
|
||||||
tauri-plugin-devtools = { version = "2.0.1" }
|
|
||||||
tauri-plugin-mihomo = { git = "https://github.com/clash-verge-rev/tauri-plugin-mihomo" }
|
|
||||||
clash_verge_logger = { git = "https://github.com/clash-verge-rev/clash-verge-logger" }
|
|
||||||
async-trait = "0.1.89"
|
|
||||||
smartstring = { version = "1.0.1", features = ["serde"] }
|
|
||||||
clash_verge_service_ipc = { version = "2.0.21", features = [
|
|
||||||
"client",
|
|
||||||
], git = "https://github.com/clash-verge-rev/clash-verge-service-ipc" }
|
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
runas = "=1.2.0"
|
runas = "=1.2.0"
|
||||||
deelevate = "0.2.0"
|
deelevate = "0.2.0"
|
||||||
winreg = "0.55.0"
|
winreg = "0.52.0"
|
||||||
winapi = { version = "0.3.9", features = [
|
|
||||||
"winbase",
|
|
||||||
"fileapi",
|
|
||||||
"winnt",
|
|
||||||
"handleapi",
|
|
||||||
"errhandlingapi",
|
|
||||||
"minwindef",
|
|
||||||
"winerror",
|
|
||||||
"tlhelp32",
|
|
||||||
"processthreadsapi",
|
|
||||||
"winhttp",
|
|
||||||
"winreg",
|
|
||||||
] }
|
|
||||||
windows-sys = { version = "0.61.2", features = [
|
|
||||||
"Win32_Foundation",
|
|
||||||
"Win32_Graphics_Gdi",
|
|
||||||
"Win32_System_SystemServices",
|
|
||||||
"Win32_UI_WindowsAndMessaging",
|
|
||||||
] }
|
|
||||||
|
|
||||||
[target.'cfg(target_os = "linux")'.dependencies]
|
[target.'cfg(target_os = "linux")'.dependencies]
|
||||||
users = "0.11.0"
|
users = "0.11.0"
|
||||||
|
#openssl
|
||||||
[target.'cfg(unix)'.dependencies]
|
|
||||||
signal-hook = "0.3.18"
|
|
||||||
|
|
||||||
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies]
|
|
||||||
tauri-plugin-autostart = "2.5.1"
|
|
||||||
tauri-plugin-global-shortcut = "2.3.1"
|
|
||||||
tauri-plugin-updater = "2.9.0"
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["custom-protocol"]
|
default = ["custom-protocol"]
|
||||||
custom-protocol = ["tauri/custom-protocol"]
|
custom-protocol = ["tauri/custom-protocol"]
|
||||||
verge-dev = ["clash_verge_logger/color"]
|
verge-dev = []
|
||||||
tauri-dev = []
|
|
||||||
tokio-trace = ["console-subscriber"]
|
|
||||||
clippy = ["tauri/test"]
|
|
||||||
tracing = []
|
|
||||||
|
|
||||||
[[bench]]
|
|
||||||
name = "draft_benchmark"
|
|
||||||
path = "benches/draft_benchmark.rs"
|
|
||||||
harness = false
|
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
panic = "abort"
|
panic = "abort"
|
||||||
codegen-units = 1
|
codegen-units = 1
|
||||||
lto = "thin"
|
lto = true
|
||||||
opt-level = 3
|
opt-level = "s"
|
||||||
debug = false
|
|
||||||
strip = true
|
|
||||||
overflow-checks = false
|
|
||||||
rpath = false
|
|
||||||
|
|
||||||
[profile.dev]
|
|
||||||
incremental = true
|
|
||||||
codegen-units = 64
|
|
||||||
opt-level = 0
|
|
||||||
debug = true
|
|
||||||
strip = "none"
|
|
||||||
overflow-checks = true
|
|
||||||
lto = false
|
|
||||||
rpath = false
|
|
||||||
|
|
||||||
[profile.fast-release]
|
|
||||||
inherits = "release"
|
|
||||||
codegen-units = 64
|
|
||||||
incremental = true
|
|
||||||
lto = false
|
|
||||||
opt-level = 0
|
|
||||||
debug = true
|
|
||||||
strip = false
|
|
||||||
|
|
||||||
[lib]
|
|
||||||
name = "app_lib"
|
|
||||||
crate-type = ["staticlib", "cdylib", "rlib"]
|
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
criterion = { version = "0.7.0", features = ["async_tokio"] }
|
|
||||||
|
|
||||||
[lints.clippy]
|
|
||||||
# Core categories - most important for code safety and correctness
|
|
||||||
correctness = { level = "deny", priority = -1 }
|
|
||||||
suspicious = { level = "deny", priority = -1 }
|
|
||||||
|
|
||||||
# Critical safety lints - warn for now due to extensive existing usage
|
|
||||||
unwrap_used = "warn"
|
|
||||||
expect_used = "warn"
|
|
||||||
panic = "deny"
|
|
||||||
unimplemented = "deny"
|
|
||||||
|
|
||||||
# Development quality lints
|
|
||||||
todo = "warn"
|
|
||||||
dbg_macro = "warn"
|
|
||||||
#print_stdout = "warn"
|
|
||||||
#print_stderr = "warn"
|
|
||||||
|
|
||||||
# Performance lints for proxy application
|
|
||||||
clone_on_ref_ptr = "warn"
|
|
||||||
rc_clone_in_vec_init = "warn"
|
|
||||||
large_stack_arrays = "warn"
|
|
||||||
large_const_arrays = "warn"
|
|
||||||
|
|
||||||
# Security lints
|
|
||||||
#integer_division = "warn"
|
|
||||||
#lossy_float_literal = "warn"
|
|
||||||
#default_numeric_fallback = "warn"
|
|
||||||
|
|
||||||
# Mutex and async lints - strict control
|
|
||||||
async_yields_async = "deny" # Prevents missing await in async blocks
|
|
||||||
mutex_atomic = "deny" # Use atomics instead of Mutex<bool/int>
|
|
||||||
mutex_integer = "deny" # Use AtomicInt instead of Mutex<int>
|
|
||||||
rc_mutex = "deny" # Single-threaded Rc with Mutex is wrong
|
|
||||||
unused_async = "deny" # Too many false positives in Tauri/framework code
|
|
||||||
await_holding_lock = "deny"
|
|
||||||
large_futures = "deny"
|
|
||||||
future_not_send = "deny"
|
|
||||||
|
|
||||||
# Common style improvements
|
|
||||||
redundant_else = "deny" # Too many in existing code
|
|
||||||
needless_continue = "deny" # Too many in existing code
|
|
||||||
needless_raw_string_hashes = "deny" # Too many in existing code
|
|
||||||
|
|
||||||
# Disable noisy categories for existing codebase but keep them available
|
|
||||||
#style = { level = "allow", priority = -1 }
|
|
||||||
#complexity = { level = "allow", priority = -1 }
|
|
||||||
#perf = { level = "allow", priority = -1 }
|
|
||||||
#pedantic = { level = "allow", priority = -1 }
|
|
||||||
#nursery = { level = "allow", priority = -1 }
|
|
||||||
#restriction = { level = "allow", priority = -1 }
|
|
||||||
|
|
||||||
or_fun_call = "deny"
|
|
||||||
cognitive_complexity = "deny"
|
|
||||||
|
|||||||
17
src-tauri/Info.plist
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleURLTypes</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleURLName</key>
|
||||||
|
<string>Clash Verge</string>
|
||||||
|
<key>CFBundleURLSchemes</key>
|
||||||
|
<array>
|
||||||
|
<string>clash</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@@ -1,111 +0,0 @@
|
|||||||
use criterion::{Criterion, criterion_group, criterion_main};
|
|
||||||
use std::hint::black_box;
|
|
||||||
use std::process;
|
|
||||||
use tokio::runtime::Runtime;
|
|
||||||
|
|
||||||
use app_lib::config::IVerge;
|
|
||||||
use app_lib::utils::Draft as DraftNew;
|
|
||||||
|
|
||||||
/// 创建测试数据
|
|
||||||
fn make_draft() -> DraftNew<Box<IVerge>> {
|
|
||||||
let verge = Box::new(IVerge {
|
|
||||||
enable_auto_launch: Some(true),
|
|
||||||
enable_tun_mode: Some(false),
|
|
||||||
..Default::default()
|
|
||||||
});
|
|
||||||
DraftNew::from(verge)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn bench_draft(c: &mut Criterion) {
|
|
||||||
let rt = Runtime::new().unwrap_or_else(|e| {
|
|
||||||
eprintln!("Tokio runtime init failed: {e}");
|
|
||||||
process::exit(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
let mut group = c.benchmark_group("draft");
|
|
||||||
group.sample_size(100);
|
|
||||||
group.warm_up_time(std::time::Duration::from_millis(300));
|
|
||||||
group.measurement_time(std::time::Duration::from_secs(1));
|
|
||||||
|
|
||||||
group.bench_function("data_mut", |b| {
|
|
||||||
b.iter(|| {
|
|
||||||
let draft = black_box(make_draft());
|
|
||||||
let mut data = draft.data_mut();
|
|
||||||
data.enable_tun_mode = Some(true);
|
|
||||||
black_box(&data.enable_tun_mode);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
group.bench_function("draft_mut_first", |b| {
|
|
||||||
b.iter(|| {
|
|
||||||
let draft = black_box(make_draft());
|
|
||||||
let mut d = draft.draft_mut();
|
|
||||||
d.enable_auto_launch = Some(false);
|
|
||||||
black_box(&d.enable_auto_launch);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
group.bench_function("draft_mut_existing", |b| {
|
|
||||||
b.iter(|| {
|
|
||||||
let draft = black_box(make_draft());
|
|
||||||
{
|
|
||||||
let mut first = draft.draft_mut();
|
|
||||||
first.enable_tun_mode = Some(true);
|
|
||||||
black_box(&first.enable_tun_mode);
|
|
||||||
}
|
|
||||||
let mut second = draft.draft_mut();
|
|
||||||
second.enable_tun_mode = Some(false);
|
|
||||||
black_box(&second.enable_tun_mode);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
group.bench_function("latest_ref", |b| {
|
|
||||||
b.iter(|| {
|
|
||||||
let draft = black_box(make_draft());
|
|
||||||
let latest = draft.latest_ref();
|
|
||||||
black_box(&latest.enable_auto_launch);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
group.bench_function("apply", |b| {
|
|
||||||
b.iter(|| {
|
|
||||||
let draft = black_box(make_draft());
|
|
||||||
{
|
|
||||||
let mut d = draft.draft_mut();
|
|
||||||
d.enable_auto_launch = Some(false);
|
|
||||||
}
|
|
||||||
draft.apply();
|
|
||||||
black_box(&draft);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
group.bench_function("discard", |b| {
|
|
||||||
b.iter(|| {
|
|
||||||
let draft = black_box(make_draft());
|
|
||||||
{
|
|
||||||
let mut d = draft.draft_mut();
|
|
||||||
d.enable_auto_launch = Some(false);
|
|
||||||
}
|
|
||||||
draft.discard();
|
|
||||||
black_box(&draft);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
group.bench_function("with_data_modify_async", |b| {
|
|
||||||
b.to_async(&rt).iter(|| async {
|
|
||||||
let draft = black_box(make_draft());
|
|
||||||
let _: Result<(), anyhow::Error> = draft
|
|
||||||
.with_data_modify::<_, _, _, anyhow::Error>(|mut box_data| async move {
|
|
||||||
box_data.enable_auto_launch =
|
|
||||||
Some(!box_data.enable_auto_launch.unwrap_or(false));
|
|
||||||
Ok((box_data, ()))
|
|
||||||
})
|
|
||||||
.await;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
group.finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
criterion_group!(benches, bench_draft);
|
|
||||||
criterion_main!(benches);
|
|
||||||
@@ -1,9 +1,3 @@
|
|||||||
fn main() {
|
fn main() {
|
||||||
#[cfg(feature = "clippy")]
|
tauri_build::build()
|
||||||
{
|
|
||||||
println!("cargo:warning=Skipping tauri_build during Clippy");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(feature = "clippy"))]
|
|
||||||
tauri_build::build();
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"identifier": "desktop-windows-capability",
|
|
||||||
"description": "permissions for desktop windows applications",
|
|
||||||
"windows": ["main"],
|
|
||||||
"permissions": [
|
|
||||||
"core:webview:allow-create-webview",
|
|
||||||
"core:webview:allow-create-webview-window"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
{
|
|
||||||
"identifier": "desktop-capability",
|
|
||||||
"platforms": ["macOS", "windows", "linux"],
|
|
||||||
"webviews": ["main"],
|
|
||||||
"windows": ["main"],
|
|
||||||
"permissions": [
|
|
||||||
"global-shortcut:default",
|
|
||||||
"updater:default",
|
|
||||||
"dialog:default",
|
|
||||||
"dialog:allow-ask",
|
|
||||||
"dialog:allow-message",
|
|
||||||
"updater:default",
|
|
||||||
"updater:allow-check",
|
|
||||||
"updater:allow-download-and-install",
|
|
||||||
"process:allow-restart",
|
|
||||||
"deep-link:default",
|
|
||||||
"autostart:allow-enable",
|
|
||||||
"autostart:allow-disable",
|
|
||||||
"autostart:allow-is-enabled",
|
|
||||||
"core:window:allow-set-theme",
|
|
||||||
"notification:default",
|
|
||||||
"http:default",
|
|
||||||
"http:allow-fetch",
|
|
||||||
{
|
|
||||||
"identifier": "http:default",
|
|
||||||
"allow": [{ "url": "https://*/*" }, { "url": "http://*/*" }]
|
|
||||||
},
|
|
||||||
"mihomo:default"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
{
|
|
||||||
"identifier": "migrated",
|
|
||||||
"description": "permissions that were migrated from v1",
|
|
||||||
"local": true,
|
|
||||||
"windows": ["main"],
|
|
||||||
"permissions": [
|
|
||||||
"core:default",
|
|
||||||
"fs:allow-read-file",
|
|
||||||
"fs:allow-exists",
|
|
||||||
{
|
|
||||||
"identifier": "fs:scope",
|
|
||||||
"allow": ["$APPDATA/**", "$RESOURCE/../**", "**"]
|
|
||||||
},
|
|
||||||
"fs:allow-write-file",
|
|
||||||
{
|
|
||||||
"identifier": "fs:scope",
|
|
||||||
"allow": ["$APPDATA/**", "$RESOURCE/../**", "**"]
|
|
||||||
},
|
|
||||||
"fs:allow-app-read",
|
|
||||||
"fs:allow-app-read-recursive",
|
|
||||||
"fs:allow-appcache-read",
|
|
||||||
"fs:allow-appcache-read-recursive",
|
|
||||||
"fs:allow-appconfig-read",
|
|
||||||
"fs:allow-appconfig-read-recursive",
|
|
||||||
"core:window:allow-create",
|
|
||||||
"core:window:allow-center",
|
|
||||||
"core:window:allow-request-user-attention",
|
|
||||||
"core:window:allow-set-resizable",
|
|
||||||
"core:window:allow-set-maximizable",
|
|
||||||
"core:window:allow-set-minimizable",
|
|
||||||
"core:window:allow-set-closable",
|
|
||||||
"core:window:allow-set-title",
|
|
||||||
"core:window:allow-maximize",
|
|
||||||
"core:window:allow-unmaximize",
|
|
||||||
"core:window:allow-minimize",
|
|
||||||
"core:window:allow-unminimize",
|
|
||||||
"core:window:allow-show",
|
|
||||||
"core:window:allow-hide",
|
|
||||||
"core:window:allow-close",
|
|
||||||
"core:window:allow-set-decorations",
|
|
||||||
"core:window:allow-set-always-on-top",
|
|
||||||
"core:window:allow-set-content-protected",
|
|
||||||
"core:window:allow-set-size",
|
|
||||||
"core:window:allow-set-min-size",
|
|
||||||
"core:window:allow-set-max-size",
|
|
||||||
"core:window:allow-set-position",
|
|
||||||
"core:window:allow-set-fullscreen",
|
|
||||||
"core:window:allow-set-focus",
|
|
||||||
"core:window:allow-set-icon",
|
|
||||||
"core:window:allow-set-skip-taskbar",
|
|
||||||
"core:window:allow-set-cursor-grab",
|
|
||||||
"core:window:allow-set-cursor-visible",
|
|
||||||
"core:window:allow-set-cursor-icon",
|
|
||||||
"core:window:allow-set-cursor-position",
|
|
||||||
"core:window:allow-set-ignore-cursor-events",
|
|
||||||
"core:window:allow-start-dragging",
|
|
||||||
"core:window:allow-maximize",
|
|
||||||
"core:window:allow-toggle-maximize",
|
|
||||||
"core:window:allow-unmaximize",
|
|
||||||
"core:window:allow-minimize",
|
|
||||||
"core:window:allow-unminimize",
|
|
||||||
"core:window:allow-set-maximizable",
|
|
||||||
"core:window:allow-set-minimizable",
|
|
||||||
"core:webview:allow-print",
|
|
||||||
"shell:allow-execute",
|
|
||||||
"shell:allow-open",
|
|
||||||
"shell:allow-kill",
|
|
||||||
"shell:allow-spawn",
|
|
||||||
"shell:allow-stdin-write",
|
|
||||||
"dialog:allow-open",
|
|
||||||
"global-shortcut:allow-is-registered",
|
|
||||||
"global-shortcut:allow-register",
|
|
||||||
"global-shortcut:allow-register-all",
|
|
||||||
"global-shortcut:allow-unregister",
|
|
||||||
"global-shortcut:allow-unregister-all",
|
|
||||||
"process:allow-restart",
|
|
||||||
"process:allow-exit",
|
|
||||||
"clipboard-manager:allow-read-text",
|
|
||||||
"clipboard-manager:allow-write-text",
|
|
||||||
"shell:default",
|
|
||||||
"dialog:default"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,236 +0,0 @@
|
|||||||
# This template contains all of the possible sections and their default values
|
|
||||||
|
|
||||||
# Note that all fields that take a lint level have these possible values:
|
|
||||||
# * deny - An error will be produced and the check will fail
|
|
||||||
# * warn - A warning will be produced, but the check will not fail
|
|
||||||
# * allow - No warning or error will be produced, though in some cases a note
|
|
||||||
# will be
|
|
||||||
|
|
||||||
# The values provided in this template are the default values that will be used
|
|
||||||
# when any section or field is not specified in your own configuration
|
|
||||||
|
|
||||||
# Root options
|
|
||||||
|
|
||||||
# The graph table configures how the dependency graph is constructed and thus
|
|
||||||
# which crates the checks are performed against
|
|
||||||
[graph]
|
|
||||||
# If 1 or more target triples (and optionally, target_features) are specified,
|
|
||||||
# only the specified targets will be checked when running `cargo deny check`.
|
|
||||||
# This means, if a particular package is only ever used as a target specific
|
|
||||||
# dependency, such as, for example, the `nix` crate only being used via the
|
|
||||||
# `target_family = "unix"` configuration, that only having windows targets in
|
|
||||||
# this list would mean the nix crate, as well as any of its exclusive
|
|
||||||
# dependencies not shared by any other crates, would be ignored, as the target
|
|
||||||
# list here is effectively saying which targets you are building for.
|
|
||||||
targets = [
|
|
||||||
# The triple can be any string, but only the target triples built in to
|
|
||||||
# rustc (as of 1.40) can be checked against actual config expressions
|
|
||||||
#"x86_64-unknown-linux-musl",
|
|
||||||
# You can also specify which target_features you promise are enabled for a
|
|
||||||
# particular target. target_features are currently not validated against
|
|
||||||
# the actual valid features supported by the target architecture.
|
|
||||||
#{ triple = "wasm32-unknown-unknown", features = ["atomics"] },
|
|
||||||
]
|
|
||||||
# When creating the dependency graph used as the source of truth when checks are
|
|
||||||
# executed, this field can be used to prune crates from the graph, removing them
|
|
||||||
# from the view of cargo-deny. This is an extremely heavy hammer, as if a crate
|
|
||||||
# is pruned from the graph, all of its dependencies will also be pruned unless
|
|
||||||
# they are connected to another crate in the graph that hasn't been pruned,
|
|
||||||
# so it should be used with care. The identifiers are [Package ID Specifications]
|
|
||||||
# (https://doc.rust-lang.org/cargo/reference/pkgid-spec.html)
|
|
||||||
#exclude = []
|
|
||||||
# If true, metadata will be collected with `--all-features`. Note that this can't
|
|
||||||
# be toggled off if true, if you want to conditionally enable `--all-features` it
|
|
||||||
# is recommended to pass `--all-features` on the cmd line instead
|
|
||||||
all-features = false
|
|
||||||
# If true, metadata will be collected with `--no-default-features`. The same
|
|
||||||
# caveat with `all-features` applies
|
|
||||||
no-default-features = false
|
|
||||||
# If set, these feature will be enabled when collecting metadata. If `--features`
|
|
||||||
# is specified on the cmd line they will take precedence over this option.
|
|
||||||
#features = []
|
|
||||||
|
|
||||||
# The output table provides options for how/if diagnostics are outputted
|
|
||||||
[output]
|
|
||||||
# When outputting inclusion graphs in diagnostics that include features, this
|
|
||||||
# option can be used to specify the depth at which feature edges will be added.
|
|
||||||
# This option is included since the graphs can be quite large and the addition
|
|
||||||
# of features from the crate(s) to all of the graph roots can be far too verbose.
|
|
||||||
# This option can be overridden via `--feature-depth` on the cmd line
|
|
||||||
feature-depth = 1
|
|
||||||
|
|
||||||
# This section is considered when running `cargo deny check advisories`
|
|
||||||
# More documentation for the advisories section can be found here:
|
|
||||||
# https://embarkstudios.github.io/cargo-deny/checks/advisories/cfg.html
|
|
||||||
[advisories]
|
|
||||||
# The path where the advisory databases are cloned/fetched into
|
|
||||||
#db-path = "$CARGO_HOME/advisory-dbs"
|
|
||||||
# The url(s) of the advisory databases to use
|
|
||||||
#db-urls = ["https://github.com/rustsec/advisory-db"]
|
|
||||||
# A list of advisory IDs to ignore. Note that ignored advisories will still
|
|
||||||
# output a note when they are encountered.
|
|
||||||
ignore = [
|
|
||||||
#"RUSTSEC-0000-0000",
|
|
||||||
#{ id = "RUSTSEC-0000-0000", reason = "you can specify a reason the advisory is ignored" },
|
|
||||||
#"a-crate-that-is-yanked@0.1.1", # you can also ignore yanked crate versions if you wish
|
|
||||||
#{ crate = "a-crate-that-is-yanked@0.1.1", reason = "you can specify why you are ignoring the yanked crate" },
|
|
||||||
"RUSTSEC-2024-0415",
|
|
||||||
]
|
|
||||||
# If this is true, then cargo deny will use the git executable to fetch advisory database.
|
|
||||||
# If this is false, then it uses a built-in git library.
|
|
||||||
# Setting this to true can be helpful if you have special authentication requirements that cargo-deny does not support.
|
|
||||||
# See Git Authentication for more information about setting up git authentication.
|
|
||||||
#git-fetch-with-cli = true
|
|
||||||
|
|
||||||
# This section is considered when running `cargo deny check licenses`
|
|
||||||
# More documentation for the licenses section can be found here:
|
|
||||||
# https://embarkstudios.github.io/cargo-deny/checks/licenses/cfg.html
|
|
||||||
[licenses]
|
|
||||||
# List of explicitly allowed licenses
|
|
||||||
# See https://spdx.org/licenses/ for list of possible licenses
|
|
||||||
# [possible values: any SPDX 3.11 short identifier (+ optional exception)].
|
|
||||||
allow = [
|
|
||||||
#"MIT",
|
|
||||||
#"Apache-2.0",
|
|
||||||
#"Apache-2.0 WITH LLVM-exception",
|
|
||||||
]
|
|
||||||
# The confidence threshold for detecting a license from license text.
|
|
||||||
# The higher the value, the more closely the license text must be to the
|
|
||||||
# canonical license text of a valid SPDX license file.
|
|
||||||
# [possible values: any between 0.0 and 1.0].
|
|
||||||
confidence-threshold = 0.85
|
|
||||||
# Allow 1 or more licenses on a per-crate basis, so that particular licenses
|
|
||||||
# aren't accepted for every possible crate as with the normal allow list
|
|
||||||
exceptions = [
|
|
||||||
# Each entry is the crate and version constraint, and its specific allow
|
|
||||||
# list
|
|
||||||
#{ allow = ["Zlib"], crate = "adler32" },
|
|
||||||
]
|
|
||||||
|
|
||||||
# Some crates don't have (easily) machine readable licensing information,
|
|
||||||
# adding a clarification entry for it allows you to manually specify the
|
|
||||||
# licensing information
|
|
||||||
#[[licenses.clarify]]
|
|
||||||
# The package spec the clarification applies to
|
|
||||||
#crate = "ring"
|
|
||||||
# The SPDX expression for the license requirements of the crate
|
|
||||||
#expression = "MIT AND ISC AND OpenSSL"
|
|
||||||
# One or more files in the crate's source used as the "source of truth" for
|
|
||||||
# the license expression. If the contents match, the clarification will be used
|
|
||||||
# when running the license check, otherwise the clarification will be ignored
|
|
||||||
# and the crate will be checked normally, which may produce warnings or errors
|
|
||||||
# depending on the rest of your configuration
|
|
||||||
#license-files = [
|
|
||||||
# Each entry is a crate relative path, and the (opaque) hash of its contents
|
|
||||||
#{ path = "LICENSE", hash = 0xbd0eed23 }
|
|
||||||
#]
|
|
||||||
|
|
||||||
[licenses.private]
|
|
||||||
# If true, ignores workspace crates that aren't published, or are only
|
|
||||||
# published to private registries.
|
|
||||||
# To see how to mark a crate as unpublished (to the official registry),
|
|
||||||
# visit https://doc.rust-lang.org/cargo/reference/manifest.html#the-publish-field.
|
|
||||||
ignore = false
|
|
||||||
# One or more private registries that you might publish crates to, if a crate
|
|
||||||
# is only published to private registries, and ignore is true, the crate will
|
|
||||||
# not have its license(s) checked
|
|
||||||
registries = [
|
|
||||||
#"https://sekretz.com/registry
|
|
||||||
]
|
|
||||||
|
|
||||||
# This section is considered when running `cargo deny check bans`.
|
|
||||||
# More documentation about the 'bans' section can be found here:
|
|
||||||
# https://embarkstudios.github.io/cargo-deny/checks/bans/cfg.html
|
|
||||||
[bans]
|
|
||||||
# Lint level for when multiple versions of the same crate are detected
|
|
||||||
multiple-versions = "warn"
|
|
||||||
# Lint level for when a crate version requirement is `*`
|
|
||||||
wildcards = "allow"
|
|
||||||
# The graph highlighting used when creating dotgraphs for crates
|
|
||||||
# with multiple versions
|
|
||||||
# * lowest-version - The path to the lowest versioned duplicate is highlighted
|
|
||||||
# * simplest-path - The path to the version with the fewest edges is highlighted
|
|
||||||
# * all - Both lowest-version and simplest-path are used
|
|
||||||
highlight = "all"
|
|
||||||
# The default lint level for `default` features for crates that are members of
|
|
||||||
# the workspace that is being checked. This can be overridden by allowing/denying
|
|
||||||
# `default` on a crate-by-crate basis if desired.
|
|
||||||
workspace-default-features = "allow"
|
|
||||||
# The default lint level for `default` features for external crates that are not
|
|
||||||
# members of the workspace. This can be overridden by allowing/denying `default`
|
|
||||||
# on a crate-by-crate basis if desired.
|
|
||||||
external-default-features = "allow"
|
|
||||||
# List of crates that are allowed. Use with care!
|
|
||||||
allow = [
|
|
||||||
#"ansi_term@0.11.0",
|
|
||||||
#{ crate = "ansi_term@0.11.0", reason = "you can specify a reason it is allowed" },
|
|
||||||
]
|
|
||||||
# List of crates to deny
|
|
||||||
deny = [
|
|
||||||
#"ansi_term@0.11.0",
|
|
||||||
#{ crate = "ansi_term@0.11.0", reason = "you can specify a reason it is banned" },
|
|
||||||
# Wrapper crates can optionally be specified to allow the crate when it
|
|
||||||
# is a direct dependency of the otherwise banned crate
|
|
||||||
#{ crate = "ansi_term@0.11.0", wrappers = ["this-crate-directly-depends-on-ansi_term"] },
|
|
||||||
]
|
|
||||||
|
|
||||||
# List of features to allow/deny
|
|
||||||
# Each entry the name of a crate and a version range. If version is
|
|
||||||
# not specified, all versions will be matched.
|
|
||||||
#[[bans.features]]
|
|
||||||
#crate = "reqwest"
|
|
||||||
# Features to not allow
|
|
||||||
#deny = ["json"]
|
|
||||||
# Features to allow
|
|
||||||
#allow = [
|
|
||||||
# "rustls",
|
|
||||||
# "__rustls",
|
|
||||||
# "__tls",
|
|
||||||
# "hyper-rustls",
|
|
||||||
# "rustls",
|
|
||||||
# "rustls-pemfile",
|
|
||||||
# "rustls-tls-webpki-roots",
|
|
||||||
# "tokio-rustls",
|
|
||||||
# "webpki-roots",
|
|
||||||
#]
|
|
||||||
# If true, the allowed features must exactly match the enabled feature set. If
|
|
||||||
# this is set there is no point setting `deny`
|
|
||||||
#exact = true
|
|
||||||
|
|
||||||
# Certain crates/versions that will be skipped when doing duplicate detection.
|
|
||||||
skip = [
|
|
||||||
#"ansi_term@0.11.0",
|
|
||||||
#{ crate = "ansi_term@0.11.0", reason = "you can specify a reason why it can't be updated/removed" },
|
|
||||||
]
|
|
||||||
# Similarly to `skip` allows you to skip certain crates during duplicate
|
|
||||||
# detection. Unlike skip, it also includes the entire tree of transitive
|
|
||||||
# dependencies starting at the specified crate, up to a certain depth, which is
|
|
||||||
# by default infinite.
|
|
||||||
skip-tree = [
|
|
||||||
#"ansi_term@0.11.0", # will be skipped along with _all_ of its direct and transitive dependencies
|
|
||||||
#{ crate = "ansi_term@0.11.0", depth = 20 },
|
|
||||||
]
|
|
||||||
|
|
||||||
# This section is considered when running `cargo deny check sources`.
|
|
||||||
# More documentation about the 'sources' section can be found here:
|
|
||||||
# https://embarkstudios.github.io/cargo-deny/checks/sources/cfg.html
|
|
||||||
[sources]
|
|
||||||
# Lint level for what to happen when a crate from a crate registry that is not
|
|
||||||
# in the allow list is encountered
|
|
||||||
unknown-registry = "warn"
|
|
||||||
# Lint level for what to happen when a crate from a git repository that is not
|
|
||||||
# in the allow list is encountered
|
|
||||||
unknown-git = "warn"
|
|
||||||
# List of URLs for allowed crate registries. Defaults to the crates.io index
|
|
||||||
# if not specified. If it is specified but empty, no registries are allowed.
|
|
||||||
allow-registry = ["https://github.com/rust-lang/crates.io-index"]
|
|
||||||
# List of URLs for allowed Git repositories
|
|
||||||
allow-git = []
|
|
||||||
|
|
||||||
[sources.allow-org]
|
|
||||||
# github.com organizations to allow git sources for
|
|
||||||
github = []
|
|
||||||
# gitlab.com organizations to allow git sources for
|
|
||||||
gitlab = []
|
|
||||||
# bitbucket.org organizations to allow git sources for
|
|
||||||
bitbucket = []
|
|
||||||
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 9.0 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 7.3 KiB |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.4 KiB |
BIN
src-tauri/icons/icon-new.icns
Normal file
BIN
src-tauri/icons/icon-shrink.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 74 KiB After Width: | Height: | Size: 65 KiB |
BIN
src-tauri/icons/mac-tray-icon-sys.png
Normal file
|
After Width: | Height: | Size: 8.7 KiB |
BIN
src-tauri/icons/mac-tray-icon-tun.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
src-tauri/icons/mac-tray-icon.png
Normal file
|
After Width: | Height: | Size: 7.6 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 47 KiB |
BIN
src-tauri/icons/tray-icon-sys.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 54 KiB |