Compare commits
707 Commits
remove-nes
...
api-docs-i
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ea97f7f7f9 | ||
|
|
b4af3f80d3 | ||
|
|
aef9e6f5d0 | ||
|
|
da0ad760c9 | ||
|
|
298e277678 | ||
|
|
f1ccaa92bb | ||
|
|
0e79002c65 | ||
|
|
6825c1d661 | ||
|
|
f71261ed85 | ||
|
|
93231acba1 | ||
|
|
4d3579d86c | ||
|
|
b527e6fb4d | ||
|
|
1efe670d4e | ||
|
|
5fa8d46476 | ||
|
|
f5a0c34650 | ||
|
|
4decb23b5f | ||
|
|
e556e552b3 | ||
|
|
22eda01994 | ||
|
|
12bf97e256 | ||
|
|
fa3b58002b | ||
|
|
8af4499d47 | ||
|
|
62a82340e1 | ||
|
|
f957817f70 | ||
|
|
bb27e2f96c | ||
|
|
ca0a16e7d7 | ||
|
|
a304019cf6 | ||
|
|
bcc2c7a00f | ||
|
|
917ff25970 | ||
|
|
34d30973f0 | ||
|
|
7789855a1b | ||
|
|
df459b77dc | ||
|
|
2e731dbbd8 | ||
|
|
d3f0a4b1b2 | ||
|
|
57a82b636f | ||
|
|
e0b0640b10 | ||
|
|
d98832fb18 | ||
|
|
cfda0fb8ed | ||
|
|
1aa96ab121 | ||
|
|
e380d347a6 | ||
|
|
d8ed6a46df | ||
|
|
c14d89e731 | ||
|
|
6e1690db35 | ||
|
|
ed6b817ff1 | ||
|
|
121718dd5a | ||
|
|
fd00f8dcfb | ||
|
|
9a7cbd0ba4 | ||
|
|
7402c31488 | ||
|
|
369d49c8d6 | ||
|
|
8db50e3bfe | ||
|
|
bc54de38b3 | ||
|
|
56131a0fd8 | ||
|
|
d5a493eb9a | ||
|
|
143c024538 | ||
|
|
1e1a8ffa0e | ||
|
|
bfacd62e02 | ||
|
|
d58ba412ae | ||
|
|
6d60452933 | ||
|
|
909be60ee0 | ||
|
|
54444ef9ed | ||
|
|
8634f23926 | ||
|
|
4bc0070a57 | ||
|
|
d9b7bcd251 | ||
|
|
2687cc4b61 | ||
|
|
39372f2b1a | ||
|
|
e4a00c17fc | ||
|
|
e88873a099 | ||
|
|
8290d9d56e | ||
|
|
92ad76a065 | ||
|
|
670d5274cc | ||
|
|
0b4dd2e756 | ||
|
|
b6d08d7bb4 | ||
|
|
156a329589 | ||
|
|
3b627d1bb9 | ||
|
|
3cc92a3ba6 | ||
|
|
843f81aa22 | ||
|
|
2ea0a694d6 | ||
|
|
4b97475050 | ||
|
|
7ef645bd27 | ||
|
|
3bb9478215 | ||
|
|
42cbd634a2 | ||
|
|
b0900d88f0 | ||
|
|
af7227e8d9 | ||
|
|
2ed9f0ac7c | ||
|
|
8aa6ee0ed7 | ||
|
|
8a651a248b | ||
|
|
d56da1a054 | ||
|
|
4ed93618c2 | ||
|
|
a13e45b0ec | ||
|
|
4bb25512dc | ||
|
|
a0378ba230 | ||
|
|
842fa1a0fe | ||
|
|
ac4f6f6663 | ||
|
|
9c00839e0a | ||
|
|
f88dafb8be | ||
|
|
6168ee8c88 | ||
|
|
633f657a1c | ||
|
|
4edfe1377a | ||
|
|
dc72ee9722 | ||
|
|
ce285ce1af | ||
|
|
4972d25abe | ||
|
|
3a3d8028ec | ||
|
|
f0abe274a7 | ||
|
|
73737673cf | ||
|
|
2df4df7a8c | ||
|
|
1e486af5ee | ||
|
|
a101797f95 | ||
|
|
621ea1feca | ||
|
|
3579cd040e | ||
|
|
97330f0ae4 | ||
|
|
fb97b96f69 | ||
|
|
4bea4abf5a | ||
|
|
10cb07dfa3 | ||
|
|
a0fc9340c6 | ||
|
|
9c6e187fdb | ||
|
|
495776dc1e | ||
|
|
c9af783134 | ||
|
|
520f30b3f3 | ||
|
|
8a0e48b038 | ||
|
|
d19d0bd01a | ||
|
|
fc4a83f9fa | ||
|
|
ac982ba47b | ||
|
|
5cdb9aeb17 | ||
|
|
972530b4b4 | ||
|
|
3353942052 | ||
|
|
1b6b0e4e65 | ||
|
|
e3f5a8fa02 | ||
|
|
59b1c333bc | ||
|
|
a09a2afb05 | ||
|
|
445bf5fd4e | ||
|
|
9625969eab | ||
|
|
bb9c605f9e | ||
|
|
34d4548595 | ||
|
|
5094cb83a8 | ||
|
|
3c97adc08f | ||
|
|
756d0188e0 | ||
|
|
e81a4d3808 | ||
|
|
f236589153 | ||
|
|
0faa1b815e | ||
|
|
869d810773 | ||
|
|
7fc08ff0e1 | ||
|
|
a9732409d7 | ||
|
|
410d7e6b53 | ||
|
|
ecabdc59ec | ||
|
|
da8a48b462 | ||
|
|
db26eebe3f | ||
|
|
7c010114d4 | ||
|
|
9748d41f4a | ||
|
|
ef8c3f2342 | ||
|
|
f8bbd9ecc2 | ||
|
|
6c0dedbb73 | ||
|
|
1ddf10f00a | ||
|
|
03dc3fdd0d | ||
|
|
1b1c572c2c | ||
|
|
b16161533d | ||
|
|
e6f551e0a0 | ||
|
|
60e08be857 | ||
|
|
9d12421e41 | ||
|
|
5351d4d4a9 | ||
|
|
c03a49a87c | ||
|
|
52ffc412c8 | ||
|
|
eb931d72b1 | ||
|
|
cf4f46e5c6 | ||
|
|
ae958b131c | ||
|
|
dfd0a55a09 | ||
|
|
58998875a4 | ||
|
|
e7f1a92c8a | ||
|
|
9a554425e2 | ||
|
|
e104ed81e5 | ||
|
|
c20c9b7cb6 | ||
|
|
db35fefdc3 | ||
|
|
df3843215d | ||
|
|
28a2150c1e | ||
|
|
f31cb4c45d | ||
|
|
01b996ddb6 | ||
|
|
5cad344fd0 | ||
|
|
924e2ecd3d | ||
|
|
5de615c633 | ||
|
|
a260601156 | ||
|
|
926d2c617e | ||
|
|
9af191fc60 | ||
|
|
ef6a9bb253 | ||
|
|
2cc56a4c13 | ||
|
|
d72c26b66c | ||
|
|
81e6f479e9 | ||
|
|
45aaf7c6d7 | ||
|
|
a5f6687798 | ||
|
|
eeeb6bbc5c | ||
|
|
b71e299854 | ||
|
|
95fe8fa5f2 | ||
|
|
9cef486ea3 | ||
|
|
3e71b70d8d | ||
|
|
84c99be11a | ||
|
|
da360af2d0 | ||
|
|
ecfae75734 | ||
|
|
47108c9f94 | ||
|
|
6c6372f6bc | ||
|
|
5e5f44878d | ||
|
|
c9d6609021 | ||
|
|
e5044f2cb8 | ||
|
|
ce24e63aca | ||
|
|
3cd46419dd | ||
|
|
b09343c050 | ||
|
|
53ee36832a | ||
|
|
6136047dff | ||
|
|
1c755054c9 | ||
|
|
bed2c3d442 | ||
|
|
fa27b5e744 | ||
|
|
a4b2ccd657 | ||
|
|
570cd10c3c | ||
|
|
7c13028d7f | ||
|
|
94379d8a54 | ||
|
|
4ca935e2cf | ||
|
|
2634a5ff83 | ||
|
|
efd7c708b2 | ||
|
|
4949cf3847 | ||
|
|
566f21d1ae | ||
|
|
29bcb43082 | ||
|
|
8250c46747 | ||
|
|
26e2e158ee | ||
|
|
1124000465 | ||
|
|
6cd6235289 | ||
|
|
2d60b9cb44 | ||
|
|
cb8266362c | ||
|
|
39860ebb86 | ||
|
|
61a58edaf9 | ||
|
|
6e5293fdfa | ||
|
|
c8f0e188a2 | ||
|
|
74fc3b9db9 | ||
|
|
f02be4f3f7 | ||
|
|
1ead33339c | ||
|
|
a70d20d135 | ||
|
|
faa7c736d0 | ||
|
|
b31ce245b7 | ||
|
|
9e0f6e1703 | ||
|
|
4ba2882740 | ||
|
|
39a48c4539 | ||
|
|
0bbab5f051 | ||
|
|
42e50fbdcc | ||
|
|
a2794d6ae2 | ||
|
|
e871e538b1 | ||
|
|
feb7db2c06 | ||
|
|
30970aa4ac | ||
|
|
7d11423cef | ||
|
|
123c1232fd | ||
|
|
9b4a091817 | ||
|
|
0b1c5003eb | ||
|
|
eca452c45f | ||
|
|
69a72b9db8 | ||
|
|
443860bff5 | ||
|
|
f442920bb8 | ||
|
|
9bd43494a6 | ||
|
|
4968758f1d | ||
|
|
a6392f245a | ||
|
|
4fd4f14456 | ||
|
|
12bb4b9e77 | ||
|
|
9c806a5c27 | ||
|
|
be5b292ba3 | ||
|
|
e2fd234cc2 | ||
|
|
ee16b43e3b | ||
|
|
4142c00db9 | ||
|
|
e58b3bc5dd | ||
|
|
c9dfcb2f47 | ||
|
|
1e17d6903d | ||
|
|
50d9099ca0 | ||
|
|
8b23d477dd | ||
|
|
0f0799898b | ||
|
|
13417eebb7 | ||
|
|
ca6e3dba41 | ||
|
|
fc4024b973 | ||
|
|
858fbb555f | ||
|
|
6033ae8983 | ||
|
|
5d498f51a1 | ||
|
|
87e1260760 | ||
|
|
3dd914fcaa | ||
|
|
ea9fe96a71 | ||
|
|
916dd6bff7 | ||
|
|
e800fc7438 | ||
|
|
06064dfbaa | ||
|
|
5fcaa3c884 | ||
|
|
be1e70f51c | ||
|
|
945237b09c | ||
|
|
5fe517a03e | ||
|
|
ea53020156 | ||
|
|
e1665c9674 | ||
|
|
b4a34ab899 | ||
|
|
969c1babd3 | ||
|
|
59d45e5ef4 | ||
|
|
75e9be30f6 | ||
|
|
dff830c1f6 | ||
|
|
e40425322f | ||
|
|
f7f23dcf3e | ||
|
|
93ed751688 | ||
|
|
c806f3a599 | ||
|
|
426446b9fc | ||
|
|
2cef7a8695 | ||
|
|
8ce4383355 | ||
|
|
12cd25af26 | ||
|
|
55afff90af | ||
|
|
d27bcffb5f | ||
|
|
aaae17f296 | ||
|
|
bc26890905 | ||
|
|
0e988ff8a0 | ||
|
|
afce736c7f | ||
|
|
1d81ce41b1 | ||
|
|
eef8ad7901 | ||
|
|
66ff9f2c04 | ||
|
|
70d4582f67 | ||
|
|
703db28acd | ||
|
|
8949f1598a | ||
|
|
ebe179780b | ||
|
|
4b5c8caa1e | ||
|
|
a746d081b7 | ||
|
|
0f5b4944e3 | ||
|
|
69c2c29e0e | ||
|
|
fe5de91ff7 | ||
|
|
666bf41aa2 | ||
|
|
48f792ab99 | ||
|
|
220e18db22 | ||
|
|
697bfef8d7 | ||
|
|
2d6c18162b | ||
|
|
cd209344c6 | ||
|
|
a451a506a0 | ||
|
|
3cc73019c5 | ||
|
|
bba632c41e | ||
|
|
0d0a53e0fd | ||
|
|
e8cec5b900 | ||
|
|
7f1147c96a | ||
|
|
cc0cbb27b3 | ||
|
|
cc928b793b | ||
|
|
687fe82667 | ||
|
|
b4a28c6a6f | ||
|
|
4f899500f6 | ||
|
|
ee6550bfbe | ||
|
|
07967d1d54 | ||
|
|
674a2ef295 | ||
|
|
f5531c1b7c | ||
|
|
85f0815d4d | ||
|
|
a034598d14 | ||
|
|
415864829a | ||
|
|
55f2b55347 | ||
|
|
a04fbad1c4 | ||
|
|
414d7c21c6 | ||
|
|
d951556eb1 | ||
|
|
23b1ee90f4 | ||
|
|
54d9d77892 | ||
|
|
8a2b0538f1 | ||
|
|
3d960aeb80 | ||
|
|
71c3a2bab6 | ||
|
|
20a474a2f2 | ||
|
|
5fb2f158ec | ||
|
|
24a9ab15e4 | ||
|
|
9c1d83d272 | ||
|
|
8ce2ee9f06 | ||
|
|
38e44a29bc | ||
|
|
b74a5a7056 | ||
|
|
9863ce2a11 | ||
|
|
810fe8e072 | ||
|
|
7c096d3e5d | ||
|
|
e800e56f96 | ||
|
|
c177bbcee7 | ||
|
|
783fa00d69 | ||
|
|
8638b3c780 | ||
|
|
1a4aa1a5cb | ||
|
|
4b2db972d7 | ||
|
|
e4c5f2fce7 | ||
|
|
8c03762cc5 | ||
|
|
760f65f7e5 | ||
|
|
0f488296d8 | ||
|
|
e242f00b64 | ||
|
|
3bbae3d595 | ||
|
|
19f17b54f8 | ||
|
|
89d1513395 | ||
|
|
b9eae7d152 | ||
|
|
57e371f5dc | ||
|
|
77291ab895 | ||
|
|
1e83d3d38d | ||
|
|
e4451b2f77 | ||
|
|
e8797bc340 | ||
|
|
6f02407835 | ||
|
|
62eb4a6dbe | ||
|
|
eaa13e8a6b | ||
|
|
4ddf02cc2b | ||
|
|
fb65c38b84 | ||
|
|
d4a9b80e2b | ||
|
|
ee727307c4 | ||
|
|
b29716d856 | ||
|
|
63703cfb15 | ||
|
|
36bbfeec80 | ||
|
|
41441f6090 | ||
|
|
d0859d5455 | ||
|
|
89a0a1a66a | ||
|
|
a904c1e5be | ||
|
|
3365b33beb | ||
|
|
7bc578d008 | ||
|
|
a7b8f79b03 | ||
|
|
bb909363a2 | ||
|
|
a99a7dd117 | ||
|
|
13e237e007 | ||
|
|
1a60acc0e6 | ||
|
|
91953b7c96 | ||
|
|
6e5360ed78 | ||
|
|
399e8944ad | ||
|
|
eca1f09ffe | ||
|
|
d65e48e6e1 | ||
|
|
41a300da8c | ||
|
|
d83f37e5af | ||
|
|
060e5930d0 | ||
|
|
b941c552f0 | ||
|
|
768cb9514f | ||
|
|
fa3b30034e | ||
|
|
b8b539de91 | ||
|
|
878a67a293 | ||
|
|
ff747db23e | ||
|
|
889664c71f | ||
|
|
c584246f18 | ||
|
|
a5207cbab4 | ||
|
|
3155b1cd2a | ||
|
|
3a8cf256d0 | ||
|
|
f81d575f9d | ||
|
|
8473fdb650 | ||
|
|
9543678121 | ||
|
|
d9674eb215 | ||
|
|
1f7cd46a28 | ||
|
|
c09ff48c6c | ||
|
|
18e423c8df | ||
|
|
a58c82bec5 | ||
|
|
1a413c114b | ||
|
|
adedaf3677 | ||
|
|
f35c2c286b | ||
|
|
86eefeff09 | ||
|
|
3b3771be4e | ||
|
|
4b60e5ab18 | ||
|
|
92b0983353 | ||
|
|
9d5cf6baaf | ||
|
|
c453d347e8 | ||
|
|
91c6427e1f | ||
|
|
a5ccd65d08 | ||
|
|
fedd7d2485 | ||
|
|
ee22e2895f | ||
|
|
77269788b6 | ||
|
|
efa723617e | ||
|
|
dc674ad1f6 | ||
|
|
c349e6fc00 | ||
|
|
4995c330e7 | ||
|
|
df32bd3af1 | ||
|
|
b188dafad9 | ||
|
|
0c1593e9b4 | ||
|
|
2e13505d19 | ||
|
|
dde841f26e | ||
|
|
ebaf8a84c6 | ||
|
|
86d9c905b5 | ||
|
|
3e5c7bda5e | ||
|
|
839b090013 | ||
|
|
37aaa66a85 | ||
|
|
0e7b66ae44 | ||
|
|
8a5eb47579 | ||
|
|
19acff81ae | ||
|
|
e98220607a | ||
|
|
eccfcf2c17 | ||
|
|
f32093aac1 | ||
|
|
7c71973684 | ||
|
|
9e9292d5e4 | ||
|
|
e3cdbbf7a8 | ||
|
|
88141a8fca | ||
|
|
5b8adfe4df | ||
|
|
87f5ff5025 | ||
|
|
1e4bf6a9ea | ||
|
|
f3715931c0 | ||
|
|
61dbcc3c4e | ||
|
|
97ce719dc1 | ||
|
|
74b7088daa | ||
|
|
7ca14ce129 | ||
|
|
1ba4aba2d0 | ||
|
|
d077d441d5 | ||
|
|
b9d2bbe034 | ||
|
|
3aadc1e6bb | ||
|
|
333eca8d45 | ||
|
|
3f01cd254d | ||
|
|
c7fe1a2484 | ||
|
|
dddd710ac8 | ||
|
|
a82a386525 | ||
|
|
4b5ddbd97f | ||
|
|
776e0c65cf | ||
|
|
2f21dd6596 | ||
|
|
dae1de739f | ||
|
|
ac46c14f5f | ||
|
|
758921c1a3 | ||
|
|
15f83e691d | ||
|
|
d913e17690 | ||
|
|
2fe63c903f | ||
|
|
643e7647f9 | ||
|
|
61e74eb120 | ||
|
|
1df2e40a59 | ||
|
|
3879be8bde | ||
|
|
1d5b5c6b33 | ||
|
|
43bf9c58c8 | ||
|
|
9290125217 | ||
|
|
3efcf2c860 | ||
|
|
7f3816a47a | ||
|
|
9315a633b3 | ||
|
|
98907d2f58 | ||
|
|
ffa6bedead | ||
|
|
79143aa539 | ||
|
|
23f0e9405f | ||
|
|
aff8e8e792 | ||
|
|
c0dddcc3ae | ||
|
|
c06e0293b5 | ||
|
|
61e3d00fb2 | ||
|
|
d2b8c0bf08 | ||
|
|
65c112a89c | ||
|
|
f8a65475c0 | ||
|
|
3267710d8d | ||
|
|
0fcb08f545 | ||
|
|
80449f3cb6 | ||
|
|
0efd740217 | ||
|
|
4f6373a71d | ||
|
|
b94b107b81 | ||
|
|
af094941c8 | ||
|
|
af75dec737 | ||
|
|
00059659bf | ||
|
|
85d3b4907b | ||
|
|
abad978404 | ||
|
|
abfda359b0 | ||
|
|
3757a89594 | ||
|
|
34624003cf | ||
|
|
8590ba6448 | ||
|
|
6e125a6802 | ||
|
|
a4665a7234 | ||
|
|
f435376eaa | ||
|
|
296e2258b9 | ||
|
|
db5d327471 | ||
|
|
04eb8348bc | ||
|
|
30b9d66619 | ||
|
|
b78d8cf08f | ||
|
|
59daec2227 | ||
|
|
3f11901c23 | ||
|
|
31ccb1e082 | ||
|
|
795b53a82a | ||
|
|
ab0a7f1034 | ||
|
|
1c63f62431 | ||
|
|
0998f9b6e1 | ||
|
|
5e212e931f | ||
|
|
ea4ee806aa | ||
|
|
3bcf2d5989 | ||
|
|
a8927594c1 | ||
|
|
f6b9e3b0d2 | ||
|
|
9c904e8500 | ||
|
|
fbf0e7a3ad | ||
|
|
c6bd90065b | ||
|
|
d8c45ea17c | ||
|
|
87316e805e | ||
|
|
74cb6fa714 | ||
|
|
dd8581a3d1 | ||
|
|
4ec0eac971 | ||
|
|
85e0db50f8 | ||
|
|
40e53d907b | ||
|
|
e3adb04fa4 | ||
|
|
71bc1d85d9 | ||
|
|
91b16b4a79 | ||
|
|
0b880331dd | ||
|
|
d304dae668 | ||
|
|
8452fc328c | ||
|
|
db8f67d816 | ||
|
|
9ba1a81821 | ||
|
|
030b80ec5a | ||
|
|
af74709b0e | ||
|
|
3e046e5735 | ||
|
|
2a525ea3c1 | ||
|
|
ec1aae01a4 | ||
|
|
72501e16e3 | ||
|
|
4bffd6b8e2 | ||
|
|
be08de26b6 | ||
|
|
4abf0a9ec3 | ||
|
|
0c6f3eb867 | ||
|
|
9a2676013a | ||
|
|
be81c7f922 | ||
|
|
31be930b9c | ||
|
|
e43a9ee150 | ||
|
|
bdfc92a707 | ||
|
|
87eaa5d640 | ||
|
|
1acb027d66 | ||
|
|
9908b9e539 | ||
|
|
1e5ebfe653 | ||
|
|
9fb173967f | ||
|
|
930cb87f98 | ||
|
|
f02832e9d9 | ||
|
|
63c69f5461 | ||
|
|
f40526dc12 | ||
|
|
81beb333b6 | ||
|
|
272f682da5 | ||
|
|
055abbf97e | ||
|
|
7997420ef7 | ||
|
|
41fece6015 | ||
|
|
be18f2706a | ||
|
|
8e9558ebad | ||
|
|
6ee2eb3bb3 | ||
|
|
f96fe1fdb8 | ||
|
|
ee95429b8d | ||
|
|
0eb4084fbc | ||
|
|
c211cb72f2 | ||
|
|
bea3c3d789 | ||
|
|
6dd40b8241 | ||
|
|
46dc35e86b | ||
|
|
359c55dd2e | ||
|
|
5a3f6124c6 | ||
|
|
00eeac0a40 | ||
|
|
69a4f865fb | ||
|
|
4a0b85c54a | ||
|
|
39a58d6311 | ||
|
|
f18e43a0f0 | ||
|
|
398e108899 | ||
|
|
579c00e008 | ||
|
|
de4da6e620 | ||
|
|
91618837bf | ||
|
|
e3abb47200 | ||
|
|
5d9aceb04f | ||
|
|
020cb1505c | ||
|
|
5a8d279051 | ||
|
|
aae5c83334 | ||
|
|
21630de9a4 | ||
|
|
0a533a9c07 | ||
|
|
c8f684a36d | ||
|
|
6ef825835a | ||
|
|
304e1077ee | ||
|
|
a6793c4061 | ||
|
|
6336fdbc98 | ||
|
|
4c197eeead | ||
|
|
8e7d79b1b9 | ||
|
|
a5022e140d | ||
|
|
ac58570ae0 | ||
|
|
6a477b5172 | ||
|
|
16ea4a7629 | ||
|
|
3527c911d7 | ||
|
|
d59316a58e | ||
|
|
85a341cf55 | ||
|
|
8ea5431774 | ||
|
|
aed32a76c7 | ||
|
|
d6864cbafe | ||
|
|
fd52f4e992 | ||
|
|
914cc8f725 | ||
|
|
5a5cbff5c4 | ||
|
|
18cc47efef | ||
|
|
c05bfd571e | ||
|
|
6d9d394b52 | ||
|
|
dc5662b06e | ||
|
|
95758dfdb9 | ||
|
|
699c029d78 | ||
|
|
6cd504fb02 | ||
|
|
018932f07a | ||
|
|
55ab66d6cc | ||
|
|
d8674cc61b | ||
|
|
d7a3215567 | ||
|
|
d458b6e6b9 | ||
|
|
86086df469 | ||
|
|
a231c83c12 | ||
|
|
1fdc213d08 | ||
|
|
199d4c2557 | ||
|
|
bdfa366fe5 | ||
|
|
ad00b9478b | ||
|
|
19eaa8bf78 | ||
|
|
9586bca50a | ||
|
|
6b2a9d7a72 | ||
|
|
6624cc7e22 | ||
|
|
5f41d063be | ||
|
|
5a4e3fcb48 | ||
|
|
18f4ba60ff | ||
|
|
1d984403bb | ||
|
|
ce53e5256a | ||
|
|
bf88842c89 | ||
|
|
9ec0de7013 | ||
|
|
3ad2fa7f1a | ||
|
|
ffb64be70d | ||
|
|
baec00f266 | ||
|
|
02d1dfee1e | ||
|
|
b46bedc781 | ||
|
|
fb06daf9b7 | ||
|
|
dca2d5367e | ||
|
|
d0d18d0774 | ||
|
|
500f598ce8 | ||
|
|
4d83649cf8 | ||
|
|
6de41bd362 | ||
|
|
97fe3a63f7 | ||
|
|
51398067a7 | ||
|
|
6e1b34c8fe | ||
|
|
92c1f6fa99 | ||
|
|
26d2d76ba6 | ||
|
|
6fbe8727ff | ||
|
|
84c33f06f5 | ||
|
|
6d33e3192a | ||
|
|
836a66e42f | ||
|
|
87cf284db9 | ||
|
|
bbac4354bb | ||
|
|
b994cb167a | ||
|
|
58f32ff108 | ||
|
|
a9d08f63d6 | ||
|
|
d1ff0969cf | ||
|
|
27c6fe4864 | ||
|
|
3aaecdb612 | ||
|
|
c1c331166a | ||
|
|
12b366a2c5 | ||
|
|
352d96b5a6 | ||
|
|
c2b755bc2c | ||
|
|
bf2f6678b2 | ||
|
|
2d56f4deb9 | ||
|
|
7402b0ee8e | ||
|
|
48f876956a | ||
|
|
e0f42d499d |
@@ -1,8 +1,7 @@
|
||||
;; -*- comment-column: 100; -*-
|
||||
{:config-paths ["macros" "src"]
|
||||
{:config-paths ["macros" "src" "config"]
|
||||
:linters
|
||||
{
|
||||
;;
|
||||
{;;
|
||||
;; enabled optional linters (these are disabled by default)
|
||||
;;
|
||||
|
||||
@@ -56,12 +55,14 @@
|
||||
;;
|
||||
;; globally-enabled custom linters
|
||||
;;
|
||||
:metabase/check-defmulti-arglists {:level :warning}
|
||||
:metabase/check-me-humanize {:level :warning}
|
||||
:metabase/defsetting-must-specify-export {:level :warning}
|
||||
:metabase/mbql-query-first-arg {:level :warning}
|
||||
:metabase/missing-test-expr-requires-in-cljs {:level :warning}
|
||||
:metabase/modules {:level :warning} ; more config in `.clj-kondo/config/modules/config.edn`
|
||||
:metabase/require-shape-checker {:level :warning}
|
||||
:metabase/test-helpers-use-non-thread-safe-functions {:level :warning}
|
||||
:metabase/test-helpers-use-non-thread-safe-functions {:level :warning} ; more config in `.clj-kondo/config/test-helpers/config.edn`
|
||||
:metabase/validate-logging {:level :warning}
|
||||
:metabase/validate-mb-driver-tests {:level :warning}
|
||||
:metabase/validate-mb-once {:level :warning}
|
||||
@@ -84,8 +85,8 @@
|
||||
metabase.actions.test-util/with-actions-test-data-and-actions-enabled
|
||||
metabase.actions.test-util/with-actions-test-data-tables
|
||||
metabase.analytics.snowplow-test/with-fake-snowplow-collector
|
||||
metabase.email-test/with-expected-messages
|
||||
metabase.email-test/with-fake-inbox
|
||||
metabase.channel.email-test/with-expected-messages
|
||||
metabase.channel.email-test/with-fake-inbox
|
||||
metabase.test.data.users/with-group
|
||||
metabase.test.data.users/with-group-for-user
|
||||
metabase.test.data/with-empty-h2-app-db
|
||||
@@ -176,13 +177,13 @@
|
||||
|
||||
:metabase/i-like-making-cams-eyes-bleed-with-horrifically-long-tests
|
||||
{:level :warning
|
||||
:max-length 180}
|
||||
:max-length 150}
|
||||
|
||||
;; this is not enabled here, it is enabled below only for specific namespaces.
|
||||
:metabase/disallow-hardcoded-driver-names-in-tests
|
||||
;; don't include `:h2` since that will probably lead to a mountain of tests where we are specifically testing
|
||||
;; middleware or compilation behavior with just H2 since it's the default.
|
||||
{:drivers #{ ;; core drivers
|
||||
{:drivers #{;; core drivers
|
||||
#_:h2
|
||||
:postgres
|
||||
:mysql
|
||||
@@ -212,6 +213,9 @@
|
||||
:refer-all {:level :warning, :exclude [clojure.test]}
|
||||
:unused-referred-var {:exclude {compojure.core [GET DELETE POST PUT]}}
|
||||
|
||||
;; TODO -- all of these entries are HACKS and we should fix them by writing real custom Kondo HOOKS for these
|
||||
;; macros. Please don't add anything new to this list! Talk to your best bud Cam if you don't know how to write a
|
||||
;; Kondo hook and he will pair with you on it. Thanks! -- Cam
|
||||
:unresolved-symbol
|
||||
{:exclude
|
||||
[(build.uberjar/with-duration-ms)
|
||||
@@ -222,7 +226,7 @@
|
||||
(clojure.test/is [query= =? malli= qv=])
|
||||
(clojure.tools.macro/macrolet)
|
||||
instaparse.core/transform
|
||||
(metabase.async.streaming-response/streaming-response)
|
||||
(metabase.server.streaming-response/streaming-response)
|
||||
(metabase.driver.druid.query-processor-test/druid-query-returning-rows)
|
||||
(metabase.lib.util.match/match)
|
||||
(metabase.lib.util.match/match-one)
|
||||
@@ -259,12 +263,16 @@
|
||||
clojure.core/pr {:message "Use metabase.util.log instead of clojure.core/pr"}
|
||||
clojure.core/tap> {:message "Don't use tap> is source code"}
|
||||
clojure.core/time {:message "Don't use time in source code"}
|
||||
clojure.test.check/quick-check {:message "You probably meant to use clojure.test.check.clojure-test/defspec instead -- quick check will run the tests when it is evaluated rather than when we run the test suite."}
|
||||
clojure.java.jdbc/get-connection {:message "Use sql-jdbc.execute/do-with-connection-with-options (for drivers) or t2/with-connection (for the app DB) instead of jdbc/get-connection"}
|
||||
clojure.java.jdbc/with-db-connection {:message "Use sql-jdbc.execute/do-with-connection-with-options (for drivers) or t2/with-connection (for the app DB) instead of jdbc/with-db-connection"}
|
||||
clojure.java.jdbc/with-db-metadata {:message "Use sql-jdbc.execute/do-with-connection-with-options + .getMetaData instead of jdbc/with-db-metadata"}
|
||||
clojure.pprint/pprint {:message "Use metabase.util.log instead of clojure.pprint/pprint"}
|
||||
clojure.string/lower-case {:message "Use metabase.util/lower-case-en instead of clojure.string/lower-case"}
|
||||
clojure.string/upper-case {:message "Use metabase.util/upper-case-en instead of clojure.string/upper-case"}
|
||||
compojure.core/context {:message "Use metabase.api.util.handlers/route-map-handler instead of compojure.core/context, it is much faster and supports OpenAPI spec generation"}
|
||||
compojure.core/defroutes {:message "Use metabase.api.util.handlers/defroutes instead of compojure.core/routes, it supports OpenAPI spec generation."}
|
||||
compojure.core/routes {:message "Use metabase.api.util.handlers/routes instead of compojure.core/routes, it supports OpenAPI spec generation."}
|
||||
fipp.edn/pprint {:message "Use metabase.util.log instead of fipp.edn/pprint"}
|
||||
honeysql.core/call {:message "Use hx/call instead because it is Honey SQL 2 friendly"}
|
||||
honeysql.core/raw {:message "Use hx/raw instead because it is Honey SQL 2 friendly"}
|
||||
@@ -277,9 +285,7 @@
|
||||
me.flowthing.pp/pprint {:message "Use metabase.util.log instead of me.flowthing.pp/pprint"}
|
||||
medley.core/random-uuid {:message "Use clojure.core/random-uuid instead of medley.core/random-uuid"}
|
||||
metabase.driver/database-supports? {:message "Use metabase.driver.util/supports? instead of metabase.driver/database-supports?"}
|
||||
metabase.lib.equality/find-column-indexes-for-refs {:message "Use lib.equality/closest-matches-in-metadata or lib.equality/find-closest-matches-for-refs instead of lib.equality/find-column-indexes-for-refs"}
|
||||
metabase.test/with-temp* {:message "Use mt/with-temp instead of mt/with-temp*"}
|
||||
toucan2.tools.with-temp/with-temp {:message "Use mt/with-temp instead of toucan2.tools.with-temp/with-temp"}}
|
||||
metabase.lib.equality/find-column-indexes-for-refs {:message "Use lib.equality/closest-matches-in-metadata or lib.equality/find-closest-matches-for-refs instead of lib.equality/find-column-indexes-for-refs"}}
|
||||
|
||||
:discouraged-namespace
|
||||
{camel-snake-kebab.core {:message "CSK is not Turkish-safe, use the versions in metabase.util instead."}
|
||||
@@ -290,217 +296,12 @@
|
||||
honeysql.format {:message "Use Honey SQL 2. Honey SQL 1 is removed as a dependency in Metabase 49+."}
|
||||
honeysql.helpers {:message "Use Honey SQL 2. Honey SQL 1 is removed as a dependency in Metabase 49+."}
|
||||
honeysql.types {:message "Use Honey SQL 2. Honey SQL 1 is removed as a dependency in Metabase 49+."}
|
||||
honeysql.util {:message "Use Honey SQL 2. Honey SQL 1 is removed as a dependency in Metabase 49+."}
|
||||
metabase.util.jvm {:message "All of metabase.util.jvm is re-exported from metabase.util; prefer that"}}
|
||||
honeysql.util {:message "Use Honey SQL 2. Honey SQL 1 is removed as a dependency in Metabase 49+."}}
|
||||
|
||||
:unresolved-var
|
||||
{:exclude
|
||||
[colorize.core]}
|
||||
|
||||
;; A "module" is any `metabase.x` namespace in `src`.
|
||||
:metabase/ns-module-checker
|
||||
{:level :warning
|
||||
|
||||
;; Map of module name => the "core" external public-facing API namespace(s). You have three options here:
|
||||
;;
|
||||
;; 1. Special sentinel value `:any` means means this module does not (yet) have external public-facing API
|
||||
;; namespace(s). This is mostly a temporary placeholder until we go in and create module namespaces, which means
|
||||
;; you should go create one.
|
||||
;;
|
||||
;; 2. A set of namespace symbols. All namespaces in other modules will only be allowed to use namespaces from
|
||||
;; this set. Ideally this set should only have one namespace, but restricting it to a set of several is still
|
||||
;; better than `:any`.
|
||||
;;
|
||||
;; 3. `nil` or not listed here -- we default to assuming there is one API namespace that matches the name of the
|
||||
;; module itself, e.g. the module namespace for `metabase.setup` would be `metabase.setup`.
|
||||
;;
|
||||
;; `nil` or an empty set Otherwise this should be a set of namespace symbols.
|
||||
;;
|
||||
;; PRO TIP: Check out the `dev.deps-graph` namespace for helpful tools to see where a module is used externally.
|
||||
:api-namespaces
|
||||
{metabase.actions #{metabase.actions.core}
|
||||
metabase.analytics #{metabase.analytics.prometheus
|
||||
metabase.analytics.snowplow
|
||||
metabase.analytics.stats
|
||||
metabase.analytics.sdk} ; TODO -- consolidate these into a real API namespace.
|
||||
metabase.analyze #{metabase.analyze}
|
||||
metabase.api #{metabase.api.common
|
||||
metabase.api.dataset
|
||||
metabase.api.macros
|
||||
metabase.api.permission-graph
|
||||
metabase.api.routes} ; TODO -- consolidate these into a real API namespace. I think the `*current-user*` type stuff might need to be moved into a separate module.
|
||||
metabase.async #{metabase.async.streaming-response
|
||||
metabase.async.streaming-response.thread-pool
|
||||
metabase.async.util} ; TODO -- consolidate these into a real API namespace.
|
||||
metabase.audit #{metabase.audit}
|
||||
metabase.bootstrap #{metabase.bootstrap}
|
||||
metabase.cmd #{} ; there are no namespaces here since you shouldn't be using this in any other module.
|
||||
metabase.channel #{metabase.channel.core
|
||||
metabase.channel.render.core
|
||||
metabase.channel.template.core}
|
||||
metabase.config #{metabase.config}
|
||||
metabase.core #{metabase.core.initialization-status} ; TODO -- only namespace used outside of EE, this probably belongs in `metabase.server` anyway since that's the only place it's used.
|
||||
metabase.db #{metabase.db
|
||||
metabase.db.metadata-queries ; TODO this should probably be separate from metabase.db
|
||||
metabase.db.query ; TODO this is mostly util stuff like `metabase.db.query/query` that we don't even need anymore.
|
||||
metabase.db.setup} ; TODO these are only calling `metabase.db.setup/setup-db!` and there's a slightly different version in `metabase.db`
|
||||
metabase.driver :any ; TODO -- 19 namespaces!!!! CRY
|
||||
metabase.email #{metabase.email
|
||||
metabase.email.messages
|
||||
metabase.email.result-attachment} ; TODO -- consolidate these into a real API namespace.
|
||||
metabase.embed #{metabase.embed.settings}
|
||||
metabase.events #{metabase.events}
|
||||
metabase.formatter #{metabase.formatter}
|
||||
metabase.integrations #{metabase.integrations.common
|
||||
metabase.integrations.google
|
||||
metabase.integrations.ldap
|
||||
metabase.integrations.slack} ; TODO -- consolidate these into a real API namespace.
|
||||
metabase.legacy-mbql #{metabase.legacy-mbql.normalize
|
||||
metabase.legacy-mbql.predicates
|
||||
metabase.legacy-mbql.schema
|
||||
metabase.legacy-mbql.schema.helpers
|
||||
metabase.legacy-mbql.util} ; TODO -- consolidate these into a real API namespace.
|
||||
metabase.lib :any ; TODO -- :cry: 34 externally referenced namespaces, but maybe half of them are schema namespaces which technically don't need to be required.
|
||||
metabase.logger #{metabase.logger}
|
||||
metabase.metabot #{metabase.metabot}
|
||||
metabase.models :any ; TODO -- scream, 62 namespaces used elsewhere, but to be fair a lot of these don't *need* to be required.
|
||||
metabase.moderation #{metabase.moderation}
|
||||
metabase.notification #{metabase.notification.core
|
||||
metabase.notification.payload.core}
|
||||
metabase.permissions #{metabase.permissions.util} ; TODO -- this is currently the only namespace in this module. Give it a real API namespace?
|
||||
metabase.plugins #{metabase.plugins
|
||||
metabase.plugins.classloader} ; TODO -- not 100% sure the classloader belongs here
|
||||
metabase.premium-features #{metabase.premium-features.core}
|
||||
metabase.public-settings #{metabase.public-settings}
|
||||
metabase.pulse #{metabase.pulse.core}
|
||||
metabase.query-processor :any ; TODO omg scream, 29 namespaces used outside of the module. WHAT THE HECC
|
||||
metabase.query-analysis #{metabase.query-analysis
|
||||
metabase.query-analysis.failure-map}
|
||||
metabase.related #{metabase.related}
|
||||
metabase.request #{metabase.request.core}
|
||||
metabase.sample-data #{metabase.sample-data}
|
||||
metabase.search #{metabase.search.core
|
||||
;; Need to expose this submodule, to break circular dependencies with models.
|
||||
metabase.search.spec}
|
||||
metabase.server #{metabase.server.core
|
||||
;;
|
||||
;; TODO FIXME -- this is loaded for side effects since it contains the JSON
|
||||
;; encoder logic for stuff like `java.time` classes. As a
|
||||
;; result, [[metabase.models.setting]] (and thus the `metabase.models` module)
|
||||
;; has to depend on the `metabase.server` module...we should create either a new
|
||||
;; `metabase.json` or `metabase.encoders` module for stuff like this to live. Or
|
||||
;; maybe it just belongs in a generic `metabase.config` module.
|
||||
metabase.server.middleware.json
|
||||
;;
|
||||
;; TODO -- we can't make this part of [[metabase.server.core]] YET because it
|
||||
;; causes circular dependencies. Maybe in the future once we tease apart more of
|
||||
;; the modules tangle we can.
|
||||
metabase.server.protocols}
|
||||
metabase.setup #{metabase.setup}
|
||||
metabase.sync #{metabase.sync
|
||||
metabase.sync.analyze
|
||||
metabase.sync.concurrent
|
||||
metabase.sync.field-values
|
||||
metabase.sync.schedules
|
||||
metabase.sync.sync-metadata
|
||||
metabase.sync.sync-metadata.fields
|
||||
metabase.sync.sync-metadata.tables
|
||||
metabase.sync.util} ; TODO -- consolidate these into a real API namespace.
|
||||
metabase.task #{metabase.task
|
||||
metabase.task.bootstrap
|
||||
metabase.task.index-values
|
||||
metabase.task.persist-refresh
|
||||
;; We need to expose this to the metabase.search module.
|
||||
;; Ideally, it would just live inside that module.
|
||||
metabase.task.search-index} ; TODO -- consolidate these into a real API namespace.
|
||||
metabase.troubleshooting #{metabase.troubleshooting}
|
||||
metabase.types #{metabase.types}
|
||||
metabase.upload #{metabase.upload}
|
||||
metabase.util :any ; I think util being `:any` is actually something I am ok with. But this has 32 namespaces.
|
||||
metabase.xrays #{metabase.xrays}}
|
||||
|
||||
;; Map of module => other modules you're allowed to use there. You have two options here:
|
||||
;;
|
||||
;; 1. `:any` means namespaces in this module are allowed to use any other module -- allowed modules are not
|
||||
;; enforced for this module. Module API namespaces for modules that have them defined are still enforced. For
|
||||
;; ones that are `nil`, please go in and add a list of allowed modules. `:any` is mostly meant a temporary
|
||||
;; placeholder until we can fill these all out, so feel free to fix these.
|
||||
;;
|
||||
;; 2. A set of module symbols. This is the list of modules that are allowed to be referenced. An empty set means no
|
||||
;; other modules are allowed to be referenced; this is the default for any modules that aren't listed here.
|
||||
:allowed-modules
|
||||
{metabase.actions :any
|
||||
metabase.analytics :any
|
||||
metabase.analyze :any
|
||||
metabase.api :any
|
||||
metabase.async :any
|
||||
metabase.audit :any
|
||||
metabase.auth-provider #{metabase.util
|
||||
metabase.premium-features}
|
||||
metabase.bootstrap #{}
|
||||
metabase.cmd :any
|
||||
metabase.compatibility :any
|
||||
metabase.channel :any
|
||||
metabase.config #{metabase.plugins}
|
||||
metabase.core :any
|
||||
metabase.db :any
|
||||
metabase.driver :any
|
||||
metabase.email :any
|
||||
metabase.embed :any
|
||||
metabase.events :any
|
||||
metabase.formatter :any
|
||||
metabase.integrations :any
|
||||
metabase.legacy-mbql :any
|
||||
metabase.lib :any
|
||||
metabase.logger #{metabase.config
|
||||
metabase.plugins}
|
||||
metabase.metabot :any
|
||||
metabase.models :any
|
||||
metabase.moderation :any
|
||||
metabase.notification :any
|
||||
metabase.permissions :any
|
||||
metabase.plugins :any
|
||||
metabase.premium-features :any
|
||||
metabase.public-settings :any
|
||||
metabase.pulse :any
|
||||
metabase.query-analysis #{metabase.config
|
||||
metabase.driver
|
||||
metabase.legacy-mbql
|
||||
metabase.lib
|
||||
metabase.models
|
||||
metabase.public-settings
|
||||
metabase.query-processor
|
||||
metabase.util}
|
||||
metabase.query-processor :any
|
||||
metabase.related :any
|
||||
metabase.request #{metabase.config
|
||||
metabase.models
|
||||
metabase.public-settings
|
||||
metabase.util}
|
||||
metabase.sample-data :any
|
||||
metabase.search :any
|
||||
metabase.server :any
|
||||
metabase.setup :any
|
||||
metabase.sync :any
|
||||
metabase.task :any
|
||||
metabase.troubleshooting :any
|
||||
metabase.types #{metabase.util}
|
||||
metabase.upload :any
|
||||
metabase.util :any ; TODO -- this should probably be #{}
|
||||
metabase.xrays :any}
|
||||
|
||||
;; namespaces matching these patterns (with `re-find`) are excluded from the module linter. Since regex literals
|
||||
;; aren't allowed in EDN just used the `(str <regex>)` version i.e. two slashes instead of one.
|
||||
;;
|
||||
;; this is mostly intended for excluding test namespaces or those rare 'glue' namespaces that glue multiple modules
|
||||
;; together, e.g. `metabase.lib.metadata.jvm`.
|
||||
:ignored-namespace-patterns
|
||||
#{"-test$" ; anything ending in `-test`
|
||||
"test[-.]util" ; anything that contains `test.util` or `test-util`
|
||||
"test\\.impl" ; anything that contains `test.impl`
|
||||
"^metabase\\.test" ; anything starting with `metabase.test`
|
||||
"^metabase\\.http-client$"}} ; `metabase.http-client` which is a test-only namespace despite its name.
|
||||
|
||||
:consistent-alias
|
||||
{:aliases
|
||||
{buddy.core.hash buddy-hash
|
||||
@@ -540,6 +341,7 @@
|
||||
medley.core m
|
||||
metabase-enterprise.audit-app.pages.common common
|
||||
metabase-enterprise.sandbox.api.table table
|
||||
metabase-enterprise.sandbox.api.util sandbox.api.util
|
||||
metabase-enterprise.test met
|
||||
metabase.analytics.sdk sdk
|
||||
metabase.analytics.stats stats
|
||||
@@ -554,52 +356,10 @@
|
||||
metabase.analyze.fingerprint.fingerprinters fingerprinters
|
||||
metabase.analyze.fingerprint.insights insights
|
||||
metabase.analyze.fingerprint.schema fingerprint.schema
|
||||
metabase.api.activity api.activity
|
||||
metabase.api.alert api.alert
|
||||
metabase.api.automagic-dashboards api.magic
|
||||
metabase.api.bookmark api.bookmark
|
||||
metabase.api.card api.card
|
||||
metabase.api.card-test api.card-test
|
||||
metabase.api.collection api.collection
|
||||
metabase.api.common api
|
||||
metabase.api.dashboard api.dashboard
|
||||
metabase.api.dashboard-test api.dashboard-test
|
||||
metabase.api.database api.database
|
||||
metabase.api.dataset api.dataset
|
||||
metabase.api.email api.email
|
||||
metabase.api.embed api.embed
|
||||
metabase.api.field api.field
|
||||
metabase.api.geojson api.geojson
|
||||
metabase.api.ldap api.ldap
|
||||
metabase.api.logic-history api.login-history
|
||||
metabase.api.metric api.metric
|
||||
metabase.api.native-query-snippet api.native-query-snippet
|
||||
metabase.api.notify api.notify
|
||||
metabase.api.permission-graph api.permission-graph
|
||||
metabase.api.permissions api.permissions
|
||||
metabase.api.permissions-test-util perm-test-util
|
||||
metabase.api.pivots api.pivots
|
||||
metabase.api.premium-features api.premium-features
|
||||
metabase.api.preview-embed api.preview-embed
|
||||
metabase.api.public api.public
|
||||
metabase.api.pulse api.pulse
|
||||
metabase.api.revision api.revision
|
||||
metabase.api.search api.search
|
||||
metabase.api.segment api.segment
|
||||
metabase.api.session api.session
|
||||
metabase.api.setting api.setting
|
||||
metabase.api.setup api.setup
|
||||
metabase.api.slack api.slack
|
||||
metabase.api.table api.table
|
||||
metabase.api.task api.task
|
||||
metabase.api.tiles api.tiles
|
||||
metabase.api.timeline api.timeline
|
||||
metabase.api.timeline-event api.timeline-event
|
||||
metabase.api.user api.user
|
||||
metabase.api.util api.util
|
||||
metabase.async.streaming-response.thread-pool thread-pool
|
||||
metabase.channel.core channel
|
||||
metabase.channel.render.core channel.render
|
||||
metabase.cloud-migration.core cloud-migration
|
||||
metabase.cmd.copy.h2 copy.h2
|
||||
metabase.config config
|
||||
metabase.config.file config.file
|
||||
@@ -640,8 +400,6 @@
|
||||
metabase.driver.sql.parameters.substitute sql.params.substitute
|
||||
metabase.driver.sql.parameters.substitution sql.params.substitution
|
||||
metabase.eid-translation eid-translation
|
||||
metabase.email-test et
|
||||
metabase.email.messages messages
|
||||
metabase.formatter formatter
|
||||
metabase.http-client client
|
||||
metabase.legacy-mbql.normalize mbql.normalize
|
||||
@@ -649,38 +407,17 @@
|
||||
metabase.legacy-mbql.util mbql.u
|
||||
metabase.lib.util lib.util
|
||||
metabase.lib.util.match lib.util.match
|
||||
metabase.models.activity activity
|
||||
metabase.models.application-permissions-revision a-perm-revision
|
||||
metabase.models.bookmark bookmark
|
||||
metabase.models.collection collection
|
||||
metabase.models.collection.graph graph
|
||||
metabase.models.collection-permission-graph-revision c-perm-revision
|
||||
metabase.models.channel models.channel
|
||||
metabase.models.dashboard-card dashboard-card
|
||||
metabase.models.database database
|
||||
metabase.login-history.core login-history
|
||||
metabase.model-persistence.core model-persistence
|
||||
metabase.models.dependency dependency
|
||||
metabase.models.field-values field-values
|
||||
metabase.models.interface mi
|
||||
metabase.models.moderation-review moderation-review
|
||||
metabase.models.native-query-snippet native-query-snippet
|
||||
metabase.models.notification models.notification
|
||||
metabase.models.params params
|
||||
metabase.models.permissions perms
|
||||
metabase.models.permissions-group perms-group
|
||||
metabase.models.permissions-group-membership perms-group-membership
|
||||
metabase.models.permissions-revision perms-revision
|
||||
metabase.models.permissions.parse perms-parse
|
||||
metabase.models.pulse models.pulse
|
||||
metabase.models.pulse-channel pulse-channel
|
||||
metabase.models.pulse-channel-recipient pulse-channel-recipient
|
||||
metabase.models.query.permissions query-perms
|
||||
metabase.models.setting.cache setting.cache
|
||||
metabase.models.timeline timeline
|
||||
metabase.models.timeline-event timeline-event
|
||||
metabase.models.setting setting
|
||||
metabase.notification.core notification
|
||||
metabase.notification.test-util notification.tu
|
||||
metabase.permissions.core perms
|
||||
metabase.plugins.initialize plugins.init
|
||||
metabase.public-settings public-settings
|
||||
metabase.public-sharing.core public-sharing
|
||||
metabase.premium-features.core premium-features
|
||||
metabase.pulse.core pulse
|
||||
metabase.pulse.render render
|
||||
@@ -712,8 +449,8 @@
|
||||
metabase.query-processor.streaming.xlsx qp.xlsx
|
||||
metabase.query-processor.timezone qp.timezone
|
||||
metabase.query-processor.util qp.util
|
||||
metabase.related related
|
||||
metabase.request.core request
|
||||
metabase.revisions.core revisions
|
||||
metabase.search.config search.config
|
||||
metabase.search.filter search.filter
|
||||
metabase.search.in-place.filter search.in-place.filter
|
||||
@@ -721,6 +458,7 @@
|
||||
metabase.search.in-place.scoring scoring
|
||||
metabase.server.core server
|
||||
metabase.server.protocols server.protocols
|
||||
metabase.sso.core sso
|
||||
metabase.sync.analyze.fingerprint sync.fingerprint
|
||||
metabase.sync.field-values sync.field-values
|
||||
metabase.sync.interface i
|
||||
@@ -728,7 +466,6 @@
|
||||
metabase.sync.sync-metadata.fields.our-metadata fields.our-metadata
|
||||
metabase.sync.util sync-util
|
||||
metabase.sync.util-test sync.util-test
|
||||
metabase.task.sync-databases task.sync-databases
|
||||
metabase.test mt
|
||||
metabase.test.data.dataset-definitions defs
|
||||
metabase.test.data.env.impl tx.env.impl
|
||||
@@ -740,6 +477,7 @@
|
||||
metabase.test.redefs test.redefs
|
||||
metabase.test.util.js test.js
|
||||
metabase.test.util.timezone test.tz
|
||||
metabase.timeline.core timeline
|
||||
metabase.timeseries-query-processor-test.util tqpt
|
||||
metabase.util.cron u.cron
|
||||
metabase.util.currency currency
|
||||
@@ -764,7 +502,7 @@
|
||||
metabase.util.schema su
|
||||
metabase.util.ui-logic ui-logic
|
||||
metabase.util.urls urls
|
||||
metabase.xrays xrays
|
||||
metabase.xrays.core xrays
|
||||
metabuild-common.core u
|
||||
metabuild-common.output out
|
||||
metabuild-common.shell shell
|
||||
@@ -782,17 +520,15 @@
|
||||
clojure.core.cache/defcache clojure.core/deftype
|
||||
clojure.core.logic/defne clj-kondo.lint-as/def-catch-all
|
||||
clojure.test.check.clojure-test/defspec clojure.test/deftest
|
||||
clojure.test.check.properties/for-all clojure.core/let
|
||||
clojurewerkz.quartzite.jobs/defjob clojure.core/defn
|
||||
metabase-enterprise.serialization.test-util/with-dbs clojure.core/fn
|
||||
metabase-enterprise.serialization.test-util/with-random-dump-dir clojure.core/let
|
||||
metabase.actions.test-util/with-actions clojure.core/let
|
||||
metabase.api.common/defroutes clojure.core/def
|
||||
metabase.api.common/let-404 clojure.core/let
|
||||
metabase.api.search-test/do-test-users clojure.core/let
|
||||
metabase.async.api-response-test/with-response clojure.core/let
|
||||
metabase.dashboard-subscription-test/with-dashboard-sub-for-card clojure.core/let
|
||||
metabase.channel.impl.http-test/with-captured-http-requests clojure.core/fn
|
||||
metabase.channel.impl.http-test/with-server clojure.core/let
|
||||
metabase.dashboard-subscription-test/with-dashboard-sub-for-card clojure.core/let
|
||||
metabase.db.custom-migrations/define-migration clj-kondo.lint-as/def-catch-all
|
||||
metabase.db.custom-migrations/define-reversible-migration clj-kondo.lint-as/def-catch-all
|
||||
metabase.db.data-migrations/defmigration clojure.core/def
|
||||
@@ -804,14 +540,12 @@
|
||||
metabase.driver.sql-jdbc.actions/with-jdbc-transaction clojure.core/let
|
||||
metabase.driver.sql-jdbc.connection/with-connection-spec-for-testing-connection clojure.core/let
|
||||
metabase.driver.sql-jdbc.execute.diagnostic/capturing-diagnostic-info clojure.core/fn
|
||||
metabase.integrations.ldap/with-ldap-connection clojure.core/fn
|
||||
metabase.models.collection-test/with-collection-in-location clojure.core/let
|
||||
metabase.models.json-migration/def-json-migration clj-kondo.lint-as/def-catch-all
|
||||
metabase.models.setting.multi-setting/define-multi-setting clojure.core/def
|
||||
metabase.models.setting/defsetting clj-kondo.lint-as/def-catch-all
|
||||
metabase.premium-features.core/defenterprise-schema clj-kondo.lint-as/def-catch-all
|
||||
metabase.premium-features.defenterprise/defenterprise-schema clj-kondo.lint-as/def-catch-all
|
||||
metabase.premium-features.core/define-premium-feature clojure.core/def
|
||||
metabase.premium-features.defenterprise/defenterprise-schema clj-kondo.lint-as/def-catch-all
|
||||
metabase.pulse.send-test/with-pulse-for-card clojure.core/let
|
||||
metabase.query-processor-test.pipeline-queries-test/pmbql-query clojure.core/->
|
||||
metabase.query-processor-test.pipeline-queries-test/run-pmbql-query clojure.core/->
|
||||
@@ -819,6 +553,8 @@
|
||||
metabase.query-processor.middleware.cache.impl/with-reducible-deserialized-results clojure.core/let
|
||||
metabase.query-processor.middleware.process-userland-query-test/with-query-execution! clojure.core/let
|
||||
metabase.query-processor.setup/with-qp-setup clojure.core/let
|
||||
metabase.search.api-test/do-test-users clojure.core/let
|
||||
metabase.sso.ldap/with-ldap-connection clojure.core/fn
|
||||
metabase.sync.util/sum-for clojure.core/for
|
||||
metabase.sync.util/with-emoji-progress-bar clojure.core/let
|
||||
metabase.test.data.interface/defdataset clojure.core/def
|
||||
@@ -834,6 +570,7 @@
|
||||
metabase.test/with-temp-file clojure.core/let
|
||||
metabase.test/with-user-in-groups clojure.core/let
|
||||
metabase.upload-test/with-upload-table! clojure.core/let
|
||||
metabase.util/with-timer-ms clojure.core/fn
|
||||
metabase.util.files/with-open-path-to-resource clojure.core/let
|
||||
metabase.util.malli.defn/defn schema.core/defn
|
||||
metabase.util.malli.defn/defn- schema.core/defn
|
||||
@@ -862,7 +599,10 @@
|
||||
{cljs.test/deftest hooks.clojure.test/deftest
|
||||
cljs.test/is hooks.clojure.test/is
|
||||
cljs.test/use-fixtures hooks.clojure.test/use-fixtures
|
||||
clojure.core/ns hooks.clojure.core/lint-ns
|
||||
clojure.core/defmulti hooks.clojure.core.defmulti/lint-defmulti
|
||||
clojure.core/ns hooks.clojure.core.ns/lint-ns
|
||||
clojure.core/require hooks.clojure.core.require/lint-require
|
||||
clojure.core/requiring-resolve hooks.clojure.core.require/lint-requiring-resolve
|
||||
clojure.test/deftest hooks.clojure.test/deftest
|
||||
clojure.test/is hooks.clojure.test/is
|
||||
clojure.test/use-fixtures hooks.clojure.test/use-fixtures
|
||||
@@ -871,17 +611,10 @@
|
||||
metabase-enterprise.audit-app.pages-test/with-temp-objects hooks.common/with-one-binding
|
||||
metabase-enterprise.cache.config-test/with-temp-persist-models hooks.common/with-seven-bindings
|
||||
metabase-enterprise.serialization.test-util/with-temp-dpc hooks.toucan2.tools.with-temp/with-temp
|
||||
metabase.analytics.prometheus-test/with-prometheus-system! hooks.common/with-two-bindings
|
||||
metabase.api.alert-test/with-alert-in-collection! hooks.common/with-four-bindings
|
||||
metabase.api.automagic-dashboards-test/with-indexed-model! hooks.metabase.api.automagic-dashboards-test/with-indexed-model!
|
||||
metabase.api.card-test/with-card-param-values-fixtures hooks.common/let-one-with-optional-value
|
||||
metabase.api.card-test/with-persistence-setup! hooks.common/with-one-top-level-binding
|
||||
metabase.api.card-test/with-temp-native-card! hooks.common/with-two-bindings
|
||||
metabase.api.card-test/with-temp-native-card-with-params! hooks.common/with-two-bindings
|
||||
metabase.api.collection-test/with-french-user-and-personal-collection! hooks.common/with-two-top-level-bindings
|
||||
metabase.api.common/defendpoint hooks.metabase.api.common/defendpoint
|
||||
metabase.api.common/defendpoint-async hooks.metabase.api.common/defendpoint
|
||||
metabase.api.common/defendpoint-async-schema hooks.metabase.api.common/defendpoint
|
||||
metabase.api.common.internal-test/with-jetty-server hooks.common/with-one-binding
|
||||
metabase.api.dashboard-test/with-chain-filter-fixtures hooks.common/let-one-with-optional-value
|
||||
metabase.api.dashboard-test/with-simple-dashboard-with-tabs hooks.common/with-one-binding
|
||||
@@ -890,17 +623,9 @@
|
||||
metabase.api.embed-test/with-temp-card hooks.common/let-one-with-optional-value
|
||||
metabase.api.embed-test/with-temp-dashcard hooks.common/let-one-with-optional-value
|
||||
metabase.api.macros/defendpoint hooks.metabase.api.macros/defendpoint
|
||||
metabase.api.persist-test/with-setup! hooks.common/with-one-top-level-binding
|
||||
metabase.api.public-test/with-required-param-card! hooks.common/with-one-binding
|
||||
metabase.api.public-test/with-temp-public-card hooks.common/let-one-with-optional-value
|
||||
metabase.api.public-test/with-temp-public-dashboard hooks.common/let-one-with-optional-value
|
||||
metabase.api.public-test/with-temp-public-dashboard-and-card hooks.common/with-three-bindings
|
||||
metabase.api.search-test/with-search-items-in-collection hooks.metabase.api.search-test/with-search-items-in-collection
|
||||
metabase.api.search-test/with-search-items-in-root-collection hooks.common/do*
|
||||
metabase.api.user-test/with-temp-user-email hooks.common/with-one-binding
|
||||
metabase.async.streaming-response-test/with-start-execution-chan hooks.common/with-one-binding
|
||||
metabase.channel.template.handlebars-test/with-temp-template! hooks.common/with-vec-first-binding
|
||||
metabase.api.user-test/with-temp-user-email! hooks.common/with-one-binding
|
||||
metabase.channel.template.handlebars-helper/defhelper hooks.metabase.channel.template.handlebars-helper/defhelper
|
||||
metabase.channel.template.handlebars-test/with-temp-template! hooks.common/with-vec-first-binding
|
||||
metabase.dashboard-subscription-test/with-link-card-fixture-for-dashboard hooks.common/let-second
|
||||
metabase.db.schema-migrations-test.impl/test-migrations hooks.metabase.db.schema-migrations-test.impl/test-migrations
|
||||
metabase.driver.bigquery-cloud-sdk-test/calculate-bird-scarcity hooks.metabase.query-processor-test.expressions-test/calculate-bird-scarcity
|
||||
@@ -913,18 +638,30 @@
|
||||
metabase.lib.test-util.macros/$ids hooks.metabase.test.data/$ids
|
||||
metabase.lib.test-util.macros/mbql-query hooks.metabase.test.data/mbql-query
|
||||
metabase.lib.test-util.macros/with-testing-against-standard-queries hooks.metabase.lib.test-util.macros/with-testing-against-standard-queries
|
||||
metabase.model-persistence.api-test/with-persistence-setup! hooks.common/with-one-top-level-binding
|
||||
metabase.model-persistence.api-test/with-setup! hooks.common/with-one-top-level-binding
|
||||
metabase.model-persistence.test-util/with-persistence-enabled! hooks.metabase.model-persistence.test-util/with-persistence-enabled!
|
||||
metabase.models.collection-test/with-collection-hierarchy! hooks.common/let-one-with-optional-value
|
||||
metabase.models.collection-test/with-personal-and-impersonal-collections hooks.common/with-two-bindings
|
||||
metabase.models.dashboard-tab-test/with-dashtab-in-personal-collection hooks.common/with-one-top-level-binding
|
||||
metabase.models.dashboard-test/with-dash-in-collection! hooks.common/with-three-bindings
|
||||
metabase.models.interface/define-batched-hydration-method hooks.metabase.models.interface/define-hydration-method
|
||||
metabase.models.interface/define-simple-hydration-method hooks.metabase.models.interface/define-hydration-method
|
||||
metabase.models.pulse-test/with-dashboard-subscription-in-collection! hooks.common/with-four-bindings
|
||||
metabase.models.pulse-test/with-pulse-in-collection! hooks.common/with-four-bindings
|
||||
metabase.models.setting.multi-setting/define-multi-setting hooks.metabase.models.setting/define-multi-setting
|
||||
metabase.models.setting.multi-setting/define-multi-setting-impl hooks.metabase.models.setting/define-multi-setting-impl
|
||||
metabase.models.setting/defsetting hooks.metabase.models.setting/defsetting
|
||||
metabase.permissions.core/allow-changing-all-users-group-members hooks.common/do*
|
||||
metabase.permissions.core/disable-perms-cache hooks.common/do*
|
||||
metabase.plugins.classloader/require hooks.clojure.core.require/lint-require
|
||||
metabase.premium-features.core/defenterprise hooks.metabase.premium-features.defenterprise/defenterprise
|
||||
metabase.premium-features.defenterprise/defenterprise hooks.metabase.premium-features.defenterprise/defenterprise
|
||||
metabase.public-sharing.api-test/with-required-param-card! hooks.common/with-one-binding
|
||||
metabase.public-sharing.api-test/with-temp-public-card hooks.common/let-one-with-optional-value
|
||||
metabase.public-sharing.api-test/with-temp-public-dashboard hooks.common/let-one-with-optional-value
|
||||
metabase.public-sharing.api-test/with-temp-public-dashboard-and-card hooks.common/with-three-bindings
|
||||
metabase.pulse.api.alert-test/with-alert-in-collection! hooks.common/with-four-bindings
|
||||
metabase.pulse.models.pulse-test/with-dashboard-subscription-in-collection! hooks.common/with-four-bindings
|
||||
metabase.pulse.models.pulse-test/with-pulse-in-collection! hooks.common/with-four-bindings
|
||||
metabase.pulse.test-util/checkins-query-card hooks.metabase.test.data/$ids
|
||||
metabase.query-processor-test.expressions-test/calculate-bird-scarcity hooks.metabase.query-processor-test.expressions-test/calculate-bird-scarcity
|
||||
metabase.query-processor-test.filter-test/count-with-filter-clause hooks.metabase.test.data/$ids
|
||||
@@ -933,6 +670,9 @@
|
||||
metabase.request.core/with-current-user hooks.common/with-used-first-arg
|
||||
metabase.request.core/with-limit-and-offset hooks.common/with-used-first-two-args
|
||||
metabase.sample-data-test/with-temp-sample-database-db hooks.common/with-one-binding
|
||||
metabase.search.api-test/with-search-items-in-collection hooks.metabase.search.api-test/with-search-items-in-collection
|
||||
metabase.search.api-test/with-search-items-in-root-collection hooks.common/do*
|
||||
metabase.server.streaming-response-test/with-start-execution-chan hooks.common/with-one-binding
|
||||
metabase.stale-test/with-stale-items hooks.toucan2.tools.with-temp/with-temp
|
||||
metabase.test.data.datasets/test-driver hooks.metabase.test.data.datasets/test-driver
|
||||
metabase.test.data.datasets/test-drivers hooks.metabase.test.data.datasets/test-drivers
|
||||
@@ -941,11 +681,13 @@
|
||||
metabase.test.data/dataset hooks.metabase.test.data/dataset
|
||||
metabase.test.data/mbql-query hooks.metabase.test.data/mbql-query
|
||||
metabase.test.data/run-mbql-query hooks.metabase.test.data/mbql-query
|
||||
metabase.test.gentest/with-gentest hooks.metabase.test.gentest/with-gentest
|
||||
metabase.test.util.async/with-open-channels hooks.common/let-with-optional-value-for-last-binding
|
||||
metabase.test.util.log/with-log-level hooks.common/with-ignored-first-arg
|
||||
metabase.test.util/discard-setting-changes hooks.common/with-ignored-first-arg
|
||||
metabase.test.util/with-column-remappings hooks.common/with-ignored-first-arg
|
||||
metabase.test.util/with-non-admin-groups-no-root-collection-perms hooks.common/do*
|
||||
metabase.test.util/with-prometheus-system! hooks.common/with-two-bindings
|
||||
metabase.test.util/with-temp-file hooks.metabase.test.util/with-temp-file
|
||||
metabase.test.util/with-temporary-setting-values hooks.metabase.test.util/with-temporary-setting-values
|
||||
metabase.test/$ids hooks.metabase.test.data/$ids
|
||||
@@ -961,8 +703,10 @@
|
||||
metabase.test/with-log-level hooks.common/with-ignored-first-arg
|
||||
metabase.test/with-log-messages-for-level hooks.metabase.util.log.capture/with-log-messages-for-level
|
||||
metabase.test/with-non-admin-groups-no-root-collection-perms hooks.common/do*
|
||||
metabase.test/with-persistence-enabled! hooks.metabase.model-persistence.test-util/with-persistence-enabled!
|
||||
metabase.test/with-temp hooks.toucan2.tools.with-temp/with-temp
|
||||
metabase.test/with-temp-file hooks.metabase.test.util/with-temp-file
|
||||
metabase.test/with-prometheus-system! hooks.common/with-two-bindings
|
||||
metabase.test/with-temporary-setting-values hooks.metabase.test.util/with-temporary-setting-values
|
||||
metabase.util.log.capture/with-log-messages-for-level hooks.metabase.util.log.capture/with-log-messages-for-level
|
||||
metabase.util.log/debug hooks.metabase.util.log/info
|
||||
@@ -979,46 +723,45 @@
|
||||
metabase.util.log/warnf hooks.metabase.util.log/infof
|
||||
metabase.util.malli.registry/def hooks.metabase.util.malli.registry/def
|
||||
metabase.util/case-enum hooks.metabase.util/case-enum
|
||||
metabase.util/format-color hooks.metabase.util/format-color}
|
||||
metabase.util/format-color hooks.metabase.util/format-color
|
||||
metabase.xrays.api.automagic-dashboards-test/with-indexed-model! hooks.metabase.xrays.api.automagic-dashboards-test/with-indexed-model!}
|
||||
|
||||
:macroexpand
|
||||
{clojurewerkz.quartzite.jobs/build macros.quartz/build-job
|
||||
clojurewerkz.quartzite.schedule.cron/schedule macros.quartz/schedule
|
||||
clojurewerkz.quartzite.schedule.simple/schedule macros.quartz/simple-schedule
|
||||
clojurewerkz.quartzite.triggers/build macros.quartz/build-trigger
|
||||
metabase-enterprise.sandbox.test-util/with-gtaps! macros.metabase-enterprise.sandbox.test-util/with-gtaps!
|
||||
metabase-enterprise.sandbox.test-util/with-gtaps-for-user! macros.metabase-enterprise.sandbox.test-util/with-gtaps!
|
||||
metabase-enterprise.serialization.test-util/with-world macros.metabase-enterprise.serialization.test-util/with-world
|
||||
metabase-enterprise.test/with-gtaps! macros.metabase-enterprise.sandbox.test-util/with-gtaps!
|
||||
metabase-enterprise.test/with-gtaps-for-user! macros.metabase-enterprise.sandbox.test-util/with-gtaps!
|
||||
metabase-enterprise.advanced-permissions.api.util-test/with-impersonations! macros.metabase-enterprise.advanced-permissions.api.util-test/with-impersonations!
|
||||
metabase-enterprise.query-reference-validation.api-test/with-test-setup! macros.metabase-enterprise.query-reference-validation.api-test/with-test-setup!
|
||||
metabase.api.card-test/with-ordered-items macros.metabase.api.card-test/with-ordered-items
|
||||
metabase.api.collection-test/with-collection-hierarchy! macros.metabase.api.collection-test/with-collection-hierarchy!
|
||||
metabase.api.collection-test/with-some-children-of-collection! macros.metabase.api.collection-test/with-some-children-of-collection!
|
||||
metabase.api.common/define-routes macros.metabase.api.common/define-routes
|
||||
metabase.api.embed-test/with-embedding-enabled-and-temp-card-referencing! macros.metabase.api.embed-test/with-embedding-enabled-and-temp-card-referencing!
|
||||
metabase.api.embed-test/with-embedding-enabled-and-temp-dashcard-referencing! macros.metabase.api.embed-test/with-embedding-enabled-and-temp-dashcard-referencing!
|
||||
metabase.api.public-test/with-sharing-enabled-and-temp-card-referencing! macros.metabase.api.public-test/with-sharing-enabled-and-temp-card-referencing!
|
||||
metabase.api.public-test/with-sharing-enabled-and-temp-dashcard-referencing! macros.metabase.api.public-test/with-sharing-enabled-and-temp-dashcard-referencing!
|
||||
metabase.lib.filter/deffilter macros.metabase.lib.filter/deffilter
|
||||
metabase.lib.common/defop macros.metabase.lib.common/defop
|
||||
metabase.models.params.chain-filter-test/chain-filter macros.metabase.models.params.chain-filter-test/chain-filter
|
||||
metabase.models.params.chain-filter-test/chain-filter-search macros.metabase.models.params.chain-filter-test/chain-filter
|
||||
metabase.models.query-analysis-test/with-test-setup macros.metabase.models.query-analysis-test/with-test-setup
|
||||
metabase.models.user-test/with-groups macros.metabase.models.user-test/with-groups
|
||||
metabase.query-processor.streaming/streaming-response macros.metabase.query-processor.streaming/streaming-response
|
||||
metabase.related-test/with-world macros.metabase.related-test/with-world
|
||||
metabase.task.setup.query-analysis-setup/with-test-setup! macros.metabase.task.setup.query-analysis-setup/with-test-setup!
|
||||
metabase.test.data.users/with-group-for-user macros.metabase.test.data.users/with-group-for-user
|
||||
metabase.test.util/with-temp-env-var-value! macros.metabase.test.util/with-temp-env-var-value!
|
||||
metabase.test.util/with-temporary-raw-setting-values macros.metabase.test.util/with-temporary-raw-setting-values
|
||||
metabase.test/with-group-for-user macros.metabase.test.data.users/with-group-for-user
|
||||
metabase.test/with-persistence-enabled! macros.metabase.test.persistence/with-persistence-enabled!
|
||||
metabase.test/with-temp-env-var-value! macros.metabase.test.util/with-temp-env-var-value!
|
||||
metabase.test/with-temporary-raw-setting-values macros.metabase.test.util/with-temporary-raw-setting-values
|
||||
metabase.util.namespaces/import-fn macros.metabase.util.namespaces/import-fn
|
||||
metabase.xrays.domain-entities.malli/define-getters-and-setters macros.metabase.xrays.domain-entities.malli/define-getters-and-setters}}
|
||||
{clojurewerkz.quartzite.jobs/build macros.quartz/build-job
|
||||
clojurewerkz.quartzite.schedule.cron/schedule macros.quartz/schedule
|
||||
clojurewerkz.quartzite.schedule.simple/schedule macros.quartz/simple-schedule
|
||||
clojurewerkz.quartzite.triggers/build macros.quartz/build-trigger
|
||||
metabase-enterprise.advanced-permissions.api.util-test/with-impersonations! macros.metabase-enterprise.advanced-permissions.api.util-test/with-impersonations!
|
||||
metabase-enterprise.query-reference-validation.api-test/with-test-setup! macros.metabase-enterprise.query-reference-validation.api-test/with-test-setup!
|
||||
metabase-enterprise.sandbox.test-util/with-gtaps! macros.metabase-enterprise.sandbox.test-util/with-gtaps!
|
||||
metabase-enterprise.sandbox.test-util/with-gtaps-for-user! macros.metabase-enterprise.sandbox.test-util/with-gtaps!
|
||||
metabase-enterprise.serialization.test-util/with-world macros.metabase-enterprise.serialization.test-util/with-world
|
||||
metabase-enterprise.test/with-gtaps! macros.metabase-enterprise.sandbox.test-util/with-gtaps!
|
||||
metabase-enterprise.test/with-gtaps-for-user! macros.metabase-enterprise.sandbox.test-util/with-gtaps!
|
||||
metabase.api.card-test/with-ordered-items macros.metabase.api.card-test/with-ordered-items
|
||||
metabase.api.collection-test/with-collection-hierarchy! macros.metabase.api.collection-test/with-collection-hierarchy!
|
||||
metabase.api.collection-test/with-some-children-of-collection! macros.metabase.api.collection-test/with-some-children-of-collection!
|
||||
metabase.api.embed-test/with-embedding-enabled-and-temp-card-referencing! macros.metabase.api.embed-test/with-embedding-enabled-and-temp-card-referencing!
|
||||
metabase.api.embed-test/with-embedding-enabled-and-temp-dashcard-referencing! macros.metabase.api.embed-test/with-embedding-enabled-and-temp-dashcard-referencing!
|
||||
metabase.lib.common/defop macros.metabase.lib.common/defop
|
||||
metabase.lib.filter/deffilter macros.metabase.lib.filter/deffilter
|
||||
metabase.models.params.chain-filter-test/chain-filter macros.metabase.models.params.chain-filter-test/chain-filter
|
||||
metabase.models.params.chain-filter-test/chain-filter-search macros.metabase.models.params.chain-filter-test/chain-filter
|
||||
metabase.models.query-analysis-test/with-test-setup macros.metabase.models.query-analysis-test/with-test-setup
|
||||
metabase.models.user-test/with-groups macros.metabase.models.user-test/with-groups
|
||||
metabase.public-sharing.api-test/with-sharing-enabled-and-temp-card-referencing! macros.metabase.public-sharing.api-test/with-sharing-enabled-and-temp-card-referencing!
|
||||
metabase.public-sharing.api-test/with-sharing-enabled-and-temp-dashcard-referencing! macros.metabase.public-sharing.api-test/with-sharing-enabled-and-temp-dashcard-referencing!
|
||||
metabase.query-analysis.task.test-setup/with-test-setup! macros.metabase.query-analysis.task.test-setup/with-test-setup!
|
||||
metabase.query-processor.streaming/streaming-response macros.metabase.query-processor.streaming/streaming-response
|
||||
metabase.test.data.users/with-group-for-user macros.metabase.test.data.users/with-group-for-user
|
||||
metabase.test.util/with-temp-env-var-value! macros.metabase.test.util/with-temp-env-var-value!
|
||||
metabase.test.util/with-temporary-raw-setting-values macros.metabase.test.util/with-temporary-raw-setting-values
|
||||
metabase.test/with-group-for-user macros.metabase.test.data.users/with-group-for-user
|
||||
metabase.test/with-temp-env-var-value! macros.metabase.test.util/with-temp-env-var-value!
|
||||
metabase.test/with-temporary-raw-setting-values macros.metabase.test.util/with-temporary-raw-setting-values
|
||||
metabase.util.namespaces/import-fn macros.metabase.util.namespaces/import-fn
|
||||
metabase.xrays.domain-entities.malli/define-getters-and-setters macros.metabase.xrays.domain-entities.malli/define-getters-and-setters
|
||||
metabase.xrays.related-test/with-world macros.metabase.xrays.related-test/with-world}}
|
||||
|
||||
:config-in-comment
|
||||
{:linters {:unresolved-symbol {:level :off}}}
|
||||
@@ -1073,9 +816,9 @@
|
||||
|
||||
:hooks
|
||||
{:analyze-call
|
||||
{clojure.core/defmacro hooks.clojure.core/non-thread-safe-form-should-end-with-exclamation
|
||||
clojure.core/defn hooks.clojure.core/non-thread-safe-form-should-end-with-exclamation
|
||||
clojure.core/defn- hooks.clojure.core/non-thread-safe-form-should-end-with-exclamation}}}
|
||||
{clojure.core/defmacro hooks.clojure.core.defn/non-thread-safe-form-should-end-with-exclamation
|
||||
clojure.core/defn hooks.clojure.core.defn/non-thread-safe-form-should-end-with-exclamation
|
||||
clojure.core/defn- hooks.clojure.core.defn/non-thread-safe-form-should-end-with-exclamation}}}
|
||||
|
||||
source-namespaces
|
||||
{:linters
|
||||
|
||||
731
.clj-kondo/config/modules/config.edn
Normal file
@@ -0,0 +1,731 @@
|
||||
;; A "module" is any `metabase.<module>.core` namespace in `src`.
|
||||
;;
|
||||
;; ## `api`:
|
||||
;;
|
||||
;; Map of module name => the "core" external public-facing API namespace(s). You have three options here:
|
||||
;;
|
||||
;; 1. Special sentinel value `:any` means means this module does not (yet) have external public-facing API
|
||||
;; namespace(s). This is mostly a temporary placeholder until we go in and create module namespaces, which means
|
||||
;; you should go create one.
|
||||
;;
|
||||
;; 2. A set of namespace symbols. All namespaces in other modules will only be allowed to use namespaces from
|
||||
;; this set. Ideally this set should only have one namespace, but restricting it to a set of several is still
|
||||
;; better than `:any`.
|
||||
;;
|
||||
;; 3. `nil` or not listed here -- we default to assuming there is (some subset) of the 'standard' API namespaces
|
||||
;; `<module>.api`, `<module>.core`, and `<module>.init`
|
||||
;;
|
||||
;; ## `uses`:
|
||||
;;
|
||||
;; Map of module => other modules you're allowed to use there. You have two options here:
|
||||
;;
|
||||
;; 1. `:any` means namespaces in this module are allowed to use any other module -- allowed modules are not
|
||||
;; enforced for this module. Module API namespaces for modules that have them defined are still enforced. For
|
||||
;; ones that are `nil`, please go in and add a list of allowed modules. `:any` is mostly meant a temporary
|
||||
;; placeholder until we can fill these all out, so feel free to fix these.
|
||||
;;
|
||||
;; 2. A set of module symbols. This is the list of modules that are allowed to be referenced. An empty set means no
|
||||
;; other modules are allowed to be referenced; this is the default for any modules that aren't listed here.
|
||||
;;
|
||||
;; ## Tips
|
||||
;;
|
||||
;; PRO TIP: Check out the [[dev.deps-graph]] namespace for helpful tools to see where a module is used externally, and
|
||||
;; for tools for calculating this config.
|
||||
{:metabase/modules
|
||||
{actions
|
||||
{:api #{metabase.actions.api metabase.actions.core}
|
||||
:uses #{analytics api driver legacy-mbql lib model-persistence models query-processor search util}}
|
||||
|
||||
activity-feed
|
||||
{:api #{metabase.activity-feed.api metabase.activity-feed.init}
|
||||
:uses #{api config db events models util}}
|
||||
|
||||
analytics
|
||||
{:api #{metabase.analytics.core
|
||||
metabase.analytics.prometheus
|
||||
metabase.analytics.snowplow}
|
||||
:uses #{api
|
||||
config
|
||||
db
|
||||
driver
|
||||
eid-translation
|
||||
integrations
|
||||
models
|
||||
premium-features
|
||||
public-settings
|
||||
server
|
||||
util}}
|
||||
analyze
|
||||
{:api #{metabase.analyze.core metabase.analyze.query-results}
|
||||
:uses #{config driver legacy-mbql lib models sync util}}
|
||||
|
||||
api
|
||||
{:api #{metabase.api.cache
|
||||
metabase.api.card
|
||||
metabase.api.collection
|
||||
metabase.api.common
|
||||
metabase.api.common.validation
|
||||
metabase.api.dashboard
|
||||
metabase.api.dataset
|
||||
metabase.api.field
|
||||
metabase.api.macros
|
||||
metabase.api.open-api
|
||||
metabase.api.query-metadata
|
||||
metabase.api.routes
|
||||
metabase.api.routes.common
|
||||
metabase.api.table
|
||||
metabase.api.user
|
||||
metabase.api.util.handlers}
|
||||
:uses :any}
|
||||
|
||||
audit {:api #{metabase.audit}
|
||||
:uses #{db models}}
|
||||
|
||||
auth-provider
|
||||
{:api #{metabase.auth-provider}
|
||||
:uses #{premium-features}}
|
||||
|
||||
bookmarks
|
||||
{:api #{metabase.bookmarks.api}
|
||||
:uses #{api db models util}}
|
||||
|
||||
channel
|
||||
{:api #{metabase.channel.api
|
||||
metabase.channel.core
|
||||
metabase.channel.email
|
||||
metabase.channel.email.messages
|
||||
metabase.channel.init
|
||||
metabase.channel.render.core
|
||||
metabase.channel.template.core}
|
||||
:uses #{analytics
|
||||
api
|
||||
config
|
||||
db
|
||||
driver
|
||||
events
|
||||
formatter
|
||||
integrations
|
||||
lib
|
||||
models
|
||||
notification
|
||||
permissions
|
||||
premium-features
|
||||
public-settings
|
||||
query-processor
|
||||
timeline
|
||||
types
|
||||
util}}
|
||||
|
||||
cloud-migration
|
||||
{:api #{metabase.cloud-migration.api
|
||||
metabase.cloud-migration.core
|
||||
metabase.cloud-migration.init}
|
||||
:uses #{api cmd config db models premium-features util}}
|
||||
|
||||
cmd
|
||||
{:api #{metabase.cmd
|
||||
metabase.cmd.copy
|
||||
metabase.cmd.dump-to-h2}
|
||||
:uses #{api config db legacy-mbql models plugins query-processor search util}}
|
||||
|
||||
;; technically this 'uses' `enterprise/core` and `test` since it tries to load them to see if they exists so we know
|
||||
;; if EE/test code is available; however we can ignore them since they're not real usages.
|
||||
config
|
||||
{:api #{metabase.config}
|
||||
:uses #{}}
|
||||
|
||||
;; this is not actually a real module, but comes from one of our libraries.
|
||||
connection-pool
|
||||
{:api #{metabase.connection-pool}
|
||||
:uses #{}}
|
||||
|
||||
core
|
||||
{:api #{metabase.core.initialization-status}
|
||||
:uses :any}
|
||||
|
||||
db
|
||||
{:api #{metabase.db metabase.db.metadata-queries metabase.db.query metabase.db.setup}
|
||||
:uses #{auth-provider config connection-pool driver legacy-mbql lib plugins query-processor task util}}
|
||||
|
||||
driver
|
||||
{:api #{metabase.driver
|
||||
metabase.driver.common
|
||||
metabase.driver.common.parameters
|
||||
metabase.driver.common.parameters.dates
|
||||
metabase.driver.common.parameters.operators
|
||||
metabase.driver.common.parameters.parse
|
||||
metabase.driver.common.parameters.values
|
||||
metabase.driver.ddl.interface
|
||||
metabase.driver.h2
|
||||
metabase.driver.impl
|
||||
metabase.driver.init
|
||||
metabase.driver.mysql
|
||||
metabase.driver.postgres
|
||||
metabase.driver.sql
|
||||
metabase.driver.sql-jdbc.connection
|
||||
metabase.driver.sql-jdbc.execute
|
||||
metabase.driver.sql-jdbc.execute.diagnostic
|
||||
metabase.driver.sql-jdbc.sync
|
||||
metabase.driver.sql.query-processor
|
||||
metabase.driver.sql.query-processor.deprecated
|
||||
metabase.driver.sql.util
|
||||
metabase.driver.sync
|
||||
metabase.driver.util}
|
||||
:uses #{actions
|
||||
auth-provider
|
||||
config
|
||||
connection-pool
|
||||
db
|
||||
legacy-mbql
|
||||
lib
|
||||
logger
|
||||
models
|
||||
plugins
|
||||
premium-features
|
||||
public-settings
|
||||
pulse
|
||||
query-processor
|
||||
sync
|
||||
upload
|
||||
util}}
|
||||
|
||||
eid-translation
|
||||
{:api #{metabase.eid-translation}
|
||||
:uses #{}}
|
||||
|
||||
embed
|
||||
{:api #{metabase.embed.settings}
|
||||
:uses #{analytics models premium-features util}}
|
||||
|
||||
events
|
||||
{:api #{metabase.events metabase.events.init metabase.events.notification}
|
||||
:uses #{api driver models notification premium-features util}}
|
||||
|
||||
formatter
|
||||
{:api #{metabase.formatter}
|
||||
:uses #{models public-settings query-processor types util}}
|
||||
|
||||
indexed-entities
|
||||
{:api #{metabase.indexed-entities.api metabase.indexed-entities.init}
|
||||
:uses #{analytics api driver legacy-mbql lib models query-processor search sync task util}}
|
||||
|
||||
integrations
|
||||
{:api #{metabase.integrations.slack}
|
||||
:uses #{events models util}}
|
||||
|
||||
legacy-mbql
|
||||
{:api #{metabase.legacy-mbql.normalize
|
||||
metabase.legacy-mbql.predicates
|
||||
metabase.legacy-mbql.schema
|
||||
metabase.legacy-mbql.schema.helpers
|
||||
metabase.legacy-mbql.util}
|
||||
:uses #{lib models types util}}
|
||||
|
||||
lib
|
||||
{:api #{metabase.lib.binning
|
||||
metabase.lib.binning.util
|
||||
metabase.lib.card
|
||||
metabase.lib.convert
|
||||
metabase.lib.core
|
||||
metabase.lib.equality
|
||||
metabase.lib.field
|
||||
metabase.lib.filter
|
||||
metabase.lib.ident
|
||||
metabase.lib.join.util
|
||||
metabase.lib.metadata
|
||||
metabase.lib.metadata.calculation
|
||||
metabase.lib.metadata.jvm
|
||||
metabase.lib.metadata.protocols
|
||||
metabase.lib.normalize
|
||||
metabase.lib.options
|
||||
metabase.lib.query
|
||||
metabase.lib.schema
|
||||
metabase.lib.schema.actions
|
||||
metabase.lib.schema.binning
|
||||
metabase.lib.schema.common
|
||||
metabase.lib.schema.expression
|
||||
metabase.lib.schema.expression.temporal
|
||||
metabase.lib.schema.expression.window
|
||||
metabase.lib.schema.id
|
||||
metabase.lib.schema.info
|
||||
metabase.lib.schema.literal
|
||||
metabase.lib.schema.metadata
|
||||
metabase.lib.schema.parameter
|
||||
metabase.lib.schema.template-tag
|
||||
metabase.lib.schema.temporal-bucketing
|
||||
metabase.lib.schema.util
|
||||
metabase.lib.temporal-bucket
|
||||
metabase.lib.types.isa
|
||||
metabase.lib.util
|
||||
metabase.lib.util.match
|
||||
metabase.lib.walk}
|
||||
:uses #{config driver legacy-mbql models types util}}
|
||||
|
||||
logger
|
||||
{:api #{metabase.logger metabase.logger.init}
|
||||
:uses #{config plugins}}
|
||||
|
||||
login-history
|
||||
{:api #{metabase.login-history.api
|
||||
metabase.login-history.core
|
||||
metabase.login-history.init}
|
||||
:uses #{analytics api channel models request util}}
|
||||
|
||||
model-persistence
|
||||
{:api #{metabase.model-persistence.api
|
||||
metabase.model-persistence.core
|
||||
metabase.model-persistence.init}
|
||||
:uses #{api db driver events lib models premium-features public-settings query-processor request task util}}
|
||||
|
||||
models
|
||||
{:api #{metabase.models.api-key
|
||||
metabase.models.application-permissions-revision
|
||||
metabase.models.audit-log
|
||||
metabase.models.cache-config
|
||||
metabase.models.card
|
||||
metabase.models.card.metadata
|
||||
metabase.models.collection
|
||||
metabase.models.collection-permission-graph-revision
|
||||
metabase.models.collection.graph
|
||||
metabase.models.collection.root
|
||||
metabase.models.dashboard
|
||||
metabase.models.dashboard-card
|
||||
metabase.models.dashboard-tab
|
||||
metabase.models.dashboard.constants
|
||||
metabase.models.database
|
||||
metabase.models.dispatch
|
||||
metabase.models.field
|
||||
metabase.models.field-usage
|
||||
metabase.models.field-values
|
||||
metabase.models.humanization
|
||||
metabase.models.init
|
||||
metabase.models.interface
|
||||
metabase.models.moderation-review
|
||||
metabase.models.native-query-snippet
|
||||
metabase.models.native-query-snippet.permissions
|
||||
metabase.models.notification
|
||||
metabase.models.params
|
||||
metabase.models.params.chain-filter
|
||||
metabase.models.params.custom-values
|
||||
metabase.models.params.field-values
|
||||
metabase.models.params.shared
|
||||
metabase.models.query
|
||||
metabase.models.query-analysis
|
||||
metabase.models.query.permissions
|
||||
metabase.models.resolution
|
||||
metabase.models.secret
|
||||
metabase.models.serialization
|
||||
metabase.models.setting
|
||||
metabase.models.setting.cache
|
||||
metabase.models.setting.multi-setting
|
||||
metabase.models.table
|
||||
metabase.models.task-history
|
||||
metabase.models.user
|
||||
metabase.models.user-parameter-value
|
||||
metabase.models.view-log-impl
|
||||
metabase.models.visualization-settings}
|
||||
:uses #{analytics
|
||||
analyze
|
||||
api
|
||||
audit
|
||||
channel
|
||||
config
|
||||
db
|
||||
driver
|
||||
events
|
||||
legacy-mbql
|
||||
lib
|
||||
moderation
|
||||
permissions
|
||||
plugins
|
||||
premium-features
|
||||
public-settings
|
||||
public-sharing
|
||||
pulse
|
||||
query-analysis
|
||||
query-processor
|
||||
request
|
||||
search
|
||||
server
|
||||
setup
|
||||
sync
|
||||
task
|
||||
types
|
||||
util
|
||||
enterprise/advanced-permissions}}
|
||||
|
||||
moderation
|
||||
{:api #{metabase.moderation}
|
||||
:uses #{models util}}
|
||||
|
||||
notification
|
||||
{:api #{metabase.notification.core
|
||||
metabase.notification.init
|
||||
metabase.notification.payload.core
|
||||
metabase.notification.payload.execute}
|
||||
:uses #{analytics api channel events models permissions premium-features public-settings query-processor request util}}
|
||||
|
||||
permissions
|
||||
{:api #{metabase.permissions.api
|
||||
metabase.permissions.core
|
||||
metabase.permissions.models.data-permissions
|
||||
metabase.permissions.models.permissions
|
||||
metabase.permissions.models.permissions-group
|
||||
metabase.permissions.util}
|
||||
:uses #{api audit config db models plugins premium-features request server util}}
|
||||
|
||||
plugins
|
||||
{:api #{metabase.plugins metabase.plugins.classloader}
|
||||
:uses #{config driver util}}
|
||||
|
||||
premium-features
|
||||
{:api #{metabase.premium-features.core
|
||||
metabase.premium-features.token-check}
|
||||
:uses #{config db models plugins util}}
|
||||
|
||||
public-settings
|
||||
{:api #{metabase.public-settings}
|
||||
:uses #{api config models premium-features util}}
|
||||
|
||||
public-sharing
|
||||
{:api #{metabase.public-sharing.api
|
||||
metabase.public-sharing.core
|
||||
metabase.public-sharing.init}
|
||||
:uses #{actions analytics api db events lib models query-processor request util}}
|
||||
|
||||
pulse
|
||||
{:api #{metabase.pulse.api
|
||||
metabase.pulse.core
|
||||
metabase.pulse.init
|
||||
metabase.pulse.task.send-pulses}
|
||||
:uses #{api channel config db driver events integrations models notification permissions plugins premium-features
|
||||
query-processor request task util
|
||||
enterprise/advanced-config enterprise/advanced-permissions enterprise/sandbox}}
|
||||
|
||||
query-analysis
|
||||
{:api #{metabase.query-analysis.core metabase.query-analysis.init}
|
||||
:uses #{config driver legacy-mbql lib public-settings query-processor task util}}
|
||||
|
||||
query-processor
|
||||
{:api #{metabase.query-processor
|
||||
metabase.query-processor.card
|
||||
metabase.query-processor.compile
|
||||
metabase.query-processor.dashboard
|
||||
metabase.query-processor.debug
|
||||
metabase.query-processor.error-type
|
||||
metabase.query-processor.interface
|
||||
metabase.query-processor.metadata
|
||||
metabase.query-processor.middleware.annotate
|
||||
metabase.query-processor.middleware.cache-backend.db
|
||||
metabase.query-processor.middleware.constraints
|
||||
metabase.query-processor.middleware.fetch-source-query
|
||||
metabase.query-processor.middleware.fetch-source-query-legacy
|
||||
metabase.query-processor.middleware.limit
|
||||
metabase.query-processor.middleware.permissions
|
||||
metabase.query-processor.middleware.wrap-value-literals
|
||||
metabase.query-processor.pipeline
|
||||
metabase.query-processor.pivot
|
||||
metabase.query-processor.preprocess
|
||||
metabase.query-processor.reducible
|
||||
metabase.query-processor.schema
|
||||
metabase.query-processor.setup
|
||||
metabase.query-processor.store
|
||||
metabase.query-processor.streaming
|
||||
metabase.query-processor.streaming.common
|
||||
metabase.query-processor.streaming.interface
|
||||
metabase.query-processor.timezone
|
||||
metabase.query-processor.util
|
||||
metabase.query-processor.util.add-alias-info
|
||||
metabase.query-processor.util.nest-query
|
||||
metabase.query-processor.util.persisted-cache
|
||||
metabase.query-processor.util.relative-datetime
|
||||
metabase.query-processor.util.transformations.nest-breakouts
|
||||
metabase.query-processor.writeback}
|
||||
:uses #{analytics
|
||||
analyze
|
||||
api
|
||||
audit
|
||||
config
|
||||
db
|
||||
driver
|
||||
events
|
||||
formatter
|
||||
legacy-mbql
|
||||
lib
|
||||
model-persistence
|
||||
models
|
||||
permissions
|
||||
premium-features
|
||||
public-settings
|
||||
request
|
||||
server
|
||||
types
|
||||
util}}
|
||||
|
||||
request
|
||||
{:api #{metabase.request.core}
|
||||
:uses #{api config models permissions public-settings util}}
|
||||
|
||||
revisions
|
||||
{:api #{metabase.revisions.api metabase.revisions.core metabase.revisions.init}
|
||||
:uses #{api config events models util}}
|
||||
|
||||
sample-data
|
||||
{:api #{metabase.sample-data}
|
||||
:uses #{plugins sync util}}
|
||||
|
||||
search
|
||||
{:api #{metabase.search.api
|
||||
metabase.search.appdb.scoring
|
||||
metabase.search.config
|
||||
metabase.search.core
|
||||
metabase.search.in-place.scoring
|
||||
metabase.search.ingestion
|
||||
metabase.search.init
|
||||
metabase.search.spec}
|
||||
:uses #{analytics api audit config db driver models permissions premium-features public-settings request task util}}
|
||||
|
||||
segments
|
||||
{:api #{metabase.segments.api}
|
||||
:uses #{api events legacy-mbql lib models permissions search util xrays}}
|
||||
|
||||
server
|
||||
{:api #{metabase.server.core
|
||||
metabase.server.middleware.json
|
||||
metabase.server.middleware.session
|
||||
metabase.server.streaming-response}
|
||||
:uses #{analytics api config core db driver models premium-features public-settings request util enterprise/sso}}
|
||||
|
||||
session
|
||||
{:api #{metabase.session.api metabase.session.init metabase.session.models.session}
|
||||
:uses #{api channel config db driver events login-history models public-settings request sso task util}}
|
||||
|
||||
setup
|
||||
{:api #{metabase.setup.api metabase.setup.core}
|
||||
:uses #{analytics
|
||||
api
|
||||
channel
|
||||
config
|
||||
db
|
||||
embed
|
||||
events
|
||||
integrations
|
||||
models
|
||||
permissions
|
||||
premium-features
|
||||
public-settings
|
||||
request
|
||||
session
|
||||
util}}
|
||||
|
||||
sso
|
||||
{:api #{metabase.sso.api
|
||||
metabase.sso.core
|
||||
metabase.sso.init}
|
||||
:uses #{api models permissions premium-features util}}
|
||||
|
||||
sync
|
||||
{:api #{metabase.sync.api
|
||||
metabase.sync.concurrent
|
||||
metabase.sync.core
|
||||
metabase.sync.init
|
||||
metabase.sync.schedules
|
||||
metabase.sync.task.sync-databases
|
||||
metabase.sync.util}
|
||||
:uses #{analyze api audit config db driver events lib models plugins query-processor task util}}
|
||||
|
||||
task
|
||||
{:api #{metabase.task
|
||||
metabase.task.bootstrap
|
||||
metabase.task.init
|
||||
metabase.task.notification}
|
||||
:uses #{analytics
|
||||
channel
|
||||
config
|
||||
db
|
||||
driver
|
||||
integrations
|
||||
models
|
||||
notification
|
||||
plugins
|
||||
premium-features
|
||||
public-settings
|
||||
query-processor
|
||||
util
|
||||
enterprise/task}}
|
||||
|
||||
tiles
|
||||
{:api #{metabase.tiles.api
|
||||
metabase.tiles.init}
|
||||
:uses #{api legacy-mbql models query-processor util}}
|
||||
|
||||
timeline
|
||||
{:api #{metabase.timeline.api metabase.timeline.core}
|
||||
:uses #{analytics api models util}}
|
||||
|
||||
types
|
||||
{:api #{metabase.types}
|
||||
:uses #{util}}
|
||||
|
||||
upload
|
||||
{:api #{metabase.upload}
|
||||
:uses #{analytics api driver events legacy-mbql lib model-persistence models permissions public-settings sync util}}
|
||||
|
||||
user-key-value
|
||||
{:api #{metabase.user-key-value.api metabase.user-key-value.init}
|
||||
:uses #{api config lib util}}
|
||||
|
||||
util
|
||||
{:api :any
|
||||
:uses #{config driver legacy-mbql lib models plugins premium-features public-settings}}
|
||||
|
||||
xrays
|
||||
{:api #{metabase.xrays.api metabase.xrays.core}
|
||||
:uses #{analyze api db driver legacy-mbql lib models public-settings query-processor util}}
|
||||
|
||||
enterprise/advanced-config
|
||||
{:api #{metabase-enterprise.advanced-config.api.logs
|
||||
metabase-enterprise.advanced-config.models.pulse-channel
|
||||
metabase-enterprise.advanced-config.file}
|
||||
:uses #{api db driver models premium-features setup sync util}}
|
||||
|
||||
enterprise/advanced-permissions
|
||||
{:api #{metabase-enterprise.advanced-permissions.api.routes
|
||||
metabase-enterprise.advanced-permissions.api.util
|
||||
metabase-enterprise.advanced-permissions.common
|
||||
metabase-enterprise.advanced-permissions.models.permissions.group-manager}
|
||||
:uses #{api audit driver lib models permissions premium-features query-processor util enterprise/sandbox}}
|
||||
|
||||
enterprise/airgap
|
||||
{:api #{}
|
||||
:uses #{premium-features util}}
|
||||
|
||||
enterprise/api
|
||||
{:api #{metabase-enterprise.api.routes
|
||||
metabase-enterprise.api.routes.common}
|
||||
:uses :any}
|
||||
|
||||
enterprise/audit-app
|
||||
{:api #{metabase-enterprise.audit-app.api.routes}
|
||||
:uses #{api
|
||||
audit
|
||||
db
|
||||
driver
|
||||
lib
|
||||
models
|
||||
permissions
|
||||
plugins
|
||||
premium-features
|
||||
query-processor
|
||||
sync
|
||||
util
|
||||
enterprise/serialization}}
|
||||
|
||||
enterprise/auth-provider
|
||||
{:api #{}
|
||||
:uses #{premium-features util}}
|
||||
|
||||
enterprise/billing
|
||||
{:api #{metabase-enterprise.billing.api.routes}
|
||||
:uses #{api premium-features util}}
|
||||
|
||||
enterprise/cache
|
||||
{:api #{metabase-enterprise.cache.strategies}
|
||||
:uses #{api models premium-features query-processor util}}
|
||||
|
||||
enterprise/content-verification
|
||||
{:api #{metabase-enterprise.content-verification.api.routes}
|
||||
:uses #{api models moderation util enterprise/api}}
|
||||
|
||||
enterprise/core
|
||||
{:api #{metabase-enterprise.core.init}
|
||||
:uses #{enterprise/enhancements}}
|
||||
|
||||
enterprise/dashboard-subscription-filters
|
||||
{:api #{}
|
||||
:uses #{premium-features}}
|
||||
|
||||
enterprise/enhancements
|
||||
{:api #{metabase-enterprise.enhancements.init}
|
||||
:uses #{models premium-features sso util enterprise/sso}}
|
||||
|
||||
enterprise/llm
|
||||
{:api #{metabase-enterprise.llm.api}
|
||||
:uses #{analytics analyze api models query-processor util}}
|
||||
|
||||
enterprise/query-reference-validation
|
||||
{:api #{metabase-enterprise.query-reference-validation.api}
|
||||
:uses #{api models public-settings request util}}
|
||||
|
||||
enterprise/sandbox
|
||||
{:api #{metabase-enterprise.sandbox.api.routes
|
||||
metabase-enterprise.sandbox.api.util}
|
||||
:uses #{api
|
||||
audit
|
||||
db
|
||||
legacy-mbql
|
||||
lib
|
||||
models
|
||||
permissions
|
||||
plugins
|
||||
premium-features
|
||||
query-processor
|
||||
request
|
||||
util
|
||||
enterprise/advanced-permissions
|
||||
enterprise/api}}
|
||||
|
||||
enterprise/scim
|
||||
{:api #{metabase-enterprise.scim.api metabase-enterprise.scim.routes}
|
||||
:uses #{analytics api models permissions public-settings server util enterprise/serialization}}
|
||||
|
||||
enterprise/search
|
||||
{:api #{}
|
||||
:uses #{premium-features search}}
|
||||
|
||||
enterprise/serialization
|
||||
{:api #{metabase-enterprise.serialization.api
|
||||
metabase-enterprise.serialization.cmd
|
||||
metabase-enterprise.serialization.v2.backfill-ids}
|
||||
:uses #{analytics api config db legacy-mbql lib logger models plugins premium-features public-settings setup util}}
|
||||
|
||||
enterprise/snippet-collections
|
||||
{:api #{}
|
||||
:uses #{models permissions premium-features util}}
|
||||
|
||||
enterprise/sso
|
||||
{:api #{metabase-enterprise.sso.api.routes
|
||||
metabase-enterprise.sso.integrations.sso-settings
|
||||
metabase-enterprise.sso.integrations.sso-utils}
|
||||
:uses #{api channel embed events models premium-features public-settings request session sso util enterprise/scim}}
|
||||
|
||||
enterprise/stale
|
||||
{:api #{metabase-enterprise.stale.routes}
|
||||
:uses #{analytics api embed models premium-features public-settings request util}}
|
||||
|
||||
enterprise/stats
|
||||
{:api #{}
|
||||
:uses #{driver premium-features enterprise/advanced-config enterprise/scim enterprise/sso}}
|
||||
|
||||
enterprise/task
|
||||
{:api #{metabase-enterprise.task.truncate-audit-tables}
|
||||
:uses #{premium-features query-processor task util enterprise/cache}}
|
||||
|
||||
enterprise/upload-management
|
||||
{:api #{metabase-enterprise.upload-management.api}
|
||||
:uses #{api models upload util}}}
|
||||
|
||||
;; namespaces matching these patterns (with `re-find`) are excluded from the module linter. Since regex literals
|
||||
;; aren't allowed in EDN just used the `(str <regex>)` version i.e. two slashes instead of one.
|
||||
;;
|
||||
;; this is mostly intended for excluding test namespaces or those rare 'glue' namespaces that glue multiple modules
|
||||
;; together, e.g. `metabase.lib.metadata.jvm`.
|
||||
:linters
|
||||
{:metabase/modules
|
||||
{:ignored-namespace-patterns
|
||||
#{"-test$" ; anything ending in `-test`
|
||||
"test[-.]util" ; anything that contains `test.util` or `test-util`
|
||||
"test\\.impl" ; anything that contains `test.impl`
|
||||
"test-setup" ; anything that contains `test-setup`
|
||||
"^metabase(?:-enterprise)?\\.test" ; anything starting with `metabase.test` or `metabase-enterprise.test`
|
||||
"^metabase\\.http-client$"}}}} ; `metabase.http-client` which is a test-only namespace despite its name.
|
||||
132
.clj-kondo/config/test-helpers/config.edn
Normal file
@@ -0,0 +1,132 @@
|
||||
{:linters
|
||||
{:metabase/test-helpers-use-non-thread-safe-functions
|
||||
;; TODO -- seems silly to maintain different blacklists and whitelists here than we use for the deftest `^:parallel`
|
||||
;; checker...
|
||||
{:explicitly-safe
|
||||
#{ ;; these toucan methods might actually set global values if it's used outside of a transaction,
|
||||
;; but since mt/with-temp runs in a transaction, so we'll ignore them in this case.
|
||||
toucan2.core/delete!
|
||||
toucan2.core/update!
|
||||
toucan2.core/insert!
|
||||
toucan2.core/insert-returning-instance!
|
||||
toucan2.core/insert-returning-instances!
|
||||
toucan2.core/insert-returning-pk!
|
||||
toucan2.core/insert-returning-pks!
|
||||
clojure.core.async/<!!
|
||||
clojure.core.async/>!!
|
||||
clojure.core.async/alts!!
|
||||
clojure.core.async/close!
|
||||
clojure.core.async/poll!
|
||||
clojure.core.memoize/memo-clear!
|
||||
clojure.core/conj!
|
||||
clojure.core/persistent!
|
||||
clojure.core/reset!
|
||||
clojure.core/swap!
|
||||
clojure.core/volatile!
|
||||
clojure.core/vreset!
|
||||
clojure.core/vswap!
|
||||
clojure.java.jdbc/execute!
|
||||
methodical.core/add-aux-method-with-unique-key!
|
||||
methodical.core/remove-aux-method-with-unique-key!
|
||||
next.jdbc/execute!
|
||||
|
||||
;; Definitely thread safe
|
||||
metabase.test.util.dynamic-redefs/patch-vars!
|
||||
|
||||
;; TODO: most of these symbols shouldn't be here, we should go through them and
|
||||
;; find the functions/macros that use them and make sure their names end with !
|
||||
;; best way to do this is try remove each of these and rely on kondo output to find places where it's used
|
||||
clojure.test/grant-collection-perms!
|
||||
clojure.test/grant-collection-perms-fn!
|
||||
clojure.test/grant-perms-fn!
|
||||
clojure.test/purge-old-entries!
|
||||
clojure.test/revoke-collection-perms!
|
||||
clojure.test/save-results!
|
||||
metabase-enterprise.advanced-permissions.models.permissions/update-db-download-permissions!
|
||||
metabase-enterprise.internal-user/install-internal-user!
|
||||
metabase-enterprise.sso.integrations.saml-test/call-with-login-attributes-cleared!
|
||||
metabase.actions.actions/perform-action!
|
||||
metabase.actions.models/insert!
|
||||
metabase.analytics.snowplow-test/fake-track-event-impl!
|
||||
metabase.analytics.snowplow/track-event-impl!
|
||||
metabase.channel.email-test/reset-inbox!
|
||||
metabase.channel.email/send-email!
|
||||
metabase.cmd.dump-to-h2/dump-to-h2!
|
||||
metabase.cmd.load-from-h2/load-from-h2!
|
||||
metabase.core.core/ensure-audit-db-installed!
|
||||
metabase.db.schema-migrations-test.impl/run-migrations-in-range!
|
||||
metabase.db.setup/migrate!
|
||||
metabase.db.setup/setup-db!
|
||||
metabase.db/migrate!
|
||||
metabase.db/setup-db!
|
||||
metabase.driver.mongo-test/create-database-from-row-maps!
|
||||
metabase.driver.postgres-test/create-enums-db!
|
||||
metabase.driver.postgres-test/drop-if-exists-and-create-db!
|
||||
metabase.driver.sql-jdbc.execute/execute-statement!
|
||||
metabase.indexed-entities.models.model-index/add-values!
|
||||
metabase.indexed-entities.task.index-values/job-init!
|
||||
metabase.model-persistence.models.persisted-info/ready-database!
|
||||
metabase.model-persistence.task.persist-refresh/job-init!
|
||||
metabase.model-persistence.task.persist-refresh/refresh-tables!
|
||||
metabase.model-persistence.task.persist-refresh/schedule-persistence-for-database!
|
||||
metabase.models.collection.graph-test/clear-graph-revisions!
|
||||
metabase.models.collection.graph-test/do-with-n-temp-users-with-personal-collections!
|
||||
metabase.models.field-values/create-or-update-full-field-values!
|
||||
metabase.models.moderation-review/create-review!
|
||||
metabase.models.on-demand-test/add-dashcard-with-parameter-mapping!
|
||||
metabase.models.setting-test/test-user-local-allowed-setting!
|
||||
metabase.models.setting-test/test-user-local-only-setting!
|
||||
metabase.models.setting.cache/restore-cache!
|
||||
metabase.models.setting/set!
|
||||
metabase.models.setting/validate-settings-formatting!
|
||||
metabase.permissions.models.permissions/grant-application-permissions!
|
||||
metabase.permissions.models.permissions/grant-collection-read-permissions!
|
||||
metabase.permissions.models.permissions/grant-collection-readwrite-permissions!
|
||||
metabase.permissions.models.permissions/grant-full-data-permissions!
|
||||
metabase.permissions.models.permissions/grant-native-readwrite-permissions!
|
||||
metabase.permissions.models.permissions/grant-permissions!
|
||||
metabase.permissions.models.permissions/revoke-application-permissions!
|
||||
metabase.permissions.models.permissions/revoke-data-perms!
|
||||
metabase.permissions.models.permissions/update-data-perms-graph!
|
||||
metabase.permissions.models.permissions/update-group-permissions!
|
||||
metabase.permissions.test-util/with-restored-perms!
|
||||
metabase.public-sharing.api-test/add-card-to-dashboard!
|
||||
metabase.pulse.send/send-notifications!
|
||||
metabase.pulse.send/send-pulse!
|
||||
metabase.query-processor.streaming.interface/begin!
|
||||
metabase.query-processor.streaming.interface/finish!
|
||||
metabase.query-processor.streaming.interface/write-row!
|
||||
metabase.sample-data/try-to-extract-sample-database!
|
||||
metabase.setup.core/create-token!
|
||||
metabase.sso.ldap-test-util/start-ldap-server!
|
||||
metabase.sync.core/sync-database!
|
||||
metabase.sync.sync-metadata.fields.sync-metadata/update-field-metadata-if-needed!
|
||||
metabase.sync.sync-metadata/sync-db-metadata!
|
||||
metabase.sync.util-test/sync-database!
|
||||
metabase.sync.util/store-sync-summary!
|
||||
metabase.task/delete-task!
|
||||
metabase.test.data.bigquery-cloud-sdk/execute!
|
||||
metabase.test.data.impl.get-or-create/set-test-db-permissions!
|
||||
metabase.test.data.impl/copy-db-tables-and-fields!
|
||||
metabase.test.data.impl/get-or-create-database!
|
||||
metabase.test.data.impl/get-or-create-default-dataset!
|
||||
metabase.test.data.interface/create-db!
|
||||
metabase.test.data.interface/destroy-db!
|
||||
metabase.test.data.oracle/create-user!
|
||||
metabase.test.data.oracle/drop-user!
|
||||
metabase.test.data.sql-jdbc.load-data/make-insert!
|
||||
metabase.test.data.users/clear-cached-session-tokens!
|
||||
metabase.test.initialize/do-initialization!
|
||||
metabase.test.initialize/initialize-if-needed!
|
||||
metabase.test.util.log/ensure-unique-logger!
|
||||
metabase.test.util.log/set-ns-log-level!
|
||||
metabase.test.util/do-with-temp-env-var-value!
|
||||
metabase.test.util/restore-raw-setting!
|
||||
metabase.test.util/upsert-raw-setting!
|
||||
metabase.test/initialize-if-needed!
|
||||
metabase.test/test-helpers-set-global-values!
|
||||
metabase.test/with-temp-env-var-value!
|
||||
metabase.upload-test/set-local-infile!
|
||||
metabase.util.files/create-dir-if-not-exists!
|
||||
metabase.util.ssh-test/start-mock-servers!
|
||||
metabase.util.ssh-test/stop-mock-servers!}}}}
|
||||
@@ -1,7 +0,0 @@
|
||||
(ns macros.metabase.api.common)
|
||||
|
||||
(defmacro define-routes
|
||||
"Macro for api.common/define-routes"
|
||||
[& args]
|
||||
`(do (def ~'routes "docstring" nil)
|
||||
~@args))
|
||||
@@ -1,4 +1,4 @@
|
||||
(ns macros.metabase.api.public-test)
|
||||
(ns macros.metabase.public-sharing.api-test)
|
||||
|
||||
(defmacro with-sharing-enabled-and-temp-card-referencing!
|
||||
[table-kw field-kw [card-binding] & body]
|
||||
@@ -1,4 +1,4 @@
|
||||
(ns macros.metabase.task.setup.query-analysis-setup
|
||||
(ns macros.metabase.query-analysis.task.test-setup
|
||||
(:require [macros.common]))
|
||||
|
||||
(defmacro with-test-setup!
|
||||
@@ -1,5 +0,0 @@
|
||||
(ns macros.metabase.test.persistence)
|
||||
|
||||
(defmacro with-persistence-enabled! [[persist-fn-sym] & body]
|
||||
`(clojure.core/let [~persist-fn-sym (fn [])]
|
||||
~@body))
|
||||
@@ -1,4 +1,4 @@
|
||||
(ns macros.metabase.related-test
|
||||
(ns macros.metabase.xrays.related-test
|
||||
(:require [macros.common]))
|
||||
|
||||
(defmacro with-world [& body]
|
||||
@@ -1,329 +0,0 @@
|
||||
(ns hooks.clojure.core
|
||||
(:require
|
||||
[clj-kondo.hooks-api :as hooks]
|
||||
[clojure.string :as str]
|
||||
[hooks.common]))
|
||||
|
||||
;;; TODO -- seems silly to maintain different blacklists and whitelists here than we use for the deftest `^:parallel`
|
||||
;;; checker... those lists live in the Clj Kondo config file
|
||||
(def ^:private symbols-allowed-in-fns-not-ending-in-an-exclamation-point
|
||||
'#{;; these toucan methods might actually set global values if it's used outside of a transaction,
|
||||
;; but since mt/with-temp runs in a transaction, so we'll ignore them in this case.
|
||||
toucan2.core/delete!
|
||||
toucan2.core/update!
|
||||
toucan2.core/insert!
|
||||
toucan2.core/insert-returning-instance!
|
||||
toucan2.core/insert-returning-instances!
|
||||
toucan2.core/insert-returning-pk!
|
||||
toucan2.core/insert-returning-pks!
|
||||
clojure.core.async/<!!
|
||||
clojure.core.async/>!!
|
||||
clojure.core.async/alts!!
|
||||
clojure.core.async/close!
|
||||
clojure.core.async/poll!
|
||||
clojure.core.memoize/memo-clear!
|
||||
clojure.core/conj!
|
||||
clojure.core/persistent!
|
||||
clojure.core/reset!
|
||||
clojure.core/swap!
|
||||
clojure.core/volatile!
|
||||
clojure.core/vreset!
|
||||
clojure.core/vswap!
|
||||
clojure.java.jdbc/execute!
|
||||
methodical.core/add-aux-method-with-unique-key!
|
||||
methodical.core/remove-aux-method-with-unique-key!
|
||||
next.jdbc/execute!
|
||||
|
||||
;; Definitely thread safe
|
||||
metabase.test.util.dynamic-redefs/patch-vars!
|
||||
|
||||
;; TODO: most of these symbols shouldn't be here, we should go through them and
|
||||
;; find the functions/macros that use them and make sure their names end with !
|
||||
;; best way to do this is try remove each of these and rely on kondo output to find places where it's used
|
||||
clojure.test/grant-collection-perms!
|
||||
clojure.test/grant-collection-perms-fn!
|
||||
clojure.test/grant-perms-fn!
|
||||
clojure.test/purge-old-entries!
|
||||
clojure.test/revoke-collection-perms!
|
||||
clojure.test/save-results!
|
||||
metabase-enterprise.advanced-permissions.models.permissions/update-db-download-permissions!
|
||||
metabase-enterprise.internal-user/install-internal-user!
|
||||
metabase-enterprise.sso.integrations.saml-test/call-with-login-attributes-cleared!
|
||||
metabase.actions/perform-action!
|
||||
metabase.analytics.snowplow-test/fake-track-event-impl!
|
||||
metabase.analytics.snowplow/track-event-impl!
|
||||
metabase.api.public-test/add-card-to-dashboard!
|
||||
metabase.cmd.dump-to-h2/dump-to-h2!
|
||||
metabase.cmd.load-from-h2/load-from-h2!
|
||||
metabase.core/ensure-audit-db-installed!
|
||||
metabase.db.schema-migrations-test.impl/run-migrations-in-range!
|
||||
metabase.db.setup/migrate!
|
||||
metabase.db.setup/setup-db!
|
||||
metabase.db/migrate!
|
||||
metabase.db/setup-db!
|
||||
metabase.driver.mongo-test/create-database-from-row-maps!
|
||||
metabase.driver.postgres-test/create-enums-db!
|
||||
metabase.driver.postgres-test/drop-if-exists-and-create-db!
|
||||
metabase.driver.sql-jdbc.execute/execute-statement!
|
||||
metabase.email-test/reset-inbox!
|
||||
metabase.email/send-email!
|
||||
metabase.models.action/insert!
|
||||
metabase.models.collection.graph-test/clear-graph-revisions!
|
||||
metabase.models.collection.graph-test/do-with-n-temp-users-with-personal-collections!
|
||||
metabase.models.field-values/create-or-update-full-field-values!
|
||||
metabase.models.model-index/add-values!
|
||||
metabase.models.moderation-review/create-review!
|
||||
metabase.models.on-demand-test/add-dashcard-with-parameter-mapping!
|
||||
metabase.models.permissions/grant-application-permissions!
|
||||
metabase.models.permissions/grant-collection-read-permissions!
|
||||
metabase.models.permissions/grant-collection-readwrite-permissions!
|
||||
metabase.models.permissions/grant-full-data-permissions!
|
||||
metabase.models.permissions/grant-native-readwrite-permissions!
|
||||
metabase.models.permissions/grant-permissions!
|
||||
metabase.models.permissions/revoke-application-permissions!
|
||||
metabase.models.permissions/revoke-data-perms!
|
||||
metabase.models.permissions/update-data-perms-graph!
|
||||
metabase.models.permissions/update-group-permissions!
|
||||
metabase.models.persisted-info/ready-database!
|
||||
metabase.models.setting-test/test-user-local-allowed-setting!
|
||||
metabase.models.setting-test/test-user-local-only-setting!
|
||||
metabase.models.setting.cache/restore-cache!
|
||||
metabase.models.setting/set!
|
||||
metabase.models.setting/validate-settings-formatting!
|
||||
metabase.permissions.test-util/with-restored-perms!
|
||||
metabase.pulse.send/send-notifications!
|
||||
metabase.pulse.send/send-pulse!
|
||||
metabase.query-processor.streaming.interface/begin!
|
||||
metabase.query-processor.streaming.interface/finish!
|
||||
metabase.query-processor.streaming.interface/write-row!
|
||||
metabase.sample-data/try-to-extract-sample-database!
|
||||
metabase.setup/create-token!
|
||||
metabase.sync.sync-metadata.fields.sync-metadata/update-field-metadata-if-needed!
|
||||
metabase.sync.sync-metadata/sync-db-metadata!
|
||||
metabase.sync.util-test/sync-database!
|
||||
metabase.sync.util/store-sync-summary!
|
||||
metabase.sync/sync-database!
|
||||
metabase.task.index-values/job-init!
|
||||
metabase.task.persist-refresh/job-init!
|
||||
metabase.task.persist-refresh/refresh-tables!
|
||||
metabase.task.persist-refresh/schedule-persistence-for-database!
|
||||
metabase.task/delete-task!
|
||||
metabase.test.data.bigquery-cloud-sdk/execute!
|
||||
metabase.test.data.impl/copy-db-tables-and-fields!
|
||||
metabase.test.data.impl/get-or-create-database!
|
||||
metabase.test.data.impl/get-or-create-default-dataset!
|
||||
metabase.test.data.impl.get-or-create/set-test-db-permissions!
|
||||
metabase.test.data.interface/create-db!
|
||||
metabase.test.data.interface/destroy-db!
|
||||
metabase.test.data.oracle/create-user!
|
||||
metabase.test.data.oracle/drop-user!
|
||||
metabase.test.data.sql-jdbc.load-data/make-insert!
|
||||
metabase.test.data.users/clear-cached-session-tokens!
|
||||
metabase.test.initialize/do-initialization!
|
||||
metabase.test.initialize/initialize-if-needed!
|
||||
metabase.test.integrations.ldap/start-ldap-server!
|
||||
metabase.test.util.log/ensure-unique-logger!
|
||||
metabase.test.util.log/set-ns-log-level!
|
||||
metabase.test.util/do-with-temp-env-var-value!
|
||||
metabase.test.util/restore-raw-setting!
|
||||
metabase.test.util/upsert-raw-setting!
|
||||
metabase.test/initialize-if-needed!
|
||||
metabase.test/test-helpers-set-global-values!
|
||||
metabase.test/with-temp-env-var-value!
|
||||
metabase.upload-test/set-local-infile!
|
||||
metabase.util.files/create-dir-if-not-exists!
|
||||
metabase.util.ssh-test/start-mock-servers!
|
||||
metabase.util.ssh-test/stop-mock-servers!})
|
||||
|
||||
(defn- end-with-exclamation?
|
||||
[s]
|
||||
(str/ends-with? s "!"))
|
||||
|
||||
(defn- explicitly-safe? [qualified-symbol]
|
||||
(contains? symbols-allowed-in-fns-not-ending-in-an-exclamation-point qualified-symbol))
|
||||
|
||||
(defn- explicitly-unsafe? [config qualified-symbol]
|
||||
(contains? (get-in config [:linters :metabase/validate-deftest :parallel/unsafe]) qualified-symbol))
|
||||
|
||||
(defn- unsafe? [config qualified-symbol]
|
||||
(and (or (end-with-exclamation? qualified-symbol)
|
||||
(explicitly-unsafe? config qualified-symbol))
|
||||
(not (explicitly-safe? qualified-symbol))))
|
||||
|
||||
(defn- non-thread-safe-form-should-end-with-exclamation*
|
||||
[{[defn-or-defmacro form-name] :children, :as node} config]
|
||||
(when-not (and (:string-value form-name)
|
||||
(end-with-exclamation? (:string-value form-name)))
|
||||
(letfn [(walk [f form]
|
||||
(f form)
|
||||
(doseq [child (:children form)]
|
||||
(walk f child)))
|
||||
(check-node [form]
|
||||
(when-let [qualified-symbol (hooks.common/node->qualified-symbol form)]
|
||||
(when (unsafe? config qualified-symbol)
|
||||
(hooks/reg-finding!
|
||||
(assoc (meta form-name)
|
||||
:message (format "The name of this %s should end with `!` because it contains calls to non thread safe form `%s`. [:metabase/test-helpers-use-non-thread-safe-functions]"
|
||||
(:string-value defn-or-defmacro) qualified-symbol)
|
||||
:type :metabase/test-helpers-use-non-thread-safe-functions)))))]
|
||||
(walk check-node node))
|
||||
node))
|
||||
|
||||
(defn non-thread-safe-form-should-end-with-exclamation
|
||||
"Used to ensure defn and defmacro in test namespace to have name ending with `!` if it's non-thread-safe.
|
||||
A function or a macro can be defined as 'not thread safe' when their funciton name ends with a `!`.
|
||||
|
||||
Only used in tests to identify thread-safe/non-thread-safe test helpers. See #37126"
|
||||
[{:keys [node cljc lang config]}]
|
||||
(when (or (not cljc)
|
||||
(= lang :clj))
|
||||
(non-thread-safe-form-should-end-with-exclamation* node config))
|
||||
{:node node})
|
||||
|
||||
(comment
|
||||
(require '[clj-kondo.core :as clj-kondo])
|
||||
(def form (str '(defmacro a
|
||||
[x]
|
||||
`(fun-call x))))
|
||||
|
||||
(def form "(defmacro a
|
||||
[x]
|
||||
`(some! ~x))")
|
||||
|
||||
(def form "(defun f
|
||||
[x]
|
||||
(let [g! (fn [] 1)]
|
||||
(g!)))")
|
||||
|
||||
(str (hooks/parse-string form))
|
||||
(hooks/sexpr (hooks/parse-string form))
|
||||
|
||||
(binding [hooks/*reload* true]
|
||||
(-> form
|
||||
(with-in-str (clj-kondo/run! {:lint ["-"]}))
|
||||
:findings))
|
||||
|
||||
(do (non-thread-safe-form-should-end-with-exclamation* (hooks/parse-string form)) nil))
|
||||
|
||||
(defn- ns-form-node->require-node [ns-form-node]
|
||||
(some (fn [node]
|
||||
(when (and (hooks/list-node? node)
|
||||
(let [first-child (first (:children node))]
|
||||
(and (hooks/keyword-node? first-child)
|
||||
(= (hooks/sexpr first-child) :require))))
|
||||
node))
|
||||
(:children ns-form-node)))
|
||||
|
||||
(defn- lint-require-shapes [ns-form-node]
|
||||
(doseq [node (-> ns-form-node
|
||||
ns-form-node->require-node
|
||||
:children
|
||||
rest)]
|
||||
(cond
|
||||
(not (hooks/vector-node? node))
|
||||
(hooks/reg-finding! (assoc (meta node)
|
||||
:message "All :required namespaces should be wrapped in vectors [:metabase/require-shape-checker]"
|
||||
:type :metabase/require-shape-checker))
|
||||
|
||||
(hooks/vector-node? (second (:children node)))
|
||||
(hooks/reg-finding! (assoc (meta node)
|
||||
:message "Don't use prefix forms inside :require [:metabase/require-shape-checker]"
|
||||
:type :metabase/require-shape-checker)))))
|
||||
|
||||
(defn- require-node->namespace-symb-nodes [require-node]
|
||||
(let [[_ns & args] (:children require-node)]
|
||||
(into []
|
||||
;; prefixed namespace forms are NOT SUPPORTED!!!!!!!!1
|
||||
(keep (fn [node]
|
||||
(cond
|
||||
(hooks/vector-node? node)
|
||||
;; propagate the metadata attached to this vector in case there's a `:clj-kondo/ignore` form.
|
||||
(let [symbol-node (first (:children node))]
|
||||
(hooks.common/merge-ignored-linters symbol-node require-node node))
|
||||
|
||||
;; this should also be dead code since we require requires to be vectors
|
||||
(hooks/token-node? node)
|
||||
(hooks.common/merge-ignored-linters node require-node)
|
||||
|
||||
:else
|
||||
(printf "Don't know how to figure out what namespace is being required in %s\n" (pr-str node)))))
|
||||
args)))
|
||||
|
||||
(defn- ns-form-node->ns-symb [ns-form-node]
|
||||
(some-> (some (fn [node]
|
||||
(when (and (hooks/token-node? node)
|
||||
(not= (hooks/sexpr node) 'ns))
|
||||
node))
|
||||
(:children ns-form-node))
|
||||
hooks/sexpr))
|
||||
|
||||
(defn- module
|
||||
"E.g.
|
||||
|
||||
(module 'metabase.qp.middleware.wow) => 'metabase.qp"
|
||||
[ns-symb]
|
||||
(some-> (re-find #"^metabase\.[^.]+" (str ns-symb)) symbol))
|
||||
|
||||
(defn- ignored-namespace? [ns-symb config]
|
||||
(some
|
||||
(fn [pattern-str]
|
||||
(re-find (re-pattern pattern-str) (str ns-symb)))
|
||||
(:ignored-namespace-patterns config)))
|
||||
|
||||
(defn- module-api-namespaces
|
||||
"Set API namespaces for a given module. `:any` means you can use anything, there are no API namespaces for this
|
||||
module (yet). If unspecified, the default is just the namespace with the same name as the module e.g.
|
||||
`metabase.db`."
|
||||
[module config]
|
||||
(let [module-config (get-in config [:api-namespaces module])]
|
||||
(cond
|
||||
(= module-config :any)
|
||||
nil
|
||||
|
||||
(set? module-config)
|
||||
module-config
|
||||
|
||||
:else
|
||||
#{module})))
|
||||
|
||||
(defn- lint-modules [ns-form-node config]
|
||||
(let [ns-symb (ns-form-node->ns-symb ns-form-node)]
|
||||
(when-not (ignored-namespace? ns-symb config)
|
||||
(when-let [current-module (module ns-symb)]
|
||||
(let [allowed-modules (get-in config [:allowed-modules current-module])
|
||||
required-namespace-symb-nodes (-> ns-form-node
|
||||
ns-form-node->require-node
|
||||
require-node->namespace-symb-nodes)]
|
||||
(doseq [node required-namespace-symb-nodes
|
||||
:when (not (contains? (hooks.common/ignored-linters node) :metabase/ns-module-checker))
|
||||
:let [required-namespace (hooks/sexpr node)
|
||||
required-module (module required-namespace)]
|
||||
;; ignore stuff not in a module i.e. non-Metabase stuff.
|
||||
:when required-module
|
||||
:let [in-current-module? (= required-module current-module)]
|
||||
:when (not in-current-module?)
|
||||
:let [allowed-module? (or (= allowed-modules :any)
|
||||
(contains? (set allowed-modules) required-module))
|
||||
module-api-namespaces (module-api-namespaces required-module config)
|
||||
allowed-module-namespace? (or (empty? module-api-namespaces)
|
||||
(contains? module-api-namespaces required-namespace))]]
|
||||
(when-let [error (cond
|
||||
(not allowed-module?)
|
||||
(format "Module %s should not be used in the %s module. [:metabase/ns-module-checker :allowed-modules %s]"
|
||||
required-module
|
||||
current-module
|
||||
current-module)
|
||||
|
||||
(not allowed-module-namespace?)
|
||||
(format "Namespace %s is not an allowed external API namespace for the %s module. [:metabase/ns-module-checker :api-namespaces %s]"
|
||||
required-namespace
|
||||
required-module
|
||||
required-module))]
|
||||
(hooks/reg-finding! (assoc (meta node)
|
||||
:message error
|
||||
:type :metabase/ns-module-checker)))))))))
|
||||
|
||||
(defn lint-ns [x]
|
||||
(lint-require-shapes (:node x))
|
||||
(lint-modules (:node x) (get-in x [:config :linters :metabase/ns-module-checker]))
|
||||
x)
|
||||
52
.clj-kondo/src/hooks/clojure/core/defmulti.clj
Normal file
@@ -0,0 +1,52 @@
|
||||
(ns hooks.clojure.core.defmulti
|
||||
(:require
|
||||
[clj-kondo.hooks-api :as hooks]
|
||||
[clojure.string :as str]
|
||||
[hooks.common]))
|
||||
|
||||
(defn- check-arglists [report-node arglists]
|
||||
(letfn [(reg-bad-arglists! []
|
||||
(hooks/reg-finding!
|
||||
(assoc (meta report-node)
|
||||
:message ":arglists should be a quoted list of vectors [:metabase/check-defmulti-arglists]"
|
||||
:type :metabase/check-defmulti-arglists)))
|
||||
(reg-bad-arg! []
|
||||
(hooks/reg-finding!
|
||||
(assoc (meta report-node)
|
||||
:message ":arglists should contain actual arg names, not underscore (unused) symbols [:metabase/check-defmulti-arglists]"
|
||||
:type :metabase/check-defmulti-arglists)))
|
||||
(underscore-arg? [arg]
|
||||
(and (symbol? arg)
|
||||
(str/starts-with? arg "_")))
|
||||
(check-arglist [arglist]
|
||||
(cond
|
||||
(not (vector? arglist)) (reg-bad-arglists!)
|
||||
(some underscore-arg? arglist) (reg-bad-arg!)))]
|
||||
(if-not (and (seq? arglists)
|
||||
(= (first arglists) 'quote)
|
||||
(seq (second arglists)))
|
||||
(reg-bad-arglists!)
|
||||
(let [[_quote arglists] arglists]
|
||||
(doseq [arglist arglists]
|
||||
(check-arglist arglist))))))
|
||||
|
||||
(defn- defmulti-check-for-arglists-metadata
|
||||
"Make sure a [[defmulti]] has an attribute map with `:arglists` metadata."
|
||||
[node]
|
||||
(let [[_defmulti _symb & args] (:children node)
|
||||
[_docstring & args] (if (hooks/string-node? (first args))
|
||||
args
|
||||
(cons nil args))
|
||||
attr-map (when (hooks/map-node? (first args))
|
||||
(first args))
|
||||
arglists (some-> attr-map hooks/sexpr :arglists seq)]
|
||||
(if-not (seq? arglists) ; should be a list or at least list-like
|
||||
(hooks/reg-finding!
|
||||
(assoc (meta node)
|
||||
:message "All defmultis should have an attribute map with :arglists metadata. [:metabase/check-defmulti-arglists]"
|
||||
:type :metabase/check-defmulti-arglists))
|
||||
(check-arglists attr-map arglists))))
|
||||
|
||||
(defn lint-defmulti [x]
|
||||
(defmulti-check-for-arglists-metadata (:node x))
|
||||
x)
|
||||
76
.clj-kondo/src/hooks/clojure/core/defn.clj
Normal file
@@ -0,0 +1,76 @@
|
||||
(ns hooks.clojure.core.defn
|
||||
(:require
|
||||
[clj-kondo.hooks-api :as hooks]
|
||||
[clojure.string :as str]
|
||||
[hooks.common]))
|
||||
|
||||
(defn- end-with-exclamation?
|
||||
[s]
|
||||
(str/ends-with? s "!"))
|
||||
|
||||
(defn- explicitly-safe? [config qualified-symbol]
|
||||
(contains? (get-in config [:linters :metabase/test-helpers-use-non-thread-safe-functions :explicitly-safe])
|
||||
qualified-symbol))
|
||||
|
||||
(defn- explicitly-unsafe? [config qualified-symbol]
|
||||
(contains? (get-in config [:linters :metabase/validate-deftest :parallel/unsafe]) qualified-symbol))
|
||||
|
||||
(defn- unsafe? [config qualified-symbol]
|
||||
(and (or (end-with-exclamation? qualified-symbol)
|
||||
(explicitly-unsafe? config qualified-symbol))
|
||||
(not (explicitly-safe? config qualified-symbol))))
|
||||
|
||||
(defn- non-thread-safe-form-should-end-with-exclamation*
|
||||
[{[defn-or-defmacro form-name] :children, :as node} config]
|
||||
(when-not (and (:string-value form-name)
|
||||
(end-with-exclamation? (:string-value form-name)))
|
||||
(letfn [(walk [f form]
|
||||
(f form)
|
||||
(doseq [child (:children form)]
|
||||
(walk f child)))
|
||||
(check-node [form]
|
||||
(when-let [qualified-symbol (hooks.common/node->qualified-symbol form)]
|
||||
(when (unsafe? config qualified-symbol)
|
||||
(hooks/reg-finding!
|
||||
(assoc (meta form-name)
|
||||
:message (format "The name of this %s should end with `!` because it contains calls to non thread safe form `%s`. [:metabase/test-helpers-use-non-thread-safe-functions]"
|
||||
(:string-value defn-or-defmacro) qualified-symbol)
|
||||
:type :metabase/test-helpers-use-non-thread-safe-functions)))))]
|
||||
(walk check-node node))
|
||||
node))
|
||||
|
||||
(defn non-thread-safe-form-should-end-with-exclamation
|
||||
"Used to ensure defn and defmacro in test namespace to have name ending with `!` if it's non-thread-safe.
|
||||
A function or a macro can be defined as 'not thread safe' when their funciton name ends with a `!`.
|
||||
|
||||
Only used in tests to identify thread-safe/non-thread-safe test helpers. See #37126"
|
||||
[{:keys [node cljc lang config]}]
|
||||
(when (or (not cljc)
|
||||
(= lang :clj))
|
||||
(non-thread-safe-form-should-end-with-exclamation* node config))
|
||||
{:node node})
|
||||
|
||||
(comment
|
||||
(require '[clj-kondo.core :as clj-kondo])
|
||||
(def form (str '(defmacro a
|
||||
[x]
|
||||
`(fun-call x))))
|
||||
|
||||
(def form "(defmacro a
|
||||
[x]
|
||||
`(some! ~x))")
|
||||
|
||||
(def form "(defun f
|
||||
[x]
|
||||
(let [g! (fn [] 1)]
|
||||
(g!)))")
|
||||
|
||||
(str (hooks/parse-string form))
|
||||
(hooks/sexpr (hooks/parse-string form))
|
||||
|
||||
(binding [hooks/*reload* true]
|
||||
(-> form
|
||||
(with-in-str (clj-kondo/run! {:lint ["-"]}))
|
||||
:findings))
|
||||
|
||||
(do (non-thread-safe-form-should-end-with-exclamation* (hooks/parse-string form)) nil))
|
||||
91
.clj-kondo/src/hooks/clojure/core/ns.clj
Normal file
@@ -0,0 +1,91 @@
|
||||
(ns hooks.clojure.core.ns
|
||||
(:require
|
||||
[clj-kondo.hooks-api :as hooks]
|
||||
[hooks.common]
|
||||
[hooks.common.modules :as modules]))
|
||||
|
||||
(defn- ns-form-node->require-node [ns-form-node]
|
||||
(some (fn [node]
|
||||
(when (and (hooks/list-node? node)
|
||||
(let [first-child (first (:children node))]
|
||||
(and (hooks/keyword-node? first-child)
|
||||
(= (hooks/sexpr first-child) :require))))
|
||||
node))
|
||||
(:children ns-form-node)))
|
||||
|
||||
(defn- lint-require-shapes [ns-form-node]
|
||||
(doseq [node (-> ns-form-node
|
||||
ns-form-node->require-node
|
||||
:children
|
||||
rest)]
|
||||
(cond
|
||||
(not (hooks/vector-node? node))
|
||||
(hooks/reg-finding! (assoc (meta node)
|
||||
:message "All :required namespaces should be wrapped in vectors [:metabase/require-shape-checker]"
|
||||
:type :metabase/require-shape-checker))
|
||||
|
||||
(hooks/vector-node? (second (:children node)))
|
||||
(hooks/reg-finding! (assoc (meta node)
|
||||
:message "Don't use prefix forms inside :require [:metabase/require-shape-checker]"
|
||||
:type :metabase/require-shape-checker)))))
|
||||
|
||||
(defn- lint-requires-on-new-lines [ns-form-node]
|
||||
(let [[require-keyword first-require] (-> ns-form-node
|
||||
ns-form-node->require-node
|
||||
:children)]
|
||||
(when-let [require-keyword-line (:row (meta require-keyword))]
|
||||
(when-let [first-require-line (:row (meta first-require))]
|
||||
(when (= require-keyword-line first-require-line)
|
||||
(hooks/reg-finding! (assoc (meta first-require)
|
||||
:message "Put your requires on a newline from the :require keyword [:metabase/require-shape-checker]"
|
||||
:type :metabase/require-shape-checker)))))))
|
||||
|
||||
(defn- require-node->namespace-symb-nodes [require-node]
|
||||
(let [[_ns & args] (:children require-node)]
|
||||
(into []
|
||||
;; prefixed namespace forms are NOT SUPPORTED!!!!!!!!1
|
||||
(keep (fn [node]
|
||||
(cond
|
||||
(hooks/vector-node? node)
|
||||
;; propagate the metadata attached to this vector in case there's a `:clj-kondo/ignore` form.
|
||||
(let [symbol-node (first (:children node))]
|
||||
(hooks.common/merge-ignored-linters symbol-node require-node node))
|
||||
|
||||
;; this should also be dead code since we require requires to be vectors
|
||||
(hooks/token-node? node)
|
||||
(hooks.common/merge-ignored-linters node require-node)
|
||||
|
||||
:else
|
||||
(printf "Don't know how to figure out what namespace is being required in %s\n" (pr-str node)))))
|
||||
args)))
|
||||
|
||||
(defn- ns-form-node->ns-symb [ns-form-node]
|
||||
(some-> (some (fn [node]
|
||||
(when (and (hooks/token-node? node)
|
||||
(not= (hooks/sexpr node) 'ns))
|
||||
node))
|
||||
(:children ns-form-node))
|
||||
hooks/sexpr))
|
||||
|
||||
(defn- lint-modules [ns-form-node config]
|
||||
(let [ns-symb (ns-form-node->ns-symb ns-form-node)]
|
||||
(when-not (modules/ignored-namespace? config ns-symb)
|
||||
(when-let [current-module (modules/module ns-symb)]
|
||||
(let [required-namespace-symb-nodes (-> ns-form-node
|
||||
ns-form-node->require-node
|
||||
require-node->namespace-symb-nodes)]
|
||||
(doseq [node required-namespace-symb-nodes
|
||||
:when (not (contains? (hooks.common/ignored-linters node) :metabase/modules))
|
||||
:let [required-namespace (hooks/sexpr node)
|
||||
error (modules/usage-error config current-module required-namespace)]
|
||||
:when error]
|
||||
(hooks/reg-finding! (assoc (meta node)
|
||||
:message error
|
||||
:type :metabase/modules))))))))
|
||||
|
||||
(defn lint-ns [x]
|
||||
(doto (:node x)
|
||||
lint-require-shapes
|
||||
lint-requires-on-new-lines
|
||||
(lint-modules (modules/config x)))
|
||||
x)
|
||||
69
.clj-kondo/src/hooks/clojure/core/require.clj
Normal file
@@ -0,0 +1,69 @@
|
||||
(ns hooks.clojure.core.require
|
||||
(:require
|
||||
[clj-kondo.hooks-api :as hooks]
|
||||
[hooks.common.modules :as modules]))
|
||||
|
||||
(defn- lint* [node current-ns config required-namespaces]
|
||||
{:pre [(map? node)
|
||||
(simple-symbol? current-ns)
|
||||
(map? config)
|
||||
(sequential? required-namespaces)
|
||||
(every? simple-symbol? required-namespaces)]}
|
||||
(when-not (modules/ignored-namespace? config current-ns)
|
||||
;; ignore namespaces outside of the module system
|
||||
(when-let [current-module (modules/module current-ns)]
|
||||
(doseq [required-namespace required-namespaces]
|
||||
;; ignore namespaces outside of the module system.
|
||||
(when (modules/module required-namespace)
|
||||
(when-let [error (modules/usage-error config current-module required-namespace)]
|
||||
(hooks/reg-finding! (assoc (meta node)
|
||||
:message error
|
||||
:type :metabase/modules))))))))
|
||||
|
||||
(defn- unwrap-require [node]
|
||||
(case (hooks/tag node)
|
||||
;; some.namespace of some.namespace/some-var
|
||||
:token
|
||||
(let [sexpr (hooks/sexpr node)]
|
||||
(if (qualified-symbol? sexpr)
|
||||
(symbol (namespace sexpr))
|
||||
sexpr))
|
||||
|
||||
;; (quote some.namespace)
|
||||
:list
|
||||
(let [[x y] (:children node)]
|
||||
(when (and (hooks/token-node? x)
|
||||
(= (hooks/sexpr x) 'quote))
|
||||
(recur y)))
|
||||
|
||||
;; 'some.namespace
|
||||
:quote
|
||||
(recur (first (:children node)))
|
||||
|
||||
;; something like [some.namespace :as whatever]
|
||||
:vector
|
||||
(recur (first (:children node)))))
|
||||
|
||||
(comment
|
||||
(unwrap-require (-> "(requiring-resolve 'metabase.notification.payload.execute/execute-dashboard)"
|
||||
hooks/parse-string
|
||||
:children
|
||||
second)))
|
||||
|
||||
(defn- lint-require* [node current-ns config]
|
||||
(let [[_require & args] (:children node)
|
||||
required-namespaces (keep unwrap-require args)]
|
||||
(lint* node current-ns config required-namespaces)))
|
||||
|
||||
(defn- lint-requiring-resolve* [node current-ns config]
|
||||
(let [[_requiring-resolve symb-node] (:children node)
|
||||
required-namespace (unwrap-require symb-node)]
|
||||
(lint* node current-ns config [required-namespace])))
|
||||
|
||||
(defn lint-require [x]
|
||||
(lint-require* (:node x) (:ns x) (modules/config x))
|
||||
x)
|
||||
|
||||
(defn lint-requiring-resolve [x]
|
||||
(lint-requiring-resolve* (:node x) (:ns x) (modules/config x))
|
||||
x)
|
||||
81
.clj-kondo/src/hooks/common/modules.clj
Normal file
@@ -0,0 +1,81 @@
|
||||
(ns hooks.common.modules)
|
||||
|
||||
(defn ignored-namespace? [config ns-symb]
|
||||
(some
|
||||
(fn [pattern-str]
|
||||
(re-find (re-pattern pattern-str) (str ns-symb)))
|
||||
(:ignored-namespace-patterns config)))
|
||||
|
||||
(defn config [{:keys [config], :as _hook-input}]
|
||||
(merge (get-in config [:linters :metabase/modules])
|
||||
(select-keys config [:metabase/modules])))
|
||||
|
||||
(defn module
|
||||
"E.g.
|
||||
|
||||
(module 'metabase.qp.middleware.wow) => 'qp
|
||||
(module 'metabase-enterprise.whatever.core) => enterprise/whatever"
|
||||
[ns-symb]
|
||||
{:pre [(simple-symbol? ns-symb)]}
|
||||
(or (some->> (re-find #"^metabase-enterprise\.([^.]+)" (str ns-symb))
|
||||
second
|
||||
(symbol "enterprise"))
|
||||
(some-> (re-find #"^metabase\.([^.]+)" (str ns-symb))
|
||||
second
|
||||
symbol)))
|
||||
|
||||
(defn module-api-namespaces
|
||||
"Set of API namespace symbols for a given module. `:any` means you can use anything, there are no API namespaces for
|
||||
this module (yet). If unspecified, the default is just the `<module>.core` namespace."
|
||||
[config module]
|
||||
(let [module-config (get-in config [:metabase/modules module :api])]
|
||||
(cond
|
||||
(= module-config :any)
|
||||
nil
|
||||
|
||||
(set? module-config)
|
||||
module-config
|
||||
|
||||
:else
|
||||
(let [ns-prefix (if (= (namespace module) "enterprise")
|
||||
(str "metabase-enterprise." (name module))
|
||||
(name module))]
|
||||
#{(symbol (str ns-prefix ".api"))
|
||||
(symbol (str ns-prefix ".core"))
|
||||
(symbol (str ns-prefix ".init"))}))))
|
||||
|
||||
(defn allowed-modules
|
||||
"Set of namespace symbols that `module` is allowed to use. `:any` means it's allowed to use anything."
|
||||
[config module]
|
||||
(get-in config [:metabase/modules module :uses]))
|
||||
|
||||
(defn allowed-module? [config module required-module]
|
||||
(let [allowed-modules (allowed-modules config module)]
|
||||
(or (= allowed-modules :any)
|
||||
(contains? (set allowed-modules) required-module))))
|
||||
|
||||
(defn allowed-module-namespace? [config ns-symb]
|
||||
(let [module (module ns-symb)
|
||||
module-api-namespaces (module-api-namespaces config module)]
|
||||
(or (empty? module-api-namespaces)
|
||||
(contains? module-api-namespaces ns-symb))))
|
||||
|
||||
(defn usage-error
|
||||
"Find usage errors when a `required-namespace` is required in the `current-module`. Returns a string describing the
|
||||
error type if there is one, otherwise `nil` if there are no errors."
|
||||
[config current-module required-namespace]
|
||||
;; ignore stuff not in a module i.e. non-Metabase stuff.
|
||||
(when-let [required-module (module required-namespace)]
|
||||
(when-not (= current-module required-module)
|
||||
(cond
|
||||
(not (allowed-module? config current-module required-module))
|
||||
(format "Module %s should not be used in the %s module. [:metabase/modules %s :uses]"
|
||||
required-module
|
||||
current-module
|
||||
current-module)
|
||||
|
||||
(not (allowed-module-namespace? config required-namespace))
|
||||
(format "Namespace %s is not an allowed external API namespace for the %s module. [:metabase/modules %s :api]"
|
||||
required-namespace
|
||||
required-module
|
||||
required-module)))))
|
||||
@@ -1,32 +0,0 @@
|
||||
(ns hooks.metabase.api.common
|
||||
(:require
|
||||
[clj-kondo.hooks-api :as api]
|
||||
[clojure.string :as str]
|
||||
[hooks.common]))
|
||||
|
||||
(defn route-fn-name
|
||||
"route fn hook"
|
||||
[method route]
|
||||
(let [route (if (vector? route) (first route) route)]
|
||||
(-> (str (name method) route)
|
||||
(str/replace #"/" "_")
|
||||
symbol)))
|
||||
|
||||
(defn defendpoint
|
||||
[arg]
|
||||
(letfn [(update-defendpoint [node]
|
||||
(let [[_defendpoint method route & body] (:children node)]
|
||||
(-> (api/list-node
|
||||
(list
|
||||
(api/token-node 'do)
|
||||
(-> (api/token-node (symbol "compojure.core" (str (api/sexpr method))))
|
||||
(with-meta (meta method)))
|
||||
(api/list-node
|
||||
(list*
|
||||
(api/token-node 'clojure.core/defn)
|
||||
(-> (api/token-node (route-fn-name (api/sexpr method) (api/sexpr route)))
|
||||
(with-meta (meta route)))
|
||||
body))))
|
||||
(with-meta (meta node))
|
||||
hooks.common/add-lsp-ignore-unused-public-var-metadata)))]
|
||||
(update arg :node update-defendpoint)))
|
||||
@@ -1,6 +1,7 @@
|
||||
(ns hooks.metabase.api.macros
|
||||
(:require
|
||||
[clj-kondo.hooks-api :as api]))
|
||||
[clj-kondo.hooks-api :as api]
|
||||
[hooks.common]))
|
||||
|
||||
(defn defendpoint
|
||||
[arg]
|
||||
@@ -41,9 +42,15 @@
|
||||
(list*
|
||||
(api/token-node `let)
|
||||
(api/vector-node (into []
|
||||
(mapcat (fn [a-binding]
|
||||
[a-binding (api/token-node nil)]))
|
||||
bindings))
|
||||
cat
|
||||
[(mapcat (fn [a-binding]
|
||||
[a-binding (api/map-node {})])
|
||||
(take 4 bindings))
|
||||
(mapcat (fn [a-binding]
|
||||
[a-binding (api/list-node (list
|
||||
(api/token-node 'clojure.core/constantly)
|
||||
(api/token-node 'nil)))])
|
||||
(drop 4 bindings))]))
|
||||
body))))
|
||||
(with-meta (meta node)))))]
|
||||
(update arg :node update-defendpoint)))
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
(ns hooks.metabase.model-persistence.test-util
|
||||
(:require
|
||||
[clj-kondo.hooks-api :as hooks]))
|
||||
|
||||
(defn with-persistence-enabled! [x]
|
||||
(letfn [(update-node [node]
|
||||
(let [[_symb bindings & body] (:children node)
|
||||
[fn-binding] (:children bindings)]
|
||||
(-> (hooks/list-node
|
||||
(list*
|
||||
(hooks/token-node `let)
|
||||
(hooks/vector-node
|
||||
[fn-binding (hooks/list-node
|
||||
(list
|
||||
(hooks/token-node `fn)
|
||||
(hooks/vector-node [])))])
|
||||
body))
|
||||
(with-meta (meta node)))))]
|
||||
(update x :node update-node)))
|
||||
@@ -3,6 +3,7 @@
|
||||
[clj-kondo.hooks-api :as hooks]
|
||||
[hooks.common :as common]))
|
||||
|
||||
;;; TODO -- move this into
|
||||
(def ^:private ignored-implicit-export?
|
||||
'#{active-users-count
|
||||
admin-email
|
||||
@@ -197,15 +198,18 @@
|
||||
:message "Setting definition must provide an explicit value for :export? indicating whether the setting should be exported or not with serialization."
|
||||
:type :metabase/defsetting-must-specify-export))))
|
||||
|
||||
{:node (-> (list
|
||||
(hooks/token-node 'let)
|
||||
{:node (-> (hooks/list-node
|
||||
(list
|
||||
(hooks/token-node 'let)
|
||||
;; include description and the options map so they can get validated as well.
|
||||
(hooks/vector-node
|
||||
[anon-binding docstring
|
||||
anon-binding (hooks/map-node options-list)])
|
||||
getter-node
|
||||
setter-node)
|
||||
hooks/list-node
|
||||
(hooks/vector-node
|
||||
[anon-binding docstring
|
||||
anon-binding (hooks/map-node options-list)])
|
||||
(hooks/reg-keyword! (-> (hooks/keyword-node (keyword (hooks/sexpr setting-name)))
|
||||
(with-meta (meta setting-name)))
|
||||
'metabase.models.setting/defsetting)
|
||||
getter-node
|
||||
setter-node))
|
||||
(with-meta (meta node)))}))
|
||||
|
||||
(defn defsetting
|
||||
@@ -221,9 +225,11 @@
|
||||
(defn my-setting! \"Docstring.\" [_value-or-nil]))
|
||||
|
||||
for linting purposes."
|
||||
[{:keys [node]}]
|
||||
[{:keys [node], :as context}]
|
||||
(let [[setting-name docstring & options] (rest (:children node))]
|
||||
(defsetting-lint node setting-name docstring options)))
|
||||
(merge
|
||||
context
|
||||
(defsetting-lint node setting-name docstring options))))
|
||||
|
||||
(defn define-multi-setting
|
||||
"Rewrite a [[metabase.models.define-multi-setting]] form like
|
||||
@@ -238,9 +244,30 @@
|
||||
(defn my-setting! \"Docstring.\" [_value-or-nil]))
|
||||
|
||||
for linting purposes."
|
||||
[{:keys [node]}]
|
||||
[{:keys [node], :as context}]
|
||||
(let [[setting-name docstring thunk & options] (rest (:children node))]
|
||||
(defsetting-lint node setting-name docstring (concat options [(hooks/token-node :multi-thunk) thunk]))))
|
||||
(merge
|
||||
context
|
||||
(defsetting-lint node setting-name docstring (concat options [(hooks/token-node :multi-thunk) thunk])))))
|
||||
|
||||
(defn define-multi-setting-impl
|
||||
[context]
|
||||
(letfn [(update-node [node]
|
||||
(let [[_define-multi-setting-impl setting-name & more] (:children node)]
|
||||
(-> (hooks/list-node
|
||||
(list*
|
||||
(hooks/token-node 'do)
|
||||
;; For a qualified setting name like `oss-namespace/setting`, then leave the symbol as is, so the
|
||||
;; usage of that namespace/var gets recorded. Otherwise for an unqualified name convert it to a
|
||||
;; keyword so we don't get unresolved var errors.
|
||||
(if (and (hooks/token-node? setting-name)
|
||||
(qualified-symbol? (hooks/sexpr setting-name)))
|
||||
setting-name
|
||||
(-> (hooks/keyword-node (keyword (hooks/sexpr setting-name)))
|
||||
(with-meta (meta setting-name))))
|
||||
more))
|
||||
(with-meta (meta node)))))]
|
||||
(update context :node update-node)))
|
||||
|
||||
(comment
|
||||
(defn- defsetting* [form]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
(ns hooks.metabase.api.search-test
|
||||
(ns hooks.metabase.search.api-test
|
||||
(:require [clj-kondo.hooks-api :as hooks]))
|
||||
|
||||
(defn with-search-items-in-collection [{{[_ & args] :children, :as node} :node}]
|
||||
@@ -6,8 +6,8 @@
|
||||
|
||||
(defn- only-core-drivers?
|
||||
"Whether we're for sure only testing against the 'core' drivers that are also app DB types: `:postgres`, `:mysql`, or
|
||||
`:h2`. Tests like these are ok to mark `:mb/once` or `:mb/driver-tests` since we always run the full test suite
|
||||
against app DB drivers anyway."
|
||||
`:h2`. Tests like these are ok to mark `:mb/driver-tests` since we always run the full test suite against app DB
|
||||
drivers anyway."
|
||||
[node]
|
||||
(let [drivers (hooks/sexpr (second (:children node)))
|
||||
drivers (cond
|
||||
@@ -17,14 +17,6 @@
|
||||
(when drivers
|
||||
(empty? (set/difference drivers #{:h2 :mysql :postgres})))))
|
||||
|
||||
(defn- validate-mb-once [x]
|
||||
(when (:mb/once (meta (:ns x)))
|
||||
(hooks/reg-finding!
|
||||
(assoc (meta (:ns x))
|
||||
:message (str "You should not use test-driver or test-drivers in a namespace marked ^:mb/once"
|
||||
" [:metabase/validate-mb-once]")
|
||||
:type :metabase/validate-mb-once))))
|
||||
|
||||
(defn- validate-mb-driver-tests [x]
|
||||
(when-not (:mb/driver-tests (meta (:ns x)))
|
||||
(hooks/reg-finding!
|
||||
@@ -35,7 +27,6 @@
|
||||
|
||||
(defn- validate-ns-tags [x]
|
||||
(when-not (only-core-drivers? (:node x))
|
||||
(validate-mb-once x)
|
||||
(validate-mb-driver-tests x)))
|
||||
|
||||
(defn test-drivers [x]
|
||||
|
||||
14
.clj-kondo/src/hooks/metabase/test/gentest.clj
Normal file
@@ -0,0 +1,14 @@
|
||||
(ns hooks.metabase.test.gentest
|
||||
(:require
|
||||
[clj-kondo.hooks-api :as hooks]))
|
||||
|
||||
(defn with-gentest
|
||||
"(with-gentest {:as limit-spec} [s1 val1 & more] body-form body-form...)"
|
||||
[{{:keys [children] :as node} :node :as orig}]
|
||||
(let [[token limit-spec bindings & body-nodes] children
|
||||
node* (-> (hooks/list-node
|
||||
(list token limit-spec
|
||||
(hooks/list-node (list* (hooks/token-node 'let) bindings
|
||||
body-nodes))))
|
||||
(with-meta (meta node)))]
|
||||
(assoc orig :node node*)))
|
||||
@@ -1,5 +1,6 @@
|
||||
(ns hooks.metabase.api.automagic-dashboards-test
|
||||
(:require [clj-kondo.hooks-api :as hooks]))
|
||||
(ns hooks.metabase.xrays.api.automagic-dashboards-test
|
||||
(:require
|
||||
[clj-kondo.hooks-api :as hooks]))
|
||||
|
||||
(comment
|
||||
|
||||
@@ -10,7 +11,7 @@
|
||||
|
||||
(println (hooks/sexpr input))
|
||||
|
||||
(let [f (load-file ".clj-kondo/hooks/metabase/api/automagic_dashboards_test.clj")]
|
||||
(let [f (load-file ".clj-kondo/hooks/metabase/xrays/api/automagic_dashboards_test.clj")]
|
||||
(f {:node input})))
|
||||
|
||||
(defn with-indexed-model!
|
||||
63
.clj-kondo/test/hooks/clojure/core/defmulti_test.clj
Normal file
@@ -0,0 +1,63 @@
|
||||
(ns hooks.clojure.core.defmulti-test
|
||||
(:require
|
||||
[clj-kondo.hooks-api :as hooks]
|
||||
[clj-kondo.impl.utils]
|
||||
[clojure.test :refer :all]
|
||||
[hooks.clojure.core.defmulti]))
|
||||
|
||||
(defn- lint-defmulti [form]
|
||||
(binding [clj-kondo.impl.utils/*ctx* {:config {:linters {:metabase/check-defmulti-arglists {:level :warning}}}
|
||||
:ignores (atom nil)
|
||||
:findings (atom [])
|
||||
:namespaces (atom {})}]
|
||||
(hooks.clojure.core.defmulti/lint-defmulti {:node (hooks/parse-string (pr-str form))})
|
||||
@(:findings clj-kondo.impl.utils/*ctx*)))
|
||||
|
||||
(deftest ^:parallel defmulti-missing-arglists-test
|
||||
(testing "missing arglists"
|
||||
(is (=? [{:message "All defmultis should have an attribute map with :arglists metadata. [:metabase/check-defmulti-arglists]"}]
|
||||
(lint-defmulti '(defmulti expand-visualization
|
||||
(fn [card _ _]
|
||||
(-> card :visualization first))))))))
|
||||
|
||||
(deftest ^:parallel defmulti-invalid-arglists-test
|
||||
(testing "invalid arglists"
|
||||
(are [form] (=? [{:message ":arglists should be a quoted list of vectors [:metabase/check-defmulti-arglists]"}]
|
||||
(lint-defmulti form))
|
||||
'(defmulti expand-visualization
|
||||
{:arglists '()}
|
||||
(fn [card _ _]
|
||||
(-> card :visualization first)))
|
||||
'(defmulti expand-visualization
|
||||
{:arglists ([a])} ; unquoted
|
||||
(fn [card _ _]
|
||||
(-> card :visualization first)))
|
||||
'(defmulti expand-visualization
|
||||
{:arglists '[(a)]}
|
||||
(fn [card _ _]
|
||||
(-> card :visualization first)))
|
||||
'(defmulti expand-visualization
|
||||
{:arglists '((a))}
|
||||
(fn [card _ _]
|
||||
(-> card :visualization first))))))
|
||||
|
||||
(deftest ^:parallel defmulti-arglists-with-underscore-args-test
|
||||
(testing "arglists, but some symbols are _"
|
||||
(are [form] (=? [{:message ":arglists should contain actual arg names, not underscore (unused) symbols [:metabase/check-defmulti-arglists]"}]
|
||||
(lint-defmulti form))
|
||||
'(defmulti expand-visualization
|
||||
{:arglists '([card _ _])}
|
||||
(fn [card _ _]
|
||||
(-> card :visualization first)))
|
||||
'(defmulti expand-visualization
|
||||
{:arglists '([card _bad _arg])}
|
||||
(fn [card _ _]
|
||||
(-> card :visualization first))))))
|
||||
|
||||
(deftest ^:parallel defmulti-arglists-ok-test
|
||||
(testing "good"
|
||||
(is (= []
|
||||
(lint-defmulti '(defmulti expand-visualization
|
||||
{:arglists '([card x y])}
|
||||
(fn [card _ _]
|
||||
(-> card :visualization first))))))))
|
||||
74
.clj-kondo/test/hooks/clojure/core/ns_test.clj
Normal file
@@ -0,0 +1,74 @@
|
||||
(ns hooks.clojure.core.ns-test
|
||||
(:require
|
||||
[clj-kondo.hooks-api :as hooks]
|
||||
[clj-kondo.impl.utils]
|
||||
[clojure.test :refer :all]
|
||||
[hooks.clojure.core.ns]))
|
||||
|
||||
(defn- lint-ns [form config]
|
||||
(binding [clj-kondo.impl.utils/*ctx* {:config config
|
||||
:ignores (atom nil)
|
||||
:findings (atom [])
|
||||
:namespaces (atom {})}]
|
||||
(hooks.clojure.core.ns/lint-ns {:node (hooks/parse-string
|
||||
(binding [*print-meta* true]
|
||||
(pr-str form)))
|
||||
:config config})
|
||||
@(:findings clj-kondo.impl.utils/*ctx*)))
|
||||
|
||||
(defn- lint-modules [form config]
|
||||
(lint-ns form (assoc-in config [:linters :metabase/modules :level] :warning)))
|
||||
|
||||
(deftest ^:parallel module-checker-allowed-modules-test
|
||||
(is (=? [{:message "Module task should not be used in the api module. [:metabase/modules api :uses]"
|
||||
:type :metabase/modules}]
|
||||
(lint-modules
|
||||
'(ns metabase.api.search
|
||||
(:require
|
||||
[metabase.request.core :as request]
|
||||
[metabase.task :as task]))
|
||||
'{:metabase/modules {api {:uses #{request}}
|
||||
request {:api #{metabase.request.core}}}}))))
|
||||
|
||||
(deftest ^:parallel module-checker-api-namespaces-test
|
||||
(is (=? [{:message "Namespace metabase.search.config is not an allowed external API namespace for the search module. [:metabase/modules search :api]"
|
||||
:type :metabase/modules}]
|
||||
(lint-modules
|
||||
'(ns metabase.api.search
|
||||
(:require
|
||||
[metabase.search.config :as search.config]
|
||||
[metabase.search.core :as search]))
|
||||
'{:metabase/modules {api {:uses #{search}}
|
||||
search {:api #{metabase.search.core}}}}))))
|
||||
|
||||
(deftest ^:parallel module-checker-api-namespaces-ignore-test
|
||||
(is (empty? (lint-modules
|
||||
'(ns metabase.api.search
|
||||
(:require
|
||||
^{:clj-kondo/ignore [:metabase/modules]}
|
||||
[metabase.search.config :as search.config]
|
||||
[metabase.search.core :as search]))
|
||||
'{:metabase/modules {api {:uses #{search}}
|
||||
search {:api #{metabase.search.core}}}}))))
|
||||
|
||||
(deftest ^:parallel module-checker-enterprise-test
|
||||
(is (=? [{:message "Module search should not be used in the enterprise/search module. [:metabase/modules enterprise/search :uses]"
|
||||
:type :metabase/modules}]
|
||||
(lint-modules
|
||||
'(ns metabase-enterprise.search.core
|
||||
(:require
|
||||
[metabase.search.core :as search]))
|
||||
'{:metabase/modules {search {:api #{metabase.search.core}}}}))))
|
||||
|
||||
(deftest ^:parallel require-newlines-test
|
||||
(binding [clj-kondo.impl.utils/*ctx* {:config {:linters {:metabase/require-shape-checker {:level :warnings}}}
|
||||
:ignores (atom nil)
|
||||
:findings (atom [])
|
||||
:namespaces (atom {})}]
|
||||
(hooks.clojure.core.ns/lint-ns {:node (hooks/parse-string "
|
||||
(ns metabase.task.cache
|
||||
(:require [metabase.task.bunny]
|
||||
[metabase.task.rabbit]))")})
|
||||
(is (=? [{:message "Put your requires on a newline from the :require keyword [:metabase/require-shape-checker]",
|
||||
:type :metabase/require-shape-checker}]
|
||||
@(:findings clj-kondo.impl.utils/*ctx*)))))
|
||||
@@ -1,54 +0,0 @@
|
||||
(ns hooks.clojure.core-test
|
||||
(:require
|
||||
[clj-kondo.hooks-api :as hooks]
|
||||
[clojure.test :refer :all]
|
||||
[hooks.clojure.core]))
|
||||
|
||||
(deftest module-checker-allowed-modules-test
|
||||
(let [findings (atom [])]
|
||||
(with-redefs [hooks/reg-finding! (fn [node]
|
||||
(swap! findings conj node))]
|
||||
(hooks.clojure.core/lint-ns
|
||||
{:node (hooks/parse-string "
|
||||
(ns metabase.api.search
|
||||
(:require
|
||||
[metabase.request.core :as request]
|
||||
[metabase.task :as task]))")
|
||||
:config '{:linters {:metabase/ns-module-checker {:allowed-modules {metabase.api #{metabase.request}}
|
||||
:api-namespaces {metabase.request #{metabase.request.core}}}}}})
|
||||
(is (=? [{:message (str "Module metabase.task should not be used in the metabase.api module."
|
||||
" [:metabase/ns-module-checker :allowed-modules metabase.api]")
|
||||
:type :metabase/ns-module-checker}]
|
||||
@findings)))))
|
||||
|
||||
(deftest module-checker-api-namespaces-test
|
||||
(let [findings (atom [])]
|
||||
(with-redefs [hooks/reg-finding! (fn [node]
|
||||
(swap! findings conj node))]
|
||||
(hooks.clojure.core/lint-ns
|
||||
{:node (hooks/parse-string "
|
||||
(ns metabase.api.search
|
||||
(:require
|
||||
[metabase.search.config :as search.config]
|
||||
[metabase.search.core :as search]))")
|
||||
:config '{:linters {:metabase/ns-module-checker {:allowed-modules {metabase.api #{metabase.search}}
|
||||
:api-namespaces {metabase.search #{metabase.search.core}}}}}})
|
||||
(is (=? [{:message (str "Namespace metabase.search.config is not an allowed external API namespace for the"
|
||||
" metabase.search module. [:metabase/ns-module-checker :api-namespaces metabase.search]")
|
||||
:type :metabase/ns-module-checker}]
|
||||
@findings)))))
|
||||
|
||||
(deftest module-checker-api-namespaces-ignore-test
|
||||
(let [findings (atom [])]
|
||||
(with-redefs [hooks/reg-finding! (fn [node]
|
||||
(swap! findings conj node))]
|
||||
(hooks.clojure.core/lint-ns
|
||||
{:node (hooks/parse-string "
|
||||
(ns metabase.api.search
|
||||
(:require
|
||||
^{:clj-kondo/ignore [:metabase/ns-module-checker]}
|
||||
[metabase.search.config :as search.config]
|
||||
[metabase.search.core :as search]))")
|
||||
:config '{:linters {:metabase/ns-module-checker {:allowed-modules {metabase.api #{metabase.search}}
|
||||
:api-namespaces {metabase.search #{metabase.search.core}}}}}})
|
||||
(is (empty? @findings)))))
|
||||
10
.clj-kondo/test/hooks/common/modules_test.clj
Normal file
@@ -0,0 +1,10 @@
|
||||
(ns hooks.common.modules-test
|
||||
(:require
|
||||
[clojure.test :refer :all]
|
||||
[hooks.common.modules]))
|
||||
|
||||
(deftest ^:parallel module-test
|
||||
(are [symb expected] (= expected
|
||||
(hooks.common.modules/module symb))
|
||||
'metabase.qp.middleware.wow 'qp
|
||||
'metabase-enterprise.whatever.core 'enterprise/whatever))
|
||||
@@ -1,4 +1,4 @@
|
||||
(ns ^:mb/once hooks.common-test
|
||||
(ns hooks.common-test
|
||||
(:require
|
||||
[clj-kondo.hooks-api :as api]
|
||||
[clj-kondo.impl.utils]
|
||||
@@ -6,16 +6,16 @@
|
||||
[hooks.common]))
|
||||
|
||||
(deftest ^:parallel ignored-linters-test
|
||||
(doseq [ignored [":metabase/ns-module-checker"
|
||||
"[:metabase/ns-module-checker]"
|
||||
"(:metabase/ns-module-checker)"]
|
||||
(doseq [ignored [":metabase/modules"
|
||||
"[:metabase/modules]"
|
||||
"(:metabase/modules)"]
|
||||
prefix ["#_"
|
||||
"^"]
|
||||
:let [s (format "%s{:clj-kondo/ignore %s} [metabase.search.config :as search.config]"
|
||||
prefix
|
||||
ignored)]]
|
||||
(testing (pr-str s)
|
||||
(is (= #{:metabase/ns-module-checker}
|
||||
(is (= #{:metabase/modules}
|
||||
(hooks.common/ignored-linters (api/parse-string s)))))))
|
||||
|
||||
(deftest ^:parallel merge-ignored-linters-test
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
(ns hooks.metabase.api.common-test
|
||||
(:require
|
||||
[clj-kondo.hooks-api :as api]
|
||||
[clojure.test :refer :all]
|
||||
[hooks.metabase.api.common]))
|
||||
|
||||
(deftest ^:parallel defendpoint-test
|
||||
(is (= '(do
|
||||
compojure.core/POST
|
||||
(clojure.core/defn
|
||||
POST_:id_copy
|
||||
"Copy a `Card`, with the new name 'Copy of _name_'"
|
||||
[id]
|
||||
{id [:maybe ms/PositiveInt]}
|
||||
(let [orig-card (api/read-check Card id)
|
||||
new-name (str (trs "Copy of ") (:name orig-card))
|
||||
new-card (assoc orig-card :name new-name)]
|
||||
(-> (card/create-card! new-card @api/*current-user*)
|
||||
hydrate-card-details
|
||||
(assoc :last-edit-info (last-edit/edit-information-for-user @api/*current-user*))))))
|
||||
(-> {:node (-> '(api/defendpoint POST "/:id/copy"
|
||||
"Copy a `Card`, with the new name 'Copy of _name_'"
|
||||
[id]
|
||||
{id [:maybe ms/PositiveInt]}
|
||||
(let [orig-card (api/read-check Card id)
|
||||
new-name (str (trs "Copy of ") (:name orig-card))
|
||||
new-card (assoc orig-card :name new-name)]
|
||||
(-> (card/create-card! new-card @api/*current-user*)
|
||||
hydrate-card-details
|
||||
(assoc :last-edit-info (last-edit/edit-information-for-user @api/*current-user*)))))
|
||||
pr-str
|
||||
api/parse-string)}
|
||||
hooks.metabase.api.common/defendpoint
|
||||
:node
|
||||
api/sexpr))))
|
||||
@@ -4,32 +4,68 @@
|
||||
[clojure.test :refer :all]
|
||||
[hooks.metabase.api.macros]))
|
||||
|
||||
(defn- is-valid-node [x]
|
||||
(is (api/node? x))
|
||||
(doseq [child (:children x)]
|
||||
(is-valid-node child)))
|
||||
|
||||
(deftest ^:parallel defendpoint-test
|
||||
(let [form '(api.macros/defendpoint :post "/" :- [:map [:collection_id :int]]
|
||||
"Create a new [[Timeline]]."
|
||||
[_route-params
|
||||
_query-params
|
||||
{:keys [icon], collection-id :collection_id, :as body} :- [:map
|
||||
[:name ms/NonBlankString]
|
||||
[:default {:optional true} [:maybe :boolean]]]]
|
||||
(body icon)
|
||||
(body collection-id))
|
||||
node (-> form pr-str api/parse-string)]
|
||||
(is (= '(do
|
||||
api.macros/defendpoint
|
||||
:post
|
||||
"/"
|
||||
(do
|
||||
[:map [:collection_id :int]]
|
||||
[:map
|
||||
[:name ms/NonBlankString]
|
||||
[:default {:optional true} [:maybe :boolean]]])
|
||||
(clojure.core/let [_route-params nil
|
||||
_query-params nil
|
||||
{:keys [icon], collection-id :collection_id, :as body} nil]
|
||||
(body icon)
|
||||
(body collection-id)))
|
||||
(-> {:node node}
|
||||
hooks.metabase.api.macros/defendpoint
|
||||
:node
|
||||
api/sexpr)))))
|
||||
(letfn [(defendpoint [form]
|
||||
(let [node (-> form pr-str api/parse-string)]
|
||||
(is-valid-node node)
|
||||
(-> {:node node}
|
||||
hooks.metabase.api.macros/defendpoint
|
||||
:node
|
||||
api/sexpr)))]
|
||||
(are [form expected] (= expected
|
||||
(defendpoint form))
|
||||
'(api.macros/defendpoint :post "/" :- [:map [:collection_id :int]]
|
||||
"Create a new [[Timeline]]."
|
||||
[_route-params
|
||||
_query-params
|
||||
{:keys [icon], collection-id :collection_id, :as body} :- [:map
|
||||
[:name ms/NonBlankString]
|
||||
[:default {:optional true} [:maybe :boolean]]]]
|
||||
(body icon)
|
||||
(body collection-id))
|
||||
'(do
|
||||
api.macros/defendpoint
|
||||
:post
|
||||
"/"
|
||||
(do
|
||||
[:map [:collection_id :int]]
|
||||
[:map
|
||||
[:name ms/NonBlankString]
|
||||
[:default {:optional true} [:maybe :boolean]]])
|
||||
(clojure.core/let [_route-params {}
|
||||
_query-params {}
|
||||
{:keys [icon], collection-id :collection_id, :as body} {}]
|
||||
(body icon)
|
||||
(body collection-id)))
|
||||
|
||||
'(api.macros/defendpoint :post "/"
|
||||
[_route-params
|
||||
_query-params
|
||||
body
|
||||
request
|
||||
respond
|
||||
raise]
|
||||
(try
|
||||
(respond :x)
|
||||
(catch Throwable e
|
||||
(raise e))))
|
||||
'(do
|
||||
api.macros/defendpoint
|
||||
:post
|
||||
"/"
|
||||
(do)
|
||||
(clojure.core/let [_route-params {}
|
||||
_query-params {}
|
||||
body {}
|
||||
request {}
|
||||
respond (clojure.core/constantly nil)
|
||||
raise (clojure.core/constantly nil)]
|
||||
(try
|
||||
(respond :x)
|
||||
(catch Throwable e
|
||||
(raise e))))))))
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
(ns hooks.metabase.model-persistence.test-util-test
|
||||
(:require
|
||||
[clj-kondo.hooks-api :as hooks]
|
||||
[clojure.test :refer :all]
|
||||
[hooks.metabase.model-persistence.test-util]))
|
||||
|
||||
(deftest ^:parallel with-persistence-enabled-test
|
||||
(is (= '(clojure.core/let [persist-models! (clojure.core/fn [])]
|
||||
(persist-models!)
|
||||
:wow)
|
||||
(as-> '(mt/with-persistence-enabled! [persist-models!]
|
||||
(persist-models!)
|
||||
:wow) <>
|
||||
(pr-str <>)
|
||||
(hooks/parse-string <>)
|
||||
{:node <>}
|
||||
(hooks.metabase.model-persistence.test-util/with-persistence-enabled! <>)
|
||||
(:node <>)
|
||||
(hooks/sexpr <>)))))
|
||||
@@ -1,4 +1,4 @@
|
||||
(ns ^:mb/once hooks.metabase.util.log-test
|
||||
(ns hooks.metabase.util.log-test
|
||||
(:require
|
||||
[clj-kondo.hooks-api :as api]
|
||||
[clj-kondo.impl.utils]
|
||||
|
||||
37
.cljfmt.edn
@@ -93,7 +93,7 @@
|
||||
metabase-enterprise.test/with-gtaps! [[:inner 0]]
|
||||
metabase-enterprise.test/with-gtaps-for-user! [[:inner 0]]
|
||||
metabase-enterprise.test/with-user-attributes [[:block 2]]
|
||||
metabase.actions-test/with-actions-test-data-and-actions-permissively-enabled [[:block 0]]
|
||||
metabase.actions.actions-test/with-actions-test-data-and-actions-permissively-enabled [[:block 0]]
|
||||
metabase.actions.test-util/with-actions [[:block 1]]
|
||||
metabase.actions.test-util/with-actions-disabled [[:block 0]]
|
||||
metabase.actions.test-util/with-actions-enabled [[:block 0]]
|
||||
@@ -102,7 +102,6 @@
|
||||
metabase.actions.test-util/with-actions-test-data-tables [[:block 1]]
|
||||
metabase.actions.test-util/with-empty-db [[:inner 0]]
|
||||
metabase.actions.test-util/with-temp-test-data [[:inner 0]]
|
||||
metabase.api.alert-test/with-alert-in-collection [[:block 1]]
|
||||
metabase.api.card-test/with-cards-in-readable-collection [[:block 1]]
|
||||
metabase.api.card-test/with-cards-in-writeable-collection [[:block 1]]
|
||||
metabase.api.card-test/with-ordered-items [[:inner 0]]
|
||||
@@ -114,9 +113,6 @@
|
||||
metabase.api.common/check [[:default]]
|
||||
metabase.api.common/define-routes [[:block 0]]
|
||||
metabase.api.common/let-404 [[:block 1]]
|
||||
metabase.api.common.internal/auto-coerce [[:block 1]]
|
||||
metabase.api.common.internal/auto-parse [[:block 1]]
|
||||
metabase.api.common.internal-test/no-route-regexes [[:block 0]]
|
||||
metabase.api.embed-test/do-response-formats [[:block 1]]
|
||||
metabase.api.embed-test/with-embedding-enabled-and-new-secret-key [[:block 0]]
|
||||
metabase.api.embed-test/with-embedding-enabled-and-temp-card-referencing [[:block 3]]
|
||||
@@ -126,17 +122,6 @@
|
||||
metabase.api.embed-test/with-temp-dashcard [[:block 1]]
|
||||
metabase.api.preview-embed-test/with-embedding-enabled-and-new-secret-key [[:block 0]]
|
||||
metabase.api.preview-embed-test/with-new-secret-key [[:block 0]]
|
||||
metabase.api.public-test/with-sharing-enabled-and-temp-card-referencing [[:block 3]]
|
||||
metabase.api.public-test/with-sharing-enabled-and-temp-dashcard-referencing [[:block 3]]
|
||||
metabase.api.public-test/with-temp-public-card [[:block 1]]
|
||||
metabase.api.public-test/with-temp-public-dashboard [[:block 1]]
|
||||
metabase.api.public-test/with-temp-public-dashboard-and-card [[:block 1]]
|
||||
metabase.api.search-test/do-test-users [[:block 1]]
|
||||
metabase.api.session/http-401-on-error [[:block 0]]
|
||||
metabase.async.streaming-response/streaming-response [[:block 2]]
|
||||
metabase.async.streaming-response-test/with-streaming-response-thread-pool [[:block 0]]
|
||||
metabase.async.streaming-response-test/with-test-driver-db! [[:block 0]]
|
||||
metabase.async.util/cancelable-thread [[:block 0]]
|
||||
metabase.cmd.copy/step [[:block 1]]
|
||||
metabase.cmd.copy/with-connection-rollback-only [[:block 1]]
|
||||
metabase.cmd.copy/with-disabled-db-constraints [[:block 2]]
|
||||
@@ -179,11 +164,19 @@
|
||||
metabase.models.params.chain-filter-test/with-clean-field-values-for-field [[:block 1]]
|
||||
metabase.models.params.chain-filter-test/with-fk-field-to-field-remapping [[:block 0]]
|
||||
metabase.models.params.chain-filter-test/with-human-readable-values-remapping [[:block 0]]
|
||||
metabase.models.pulse-test/with-dashboard-subscription-in-collection [[:block 1]]
|
||||
metabase.models.pulse-test/with-pulse-in-collection [[:inner 0]]
|
||||
metabase.models.setting/defsetting [[:block 1]]
|
||||
metabase.models.setting.multi-setting/define-multi-setting [[:inner 0]]
|
||||
metabase.models.setting/defsetting [[:block 1]]
|
||||
metabase.models.task-history/with-task-history [[:block 1]]
|
||||
metabase.permissions.core/allow-changing-all-users-group-members [[:block 0]]
|
||||
metabase.permissions.core/disable-perms-cache [[:block 0]]
|
||||
metabase.public-sharing.api-test/with-sharing-enabled-and-temp-card-referencing [[:block 3]]
|
||||
metabase.public-sharing.api-test/with-sharing-enabled-and-temp-dashcard-referencing [[:block 3]]
|
||||
metabase.public-sharing.api-test/with-temp-public-card [[:block 1]]
|
||||
metabase.public-sharing.api-test/with-temp-public-dashboard [[:block 1]]
|
||||
metabase.public-sharing.api-test/with-temp-public-dashboard-and-card [[:block 1]]
|
||||
metabase.pulse.api.alert-test/with-alert-in-collection [[:block 1]]
|
||||
metabase.pulse.models.pulse-test/with-dashboard-subscription-in-collection [[:block 1]]
|
||||
metabase.pulse.models.pulse-test/with-pulse-in-collection [[:inner 0]]
|
||||
metabase.query-processor-test.pipeline-queries-test/pmbql-query [[:block 1]]
|
||||
metabase.query-processor-test.pipeline-queries-test/run-pmbql-query [[:block 1]]
|
||||
metabase.query-processor.debug/debug> [[:block 0]]
|
||||
@@ -201,8 +194,13 @@
|
||||
metabase.request.session/as-admin [[:block 0]]
|
||||
metabase.request.session/with-current-user [[:inner 0]]
|
||||
metabase.sample-data-test/with-temp-sample-database-db [[:block 1]]
|
||||
metabase.search.api-test/do-test-users [[:block 1]]
|
||||
metabase.server.middleware.session/as-admin [[:block 0]]
|
||||
metabase.server.middleware.session/with-current-user [[:inner 0]]
|
||||
metabase.server.streaming-response-test/with-streaming-response-thread-pool [[:block 0]]
|
||||
metabase.server.streaming-response-test/with-test-driver-db! [[:block 0]]
|
||||
metabase.server.streaming-response/streaming-response [[:block 2]]
|
||||
metabase.session.api/http-401-on-error [[:block 0]]
|
||||
metabase.sync.fetch-metadata/log-if-error [[:block 1]]
|
||||
metabase.sync.sync-metadata.fields-test/with-test-db [[:block 0]]
|
||||
metabase.sync.util/do-with-start-and-finish-debug-logging [[:default]]
|
||||
@@ -284,6 +282,7 @@
|
||||
metabase.util/prog1 [[:inner 0]]
|
||||
metabase.util/varargs [[:inner 0]]
|
||||
metabase.util/with-us-locale [[:block 0]]
|
||||
metabase.util.async/cancelable-thread [[:block 0]]
|
||||
metabase.util.date-2/with-time-zone-same-instant [[:default]]
|
||||
metabase.util.encryption-test/with-secret-key [[:block 1]]
|
||||
metabase.util.honey-sql-2/with-database-type-info [[:default]]
|
||||
|
||||
@@ -20,13 +20,8 @@
|
||||
(clojure-mode
|
||||
;; Specify which arg is the docstring for certain macros
|
||||
;; (Add more as needed)
|
||||
(eval . (put 'defendpoint-schema 'clojure-doc-string-elt 3))
|
||||
(eval . (put 'defendpoint 'clojure-doc-string-elt 3))
|
||||
(eval . (put 'defendpoint-async 'clojure-doc-string-elt 3))
|
||||
(eval . (put 'define-premium-feature 'clojure-doc-string-elt 2))
|
||||
(eval . (put 'api/defendpoint-schema 'clojure-doc-string-elt 3))
|
||||
(eval . (put 'api/defendpoint 'clojure-doc-string-elt 3))
|
||||
(eval . (put 'api/defendpoint-async 'clojure-doc-string-elt 3))
|
||||
(eval . (put 'api.macros/defendpoint 'clojure-doc-string-elt 3))
|
||||
(eval . (put 'defsetting 'clojure-doc-string-elt 2))
|
||||
(eval . (put 'setting/defsetting 'clojure-doc-string-elt 2))
|
||||
(eval . (put 's/defn 'clojure-doc-string-elt 2))
|
||||
|
||||
@@ -17,7 +17,7 @@ module.exports = {
|
||||
{
|
||||
vars: "all",
|
||||
args: "none",
|
||||
varsIgnorePattern: "^_",
|
||||
varsIgnorePattern: "^_.+$",
|
||||
ignoreRestSiblings: true,
|
||||
},
|
||||
],
|
||||
@@ -108,7 +108,6 @@ module.exports = {
|
||||
"When",
|
||||
"Then",
|
||||
"describeWithSnowplow",
|
||||
"describeEE",
|
||||
],
|
||||
},
|
||||
],
|
||||
@@ -220,10 +219,10 @@ module.exports = {
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
"error",
|
||||
{
|
||||
argsIgnorePattern: "^_",
|
||||
varsIgnorePattern: "^_",
|
||||
argsIgnorePattern: "^_.+$",
|
||||
varsIgnorePattern: "^_.+$",
|
||||
ignoreRestSiblings: true,
|
||||
destructuredArrayIgnorePattern: "^_",
|
||||
destructuredArrayIgnorePattern: "^_.+$",
|
||||
},
|
||||
],
|
||||
// This was introduced in 6.0.0
|
||||
|
||||
259
.github/CODEOWNERS
vendored
@@ -1,12 +1,257 @@
|
||||
# Before changing this file, make sure you have read how we use it:
|
||||
# https://www.notion.so/metabase/Pull-Request-Code-Review-Guide-374f05df889748b69d67af753f9bc9b8?pvs=4#36550c04ceab40b5a8b8bee6264b090c
|
||||
|
||||
enterprise/backend/src/metabase_enterprise/advanced_permissions @noahmoss
|
||||
enterprise/backend/src/metabase_enterprise/audit_app @noahmoss
|
||||
enterprise/backend/src/metabase_enterprise/sso @noahmoss
|
||||
enterprise/backend/src/metabase_enterprise/task/truncate_audit_table.clj @noahmoss
|
||||
enterprise/backend/src/metabase_enterprise/internal_user.clj @noahmoss
|
||||
enterprise/frontend/src/embedding-sdk @metabase/embedding
|
||||
frontend/src/metabase/embedding-sdk @metabase/embedding
|
||||
frontend/src/metabase/ui @metabase/core-frontend-admin-webapp
|
||||
src/metabase/**/*permissions* @noahmoss
|
||||
src/metabase/integrations @noahmoss
|
||||
snowplow/* @metabase/data
|
||||
e2e @filiphric
|
||||
|
||||
.github @metabase/devexp
|
||||
.clj-kondo @metabase/devexp
|
||||
|
||||
#
|
||||
# Backend modules <=> teams that own them
|
||||
#
|
||||
|
||||
modules/drivers @metabase/drivers
|
||||
|
||||
enterprise/backend/src/metabase_enterprise/advanced_config @metabase/core-backend-admin-webapp
|
||||
enterprise/backend/test/metabase_enterprise/advanced_config @metabase/core-backend-admin-webapp
|
||||
|
||||
enterprise/backend/src/metabase_enterprise/advanced_permissions @metabase/core-backend-admin-webapp
|
||||
enterprise/backend/test/metabase_enterprise/advanced_permissions @metabase/core-backend-admin-webapp
|
||||
|
||||
enterprise/backend/src/metabase_enterprise/airgap @metabase/core-backend-admin-webapp
|
||||
enterprise/backend/test/metabase_enterprise/airgap @metabase/core-backend-admin-webapp
|
||||
|
||||
enterprise/backend/src/metabase_enterprise/api @metabase/devexp
|
||||
enterprise/backend/test/metabase_enterprise/api @metabase/devexp
|
||||
|
||||
enterprise/backend/src/metabase_enterprise/audit_app @metabase/core-backend-admin-webapp
|
||||
enterprise/backend/test/metabase_enterprise/audit_app @metabase/core-backend-admin-webapp
|
||||
|
||||
enterprise/backend/src/metabase_enterprise/auth_provider @metabase/core-backend-admin-webapp
|
||||
enterprise/backend/test/metabase_enterprise/auth_provider @metabase/core-backend-admin-webapp
|
||||
|
||||
enterprise/backend/src/metabase_enterprise/billing @metabase/core-backend-admin-webapp
|
||||
enterprise/backend/test/metabase_enterprise/billing @metabase/core-backend-admin-webapp
|
||||
|
||||
enterprise/backend/src/metabase_enterprise/cache @metabase/core-backend-admin-webapp
|
||||
enterprise/backend/test/metabase_enterprise/cache @metabase/core-backend-admin-webapp
|
||||
|
||||
enterprise/backend/src/metabase_enterprise/content_verification @metabase/core-backend-admin-webapp
|
||||
enterprise/backend/test/metabase_enterprise/content_verification @metabase/core-backend-admin-webapp
|
||||
|
||||
enterprise/backend/src/metabase_enterprise/core @metabase/devexp
|
||||
enterprise/backend/test/metabase_enterprise/core @metabase/devexp
|
||||
|
||||
enterprise/backend/src/metabase_enterprise/dashboard_subscription_filters @metabase/core-workflows
|
||||
enterprise/backend/test/metabase_enterprise/dashboard_subscription_filters @metabase/core-workflows
|
||||
|
||||
enterprise/backend/src/metabase_enterprise/enhancements @metabase/core-backend-admin-webapp
|
||||
enterprise/backend/test/metabase_enterprise/enhancements @metabase/core-backend-admin-webapp
|
||||
|
||||
# enterprise/backend/src/metabase_enterprise/llm
|
||||
# enterprise/backend/test/metabase_enterprise/llm
|
||||
|
||||
enterprise/backend/src/metabase_enterprise/query_reference_validation @metabase/core-backend-admin-webapp
|
||||
enterprise/backend/test/metabase_enterprise/query_reference_validation @metabase/core-backend-admin-webapp
|
||||
|
||||
enterprise/backend/src/metabase_enterprise/sandbox @metabase/core-backend-admin-webapp
|
||||
enterprise/backend/test/metabase_enterprise/sandbox @metabase/core-backend-admin-webapp
|
||||
|
||||
enterprise/backend/src/metabase_enterprise/scim @metabase/core-backend-admin-webapp
|
||||
enterprise/backend/test/metabase_enterprise/scim @metabase/core-backend-admin-webapp
|
||||
|
||||
enterprise/backend/src/metabase_enterprise/search @metabase/core-workflows
|
||||
enterprise/backend/test/metabase_enterprise/search @metabase/core-workflows
|
||||
|
||||
enterprise/backend/src/metabase_enterprise/serialization @metabase/core-workflows
|
||||
enterprise/backend/test/metabase_enterprise/serialization @metabase/core-workflows
|
||||
|
||||
enterprise/backend/src/metabase_enterprise/snippet_collections @metabase/core-backend-admin-webapp
|
||||
enterprise/backend/test/metabase_enterprise/snippet_collections @metabase/core-backend-admin-webapp
|
||||
|
||||
enterprise/backend/src/metabase_enterprise/sso @metabase/core-backend-admin-webapp
|
||||
enterprise/backend/test/metabase_enterprise/sso @metabase/core-backend-admin-webapp
|
||||
|
||||
enterprise/backend/src/metabase_enterprise/stale @metabase/core-backend-admin-webapp
|
||||
enterprise/backend/test/metabase_enterprise/stale @metabase/core-backend-admin-webapp
|
||||
|
||||
enterprise/backend/src/metabase_enterprise/stats @metabase/core-backend-admin-webapp
|
||||
enterprise/backend/test/metabase_enterprise/stats @metabase/core-backend-admin-webapp
|
||||
|
||||
enterprise/backend/src/metabase_enterprise/task @metabase/core-backend-admin-webapp
|
||||
enterprise/backend/test/metabase_enterprise/task @metabase/core-backend-admin-webapp
|
||||
|
||||
enterprise/backend/src/metabase_enterprise/upload_management @metabase/core-backend-admin-webapp
|
||||
enterprise/backend/test/metabase_enterprise/upload_management @metabase/core-backend-admin-webapp
|
||||
|
||||
src/metabase/actions @metabase/core-backend-admin-webapp
|
||||
test/metabase/actions @metabase/core-backend-admin-webapp
|
||||
|
||||
src/metabase/activity_feed @metabase/core-backend-admin-webapp
|
||||
test/metabase/activity_feed @metabase/core-backend-admin-webapp
|
||||
|
||||
src/metabase/analytics @metabase/core-backend-admin-webapp
|
||||
test/metabase/analytics @metabase/core-backend-admin-webapp
|
||||
|
||||
src/metabase/analyze @metabase/drivers
|
||||
test/metabase/analyze @metabase/drivers
|
||||
|
||||
src/metabase/api @metabase/devexp
|
||||
test/metabase/api @metabase/devexp
|
||||
|
||||
src/metabase/audit @metabase/core-backend-admin-webapp
|
||||
test/metabase/audit @metabase/core-backend-admin-webapp
|
||||
|
||||
src/metabase/auth_provider @metabase/core-backend-admin-webapp
|
||||
test/metabase/auth_provider @metabase/core-backend-admin-webapp
|
||||
|
||||
src/metabase/bookmarks @metabase/core-backend-admin-webapp
|
||||
test/metabase/bookmarks @metabase/core-backend-admin-webapp
|
||||
|
||||
src/metabase/cmd @metabase/devexp
|
||||
test/metabase/cmd @metabase/devexp
|
||||
|
||||
src/metabase/channel @metabase/core-workflows
|
||||
test/metabase/channel @metabase/core-workflows
|
||||
|
||||
src/metabase/cloud_migration @metabase/core-workflows
|
||||
test/metabase/cloud_migration @metabase/core-workflows
|
||||
|
||||
src/metabase/cmd @metabase/devexp
|
||||
test/metabase/cmd @metabase/devexp
|
||||
|
||||
src/metabase/config @metabase/devexp
|
||||
test/metabase/config @metabase/devexp
|
||||
|
||||
src/metabase/core @metabase/devexp
|
||||
test/metabase/core @metabase/devexp
|
||||
|
||||
src/metabase/db @metabase/core-backend-admin-webapp
|
||||
test/metabase/db @metabase/core-backend-admin-webapp
|
||||
|
||||
src/metabase/driver @metabase/drivers
|
||||
test/metabase/driver @metabase/drivers
|
||||
|
||||
src/metabase/eid_translation @metabase/core-backend-admin-webapp
|
||||
test/metabase/eid_translation @metabase/core-backend-admin-webapp
|
||||
|
||||
src/metabase/embed @metabase/embedding
|
||||
test/metabase/embed @metabase/embedding
|
||||
|
||||
src/metabase/events @metabase/devexp
|
||||
test/metabase/events @metabase/devexp
|
||||
|
||||
src/metabase/formatter @metabase/core-backend-querying
|
||||
test/metabase/formatter @metabase/core-backend-querying
|
||||
|
||||
src/metabase/indexed_entities @metabase/core-backend-querying
|
||||
test/metabase/indexed_entities @metabase/core-backend-querying
|
||||
|
||||
src/metabase/integrations @metabase/core-workflows
|
||||
test/metabase/integrations @metabase/core-workflows
|
||||
|
||||
src/metabase/legacy_mbql @metabase/core-backend-querying
|
||||
test/metabase/legacy_mbql @metabase/core-backend-querying
|
||||
|
||||
src/metabase/lib @metabase/core-backend-querying
|
||||
test/metabase/lib @metabase/core-backend-querying
|
||||
|
||||
src/metabase/logger @metabase/devexp
|
||||
test/metabase/logger @metabase/devexp
|
||||
|
||||
src/metabase/login_history @metabase/core-backend-admin-webapp
|
||||
test/metabase/login_history @metabase/core-backend-admin-webapp
|
||||
|
||||
src/metabase/model_persistence @metabase/core-backend-querying
|
||||
test/metabase/model_persistence @metabase/core-backend-querying
|
||||
|
||||
src/metabase/models @metabase/devexp
|
||||
test/metabase/models @metabase/devexp
|
||||
|
||||
src/metabase/moderation @metabase/core-backend-admin-webapp
|
||||
test/metabase/moderation @metabase/core-backend-admin-webapp
|
||||
|
||||
src/metabase/notification @metabase/core-workflows
|
||||
test/metabase/notification @metabase/core-workflows
|
||||
|
||||
src/metabase/permissions @metabase/core-backend-admin-webapp
|
||||
test/metabase/permissions @metabase/core-backend-admin-webapp
|
||||
|
||||
src/metabase/plugins @metabase/devexp
|
||||
test/metabase/plugins @metabase/devexp
|
||||
|
||||
src/metabase/premium_features @metabase/core-backend-admin-webapp
|
||||
test/metabase/premium_features @metabase/core-backend-admin-webapp
|
||||
|
||||
src/metabase/public_settings @metabase/core-backend-admin-webapp
|
||||
test/metabase/public_settings @metabase/core-backend-admin-webapp
|
||||
|
||||
src/metabase/public_sharing @metabase/core-backend-admin-webapp
|
||||
test/metabase/public_sharing @metabase/core-backend-admin-webapp
|
||||
|
||||
src/metabase/pulse @metabase/core-workflows
|
||||
test/metabase/pulse @metabase/core-workflows
|
||||
|
||||
src/metabase/query_analysis @metabase/core-backend-querying
|
||||
test/metabase/query_analysis @metabase/core-backend-querying
|
||||
|
||||
src/metabase/query_processor @metabase/core-backend-querying
|
||||
test/metabase/query_processor @metabase/core-backend-querying
|
||||
|
||||
src/metabase/request @metabase/devexp
|
||||
test/metabase/request @metabase/devexp
|
||||
|
||||
src/metabase/revisions @metabase/core-backend-admin-webapp
|
||||
test/metabase/revisions @metabase/core-backend-admin-webapp
|
||||
|
||||
src/metabase/sample_data @metabase/core-backend-admin-webapp
|
||||
test/metabase/sample_data @metabase/core-backend-admin-webapp
|
||||
|
||||
src/metabase/search @metabase/core-workflows
|
||||
test/metabase/search @metabase/core-workflows
|
||||
|
||||
src/metabase/segments @metabase/core-backend-querying
|
||||
test/metabase/segments @metabase/core-backend-querying
|
||||
|
||||
src/metabase/server @metabase/devexp
|
||||
test/metabase/server @metabase/devexp
|
||||
|
||||
src/metabase/session @metabase/core-backend-admin-webapp
|
||||
test/metabase/session @metabase/core-backend-admin-webapp
|
||||
|
||||
src/metabase/setup @metabase/core-backend-admin-webapp
|
||||
test/metabase/setup @metabase/core-backend-admin-webapp
|
||||
|
||||
src/metabase/sso @metabase/core-backend-admin-webapp
|
||||
test/metabase/sso @metabase/core-backend-admin-webapp
|
||||
|
||||
src/metabase/sync @metabase/drivers
|
||||
test/metabase/sync @metabase/drivers
|
||||
|
||||
src/metabase/task @metabase/devexp
|
||||
test/metabase/task @metabase/devexp
|
||||
|
||||
src/metabase/tiles @metabase/core-backend-dashviz
|
||||
test/metabase/tiles @metabase/core-backend-dashviz
|
||||
|
||||
src/metabase/timeline @metabase/core-backend-dashviz
|
||||
test/metabase/timeline @metabase/core-backend-dashviz
|
||||
|
||||
src/metabase/types @metabase/core-backend-querying
|
||||
test/metabase/types @metabase/core-backend-querying
|
||||
|
||||
src/metabase/upload @metabase/core-backend-admin-webapp
|
||||
test/metabase/upload @metabase/core-backend-admin-webapp
|
||||
|
||||
src/metabase/user_key_value @metabase/core-backend-admin-webapp
|
||||
test/metabase/user_key_value @metabase/core-backend-admin-webapp
|
||||
|
||||
src/metabase/util @metabase/devexp
|
||||
test/metabase/util @metabase/devexp
|
||||
|
||||
src/metabase/xrays @metabase/core-backend-querying
|
||||
test/metabase/xrays @metabase/core-backend-querying
|
||||
|
||||
@@ -5,7 +5,7 @@ PENDING CI / PENDING REVIEW / READY _(choose one and update accordingly)_
|
||||
- Reproduces #XXXXX
|
||||
|
||||
### How to test this manually?
|
||||
- `yarn test-cypress-open`
|
||||
- `yarn test-cypress`
|
||||
- `relative/path/to/the/file`
|
||||
> _(For still unfixed bug)_
|
||||
- Replace `it.skip()` with `it.only()` to run the test in isolation
|
||||
|
||||
20
.github/actions/build-ee-extra/action.yml
vendored
@@ -4,9 +4,7 @@ description: Build Metabase Enterprise Edition with extra features
|
||||
inputs:
|
||||
java-version:
|
||||
required: true
|
||||
# build with Java 11 since that's still officially what we target as a minimum and we don't want Java >11 bytecode
|
||||
# sneaking in.
|
||||
default: 11
|
||||
default: 21
|
||||
iam-role:
|
||||
description: "The IAM role to assume"
|
||||
required: true
|
||||
@@ -32,7 +30,7 @@ runs:
|
||||
shell: bash
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: lts/Hydrogen # 18.x.x
|
||||
node-version: lts/Jod # 22.x.x
|
||||
- run: rm package.json && npm install yaml
|
||||
shell: bash
|
||||
- name: parse drivers registry
|
||||
@@ -66,10 +64,7 @@ runs:
|
||||
const extraDrivers = {
|
||||
firebolt: getDriverUrl('firebolt'),
|
||||
starburst: getDriverUrl('starburst'),
|
||||
exasol: getDriverUrl('exasol'),
|
||||
exasol_jdbc: drivers.find(d => d.name === 'exasol').deps[0],
|
||||
clickhouse: getDriverUrl('clickhouse'),
|
||||
ocient: getDriverUrl('ocient'),
|
||||
materialize: getDriverUrl('materialize'),
|
||||
};
|
||||
|
||||
@@ -86,22 +81,11 @@ runs:
|
||||
curl -OL ${{ fromJson(steps.drivers_registry.outputs.result).starburst }}
|
||||
shell: bash
|
||||
working-directory: modules
|
||||
- name: Download Exasol driver
|
||||
run: |
|
||||
curl -OL ${{ fromJson(steps.drivers_registry.outputs.result).exasol }}
|
||||
curl -OL ${{ fromJson(steps.drivers_registry.outputs.result).exasol_jdbc }}
|
||||
shell: bash
|
||||
working-directory: modules
|
||||
- name: Download Clickhouse driver
|
||||
run: |
|
||||
curl -OL ${{ fromJson(steps.drivers_registry.outputs.result).clickhouse }}
|
||||
shell: bash
|
||||
working-directory: modules
|
||||
- name: Download Ocient driver
|
||||
run: |
|
||||
curl -OL ${{ fromJson(steps.drivers_registry.outputs.result).ocient }}
|
||||
shell: bash
|
||||
working-directory: modules
|
||||
- name: Download Materialize driver
|
||||
run: |
|
||||
curl -OL ${{ fromJson(steps.drivers_registry.outputs.result).materialize }}
|
||||
|
||||
101
.github/actions/create-backport/action.yml
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
name: Create Backport PR
|
||||
|
||||
inputs:
|
||||
target-version: # major version number like 34 or 86
|
||||
required: true
|
||||
backport-commit:
|
||||
required: true
|
||||
github-token:
|
||||
required: true
|
||||
github-token-2: # need a second token to approve the PR
|
||||
required: true
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- id: create_backport_pull_request
|
||||
name: Create backport pull request
|
||||
env:
|
||||
TARGET_VERSION: ${{ inputs.target-version }}
|
||||
TARGET_BRANCH: release-x.${{ inputs.target-version }}.x
|
||||
ORIGINAL_PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }}
|
||||
ORIGINAL_TITLE: ${{ github.event.pull_request.title }}
|
||||
GITHUB_TOKEN: ${{ inputs.github-token }}
|
||||
COMMIT: ${{ inputs.backport-commit }}
|
||||
shell: bash
|
||||
run: |
|
||||
git config --global user.email "metabase-bot@metabase.com"
|
||||
git config --global user.name "Metabase bot"
|
||||
|
||||
BACKPORT_BRANCH="backport-$TARGET_VERSION-$COMMIT"
|
||||
|
||||
# Checkout the target branch and create a new backport branch
|
||||
git checkout ${TARGET_BRANCH}
|
||||
git fetch --all
|
||||
git checkout -b ${BACKPORT_BRANCH}
|
||||
git cherry-pick ${COMMIT} || true
|
||||
|
||||
CONFLICTS=$(git ls-files -u | wc -l)
|
||||
if [ "$CONFLICTS" -gt 0 ]; then
|
||||
git cherry-pick --abort
|
||||
|
||||
echo "Could not cherry pick because of a conflict"
|
||||
echo "has-conflicts=true" >> $GITHUB_OUTPUT
|
||||
|
||||
# Add a shell script for resolving conflicts
|
||||
echo "git reset HEAD~1" > ./backport.sh
|
||||
echo "rm ./backport.sh" >> ./backport.sh
|
||||
echo "git cherry-pick ${COMMIT}" >> ./backport.sh
|
||||
echo "echo 'Resolve conflicts and force push this branch'" >> ./backport.sh
|
||||
chmod +x ./backport.sh
|
||||
git add ./backport.sh
|
||||
git commit -m "Add backport resolution script"
|
||||
|
||||
PR_BODY=$(cat <<-END
|
||||
#${ORIGINAL_PULL_REQUEST_NUMBER}
|
||||
> [!IMPORTANT]
|
||||
> Manual conflict resolution is required.
|
||||
Checkout the branch and run \`./backport.sh\` script. Force push your changes after cherry-picking.
|
||||
END
|
||||
)
|
||||
else
|
||||
echo "has-conflicts=false" >> $GITHUB_OUTPUT
|
||||
PR_BODY="#${ORIGINAL_PULL_REQUEST_NUMBER}"
|
||||
fi
|
||||
|
||||
git push -u origin ${BACKPORT_BRANCH}
|
||||
|
||||
BACKPORT_PR_URL=$(gh pr create --base "${TARGET_BRANCH}" --head "${BACKPORT_BRANCH}" --label "was-backported" --assignee "${GITHUB_ACTOR}" --title "🤖 backported \"${ORIGINAL_TITLE}\"" --body "${PR_BODY}")
|
||||
BACKPORT_PR_NUMBER=${BACKPORT_PR_URL##*/}
|
||||
|
||||
echo "backport_pr_number=$BACKPORT_PR_NUMBER" >> $GITHUB_OUTPUT
|
||||
echo "New PR has been created: #${BACKPORT_PR_NUMBER}"
|
||||
|
||||
git checkout ${{ github.sha }}
|
||||
|
||||
- name: Auto approve backport PR
|
||||
if: ${{ steps.create_backport_pull_request.outputs.has-conflicts == 'false' }}
|
||||
uses: juliangruber/approve-pull-request-action@v1
|
||||
with:
|
||||
github-token: ${{ inputs.github-token-2 }}
|
||||
number: ${{ steps.create_backport_pull_request.outputs.backport_pr_number }}
|
||||
|
||||
- name: Enable Pull Request Automerge
|
||||
if: ${{ steps.create_backport_pull_request.outputs.has-conflicts == 'false' }}
|
||||
uses: peter-evans/enable-pull-request-automerge@v2
|
||||
with:
|
||||
token: ${{ inputs.github-token }}
|
||||
pull-request-number: ${{ steps.create_backport_pull_request.outputs.backport_pr_number }}
|
||||
merge-method: squash
|
||||
|
||||
- uses: ./.github/actions/notify-pull-request
|
||||
if: ${{ steps.create_backport_pull_request.outputs.has-conflicts == 'true' }}
|
||||
with:
|
||||
include-log: false
|
||||
message: Manual conflict resolution is required on \#${{ steps.create_backport_pull_request.outputs.backport_pr_number }}
|
||||
|
||||
- uses: ./.github/actions/notify-pull-request
|
||||
if: ${{ failure() }}
|
||||
with:
|
||||
include-log: true
|
||||
message: Something went wrong while creating backport
|
||||
@@ -68,10 +68,3 @@ runs:
|
||||
- name: Unzip Metabase artifact containing an uberjar
|
||||
run: unzip mb.zip
|
||||
shell: bash
|
||||
|
||||
- name: Get the version info
|
||||
run: |
|
||||
jar xf target/uberjar/metabase.jar version.properties
|
||||
cat version.properties
|
||||
mv version.properties resources/
|
||||
shell: bash
|
||||
|
||||
@@ -28,3 +28,5 @@ runs:
|
||||
env:
|
||||
PULL_REQUEST_NUMBER: ${{ inputs.pull-request-number }}
|
||||
BASE_REF: ${{ inputs.base-ref }}
|
||||
- run: git checkout ${{ github.sha }} # return to original commit
|
||||
shell: bash
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
name: Get latest release branch
|
||||
|
||||
outputs:
|
||||
branch-name:
|
||||
value: ${{ steps.get-latest-release-branch.outputs.result }}
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- uses: actions/github-script@v7
|
||||
id: get-latest-release-branch
|
||||
with:
|
||||
result-encoding: string
|
||||
script: |
|
||||
const releaseBranches = await github.rest.git.listMatchingRefs({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
ref: "heads/release-x.",
|
||||
});
|
||||
|
||||
const getVersionFromBranch = branch => {
|
||||
const match = branch.match(/release-x\.(.*?)\.x$/);
|
||||
return match && parseInt(match[1]);
|
||||
};
|
||||
const latestReleaseBranch = releaseBranches.data
|
||||
.filter(branch => getVersionFromBranch(branch.ref) !== null)
|
||||
.reduce(
|
||||
(prev, current) =>
|
||||
getVersionFromBranch(prev.ref) > getVersionFromBranch(current.ref)
|
||||
? prev
|
||||
: current,
|
||||
{ ref: "" },
|
||||
);
|
||||
const latestReleaseBranchName = latestReleaseBranch.ref.replace(
|
||||
/^refs\/heads\//,
|
||||
"",
|
||||
);
|
||||
|
||||
console.log(`Latest release branch: ${latestReleaseBranchName}`);
|
||||
|
||||
return latestReleaseBranchName;
|
||||
13
.github/actions/notify-pull-request/action.yml
vendored
@@ -10,10 +10,17 @@ runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- uses: actions/github-script@v7
|
||||
id: get-latest-release-branch
|
||||
id: notify-pull-request
|
||||
with:
|
||||
result-encoding: string
|
||||
script: |
|
||||
script: | # js
|
||||
const pr = context.payload.pull_request ?? context.payload.issue;
|
||||
|
||||
if (!pr) {
|
||||
console.error("This action can only be run on pull requests");
|
||||
return;
|
||||
}
|
||||
|
||||
const message = "${{ inputs.message }}"
|
||||
const shouldIncludeLog = ${{ inputs.include-log }}.toString() === "true";
|
||||
const author = context.payload.sender.login;
|
||||
@@ -27,7 +34,7 @@ runs:
|
||||
}
|
||||
|
||||
github.rest.issues.createComment({
|
||||
issue_number: context.payload.issue.number,
|
||||
issue_number: pr.number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
body,
|
||||
|
||||
13
.github/actions/prepare-frontend/action.yml
vendored
@@ -33,18 +33,5 @@ runs:
|
||||
path: node_modules
|
||||
key: ${{ runner.os }}-node-modules-${{ hashFiles('**/yarn.lock', '**/patches/*.patch') }}
|
||||
|
||||
- name: Get yarn cache directory path
|
||||
id: yarn-cache-dir-path
|
||||
if: steps.node-modules-cache.outputs.cache-hit != 'true'
|
||||
run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT
|
||||
shell: bash
|
||||
|
||||
- uses: actions/cache@v4
|
||||
if: steps.node-modules-cache.outputs.cache-hit != 'true'
|
||||
with:
|
||||
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
||||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
||||
restore-keys: ${{ runner.os }}-yarn-
|
||||
|
||||
- run: yarn install --frozen-lockfile --prefer-offline
|
||||
shell: bash
|
||||
|
||||
4
.github/file-paths.yaml
vendored
@@ -5,6 +5,7 @@ default: &default
|
||||
shared_sources: &shared_sources
|
||||
- "src/**/*.cljc"
|
||||
- "src/**/*.cljs"
|
||||
- "package.json"
|
||||
|
||||
shared_specs: &shared_specs
|
||||
- "test/**/*.cljc"
|
||||
@@ -93,14 +94,13 @@ sources: &sources
|
||||
- *backend_sources
|
||||
|
||||
e2e_ci: &e2e_ci
|
||||
- ".github/actions/build-e2e-matrix/**"
|
||||
- ".github/actions/prepare-frontend/**"
|
||||
- ".github/actions/prepare-backend/**"
|
||||
- ".github/actions/prepare-uberjar-artifact/**"
|
||||
- ".github/actions/e2e-prepare-containers/**"
|
||||
- ".github/actions/prepare-cypress/**"
|
||||
- ".github/actions/run-snowplow-micro/**"
|
||||
- ".github/workflows/e2e-tests.yml"
|
||||
- ".github/workflows/e2e-*"
|
||||
|
||||
e2e_specs: &e2e_specs
|
||||
- "**/*.cy.*.js"
|
||||
|
||||
16
.github/scripts/handle-mochawesome-report.js
vendored
@@ -1,4 +1,5 @@
|
||||
const fs = require("fs");
|
||||
const { merge } = require("mochawesome-merge");
|
||||
|
||||
const logger = { debug: console.debug, error: console.error };
|
||||
|
||||
@@ -50,15 +51,16 @@ const extractTestResultsInfo = ({ results, stats }) => {
|
||||
};
|
||||
};
|
||||
|
||||
function parseReport() {
|
||||
const content = fs.readFileSync(
|
||||
"./cypress/reports/cypress-test-report.json",
|
||||
"utf-8",
|
||||
);
|
||||
async function generateReport() {
|
||||
const files = ["./cypress/reports/mochareports/*.json"];
|
||||
|
||||
const data = JSON.parse(content);
|
||||
return await merge({ files });
|
||||
}
|
||||
|
||||
return extractTestResultsInfo(data).failedTests.map(test => ({
|
||||
exports.generateReport = generateReport;
|
||||
|
||||
function parseReport(report) {
|
||||
return extractTestResultsInfo(report).failedTests.map(test => ({
|
||||
title: test.fullTitle,
|
||||
error: test.err?.message,
|
||||
path: test.path,
|
||||
|
||||
25
.github/team.json
vendored
@@ -13,7 +13,8 @@
|
||||
"lbrdnk",
|
||||
"appleby",
|
||||
"uladzimirdev",
|
||||
"wzimrin"
|
||||
"wzimrin",
|
||||
"ericnormand"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -33,7 +34,8 @@
|
||||
"WiNloSt",
|
||||
"oisincoveney",
|
||||
"npretto",
|
||||
"heypoom"
|
||||
"heypoom",
|
||||
"sanex3339"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -44,21 +46,24 @@
|
||||
"qnkhuat",
|
||||
"piranha",
|
||||
"crisptrutski",
|
||||
"deniskaber"
|
||||
"deniskaber",
|
||||
"wotbrew",
|
||||
"spalt08",
|
||||
"stasgavrylov"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Admin Webapp",
|
||||
"label": ".Team/AdminWebapp",
|
||||
"members": [
|
||||
"noahmoss",
|
||||
"escherize",
|
||||
"npfitz",
|
||||
"johnswanson",
|
||||
"rafpaf",
|
||||
"sloansparger",
|
||||
"iethree",
|
||||
"nvoxland"
|
||||
"nvoxland",
|
||||
"fraserdrops",
|
||||
"edpaget"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -67,15 +72,17 @@
|
||||
"members": [
|
||||
"alxnddr",
|
||||
"kulyk",
|
||||
"adam-james-v",
|
||||
"tsplude"
|
||||
"tsplude",
|
||||
"lorem--ipsum",
|
||||
"noahmoss"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "DevEx",
|
||||
"label": ".Team/DevEx",
|
||||
"members": [
|
||||
"camsaul"
|
||||
"camsaul",
|
||||
"escherize"
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
155
.github/workflows/auto-backport.yml
vendored
@@ -5,8 +5,16 @@ on:
|
||||
|
||||
jobs:
|
||||
create-backport:
|
||||
if: github.event.pull_request.merged == true && (contains(github.event.pull_request.labels.*.name, 'backport') && github.event.action == 'closed' || github.event.label.name == 'backport')
|
||||
runs-on: ubuntu-22.04
|
||||
if: | # the PR must be closed and have a backport label
|
||||
(github.event.pull_request.merged == true || github.event.action == 'closed') && (
|
||||
contains(github.event.pull_request.labels.*.name, 'backport') ||
|
||||
contains(github.event.pull_request.labels.*.name, 'double-backport') ||
|
||||
contains(github.event.pull_request.labels.*.name, 'triple-backport') ||
|
||||
github.event.label.name == 'backport' ||
|
||||
github.event.label.name == 'double-backport' ||
|
||||
github.event.label.name == 'triple-backport'
|
||||
)
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
@@ -19,91 +27,68 @@ jobs:
|
||||
pull-request-number: ${{ github.event.pull_request.number }}
|
||||
base-ref: ${{ github.event.pull_request.base.ref }}
|
||||
|
||||
- uses: ./.github/actions/get-latest-release-branch
|
||||
name: Get latest release branch
|
||||
id: get_latest_release_branch
|
||||
|
||||
- id: create_backport_pull_request
|
||||
name: Create backport pull request
|
||||
run: |
|
||||
git config --global user.email "metabase-bot@metabase.com"
|
||||
git config --global user.name "Metabase bot"
|
||||
|
||||
BACKPORT_BRANCH="backport-$COMMIT"
|
||||
|
||||
# Checkout the target branch and create a new backport branch
|
||||
git checkout ${TARGET_BRANCH}
|
||||
git fetch --all
|
||||
git checkout -b ${BACKPORT_BRANCH}
|
||||
git cherry-pick ${COMMIT} || true
|
||||
|
||||
CONFLICTS=$(git ls-files -u | wc -l)
|
||||
if [ "$CONFLICTS" -gt 0 ]; then
|
||||
git cherry-pick --abort
|
||||
|
||||
echo "Could not cherry pick because of a conflict"
|
||||
echo "has-conflicts=true" >> $GITHUB_OUTPUT
|
||||
|
||||
# Add a shell script for resolving conflicts
|
||||
echo "git reset HEAD~1" > ./backport.sh
|
||||
echo "rm ./backport.sh" >> ./backport.sh
|
||||
echo "git cherry-pick ${COMMIT}" >> ./backport.sh
|
||||
echo "echo 'Resolve conflicts and force push this branch'" >> ./backport.sh
|
||||
chmod +x ./backport.sh
|
||||
git add ./backport.sh
|
||||
git commit -m "Add backport resolution script"
|
||||
|
||||
PR_BODY=$(cat <<-END
|
||||
#${ORIGINAL_PULL_REQUEST_NUMBER}
|
||||
> [!IMPORTANT]
|
||||
> Manual conflict resolution is required.
|
||||
Checkout the branch and run \`./backport.sh\` script. Force push your changes after cherry-picking.
|
||||
END
|
||||
)
|
||||
else
|
||||
echo "has-conflicts=false" >> $GITHUB_OUTPUT
|
||||
PR_BODY="#${ORIGINAL_PULL_REQUEST_NUMBER}"
|
||||
fi
|
||||
|
||||
git push -u origin ${BACKPORT_BRANCH}
|
||||
|
||||
BACKPORT_PR_URL=$(gh pr create --base "${TARGET_BRANCH}" --head "${BACKPORT_BRANCH}" --label "was-backported" --assignee "${GITHUB_ACTOR}" --title "🤖 backported \"${ORIGINAL_TITLE}\"" --body "${PR_BODY}")
|
||||
BACKPORT_PR_NUMBER=${BACKPORT_PR_URL##*/}
|
||||
|
||||
echo "backport_pr_number=$BACKPORT_PR_NUMBER" >> $GITHUB_OUTPUT
|
||||
echo "New PR has been created"
|
||||
|
||||
git checkout master
|
||||
env:
|
||||
TARGET_BRANCH: ${{ steps.get_latest_release_branch.outputs.branch-name }}
|
||||
ORIGINAL_PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }}
|
||||
ORIGINAL_TITLE: ${{ github.event.pull_request.title }}
|
||||
GITHUB_TOKEN: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}
|
||||
COMMIT: ${{ steps.find_commit.outputs.commit }}
|
||||
|
||||
- name: Auto approve backport PR
|
||||
if: ${{ steps.create_backport_pull_request.outputs.has-conflicts == 'false' }}
|
||||
uses: juliangruber/approve-pull-request-action@v1
|
||||
- name: how many backports?
|
||||
id: how-many-backports
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
number: ${{ steps.create_backport_pull_request.outputs.backport_pr_number }}
|
||||
script: | # js
|
||||
const labels = [
|
||||
...${{ toJson(github.event.pull_request.labels) }},
|
||||
{ name:"${{ github.event.label.name }}" }
|
||||
];
|
||||
|
||||
- name: Enable Pull Request Automerge
|
||||
if: ${{ steps.create_backport_pull_request.outputs.has-conflicts == 'false' }}
|
||||
uses: peter-evans/enable-pull-request-automerge@v2
|
||||
with:
|
||||
token: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}
|
||||
pull-request-number: ${{ steps.create_backport_pull_request.outputs.backport_pr_number }}
|
||||
merge-method: squash
|
||||
const backportLabelNames = labels.filter(label => label.name.includes('backport')).map(label => label.name);
|
||||
|
||||
- uses: ./.github/actions/notify-pull-request
|
||||
if: ${{ steps.create_backport_pull_request.outputs.has-conflicts == 'true' }}
|
||||
with:
|
||||
include-log: false
|
||||
message: Manual conflict resolution is required
|
||||
let result = 1;
|
||||
|
||||
- uses: ./.github/actions/notify-pull-request
|
||||
if: ${{ failure() }}
|
||||
if (backportLabelNames.includes("triple-backport")) {
|
||||
result = 3;
|
||||
} else if (backportLabelNames.includes("double-backport")) {
|
||||
result = 2;
|
||||
}
|
||||
|
||||
console.log("backports", result);
|
||||
return result;
|
||||
|
||||
- name: get release versions
|
||||
id: get-latest-release-version
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
include-log: true
|
||||
message: Something went wrong while creating a backport
|
||||
script: | # js
|
||||
const currentVersion = Number(${{ vars.CURRENT_VERSION }});
|
||||
|
||||
const result = {
|
||||
latest: currentVersion,
|
||||
secondLatest: currentVersion - 1,
|
||||
thirdLatest: currentVersion - 2,
|
||||
};
|
||||
|
||||
console.log(result);
|
||||
|
||||
return result;
|
||||
|
||||
- name: Single Backport
|
||||
uses: ./.github/actions/create-backport
|
||||
with:
|
||||
target-version: ${{ fromJson(steps.get-latest-release-version.outputs.result).latest }}
|
||||
backport-commit: ${{ steps.find_commit.outputs.commit }}
|
||||
github-token: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}
|
||||
github-token-2: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Double Backport
|
||||
if: ${{ fromJson(steps.how-many-backports.outputs.result) >= 2 }}
|
||||
uses: ./.github/actions/create-backport
|
||||
with:
|
||||
target-version: ${{ fromJson(steps.get-latest-release-version.outputs.result).secondLatest }}
|
||||
backport-commit: ${{ steps.find_commit.outputs.commit }}
|
||||
github-token: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}
|
||||
github-token-2: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Triple Backport
|
||||
if: ${{ fromJson(steps.how-many-backports.outputs.result) >= 3 }}
|
||||
uses: ./.github/actions/create-backport
|
||||
with:
|
||||
target-version: ${{ fromJson(steps.get-latest-release-version.outputs.result).thirdLatest }}
|
||||
backport-commit: ${{ steps.find_commit.outputs.commit }}
|
||||
github-token: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}
|
||||
github-token-2: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
279
.github/workflows/backend.yml
vendored
@@ -1,72 +1,22 @@
|
||||
name: Backend
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "master"
|
||||
- "release-**"
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, ready_for_review, labeled]
|
||||
workflow_call:
|
||||
inputs:
|
||||
skip:
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref && github.ref || github.run_id }}
|
||||
group: ${{ github.workflow }}-${{ github.head_ref && github.ref || github.run_id }}-backend
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
files-changed:
|
||||
name: Check which files changed
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 5
|
||||
outputs:
|
||||
backend_all: ${{ steps.changes.outputs.backend_all }}
|
||||
frontend_sources: ${{ steps.changes.outputs.frontend_sources }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Test which files changed
|
||||
uses: dorny/paths-filter@v3.0.0
|
||||
id: changes
|
||||
with:
|
||||
token: ${{ github.token }}
|
||||
filters: .github/file-paths.yaml
|
||||
|
||||
static-viz-files-changed:
|
||||
needs: files-changed
|
||||
if: needs.files-changed.outputs.backend_all != 'true' && needs.files-changed.outputs.frontend_sources == 'true'
|
||||
name: Check whether static-viz files changed
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 10
|
||||
outputs:
|
||||
static_viz: ${{ steps.static_viz.outputs.static_viz }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Prepare front-end environment
|
||||
uses: ./.github/actions/prepare-frontend
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: "files-changed"
|
||||
- name: Build static-viz frontend
|
||||
run: yarn build-static-viz
|
||||
- name: Upload Static Viz Bundle Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: static-viz-bundle-${{ github.sha }}
|
||||
path: resources/frontend_client/app/dist
|
||||
|
||||
- name: Check for static viz changes
|
||||
uses: dorny/paths-filter@v3.0.0
|
||||
id: static_viz
|
||||
with:
|
||||
token: ${{ github.token }}
|
||||
filters: .github/static-viz-sources.yaml
|
||||
|
||||
be-linter-clj-kondo:
|
||||
needs: [files-changed, static-viz-files-changed]
|
||||
if: |
|
||||
!cancelled() &&
|
||||
(needs.files-changed.outputs.backend_all == 'true' || needs.static-viz-files-changed.outputs.static_viz == 'true')
|
||||
if: ${{ !inputs.skip }}
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 10
|
||||
name: Clj-Kondo
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Prepare back-end environment
|
||||
@@ -77,13 +27,10 @@ jobs:
|
||||
run: ./bin/kondo.sh
|
||||
|
||||
be-linter-eastwood:
|
||||
needs: [files-changed, static-viz-files-changed]
|
||||
if: |
|
||||
!cancelled() &&
|
||||
github.event.pull_request.draft == false &&
|
||||
(needs.files-changed.outputs.backend_all == 'true' || needs.static-viz-files-changed.outputs.static_viz == 'true')
|
||||
if: ${{ !inputs.skip }}
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 20
|
||||
name: Eastwood
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Prepare back-end environment
|
||||
@@ -93,62 +40,69 @@ jobs:
|
||||
- run: clojure -X:dev:ee:ee-dev:drivers:drivers-dev:test:eastwood
|
||||
name: Run Eastwood linter
|
||||
|
||||
# Because it's not possible to conditionally run only `java-11-ee` test in the draft mode,
|
||||
# we have to extract that job manually here. Backend developers have requested that this
|
||||
# test runs at all times to give them an early warning sign is something is broken.
|
||||
be-tests-java-11-ee-pre-check:
|
||||
needs: [files-changed, static-viz-files-changed]
|
||||
if: |
|
||||
!cancelled() &&
|
||||
github.event.pull_request.draft == true &&
|
||||
(needs.files-changed.outputs.backend_all == 'true' || needs.static-viz-files-changed.outputs.static_viz == 'true')
|
||||
runs-on: ubuntu-22.04
|
||||
name: be-tests-java-11-ee-pre-check
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Prepare front-end environment
|
||||
uses: ./.github/actions/prepare-frontend
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: java-11-ee-pre-check
|
||||
|
||||
- run: yarn install --frozen-lockfile --prefer-offline
|
||||
- name: Build static viz frontend
|
||||
run: yarn build-static-viz
|
||||
|
||||
- name: Run tests
|
||||
run: clojure -X:dev:ci:test:ee:ee-dev
|
||||
|
||||
- name: Publish Test Report (JUnit)
|
||||
uses: dorny/test-reporter@v1
|
||||
if: failure()
|
||||
with:
|
||||
path: "target/junit/**/*_test.xml"
|
||||
name: JUnit Test Report be-tests-java-11-ee-pre-check
|
||||
reporter: java-junit
|
||||
list-suites: failed
|
||||
list-tests: failed
|
||||
fail-on-error: false
|
||||
|
||||
be-tests:
|
||||
needs: [files-changed, static-viz-files-changed]
|
||||
if: |
|
||||
!cancelled() &&
|
||||
github.event.pull_request.draft == false &&
|
||||
(needs.files-changed.outputs.backend_all == 'true' || needs.static-viz-files-changed.outputs.static_viz == 'true')
|
||||
if: ${{ !inputs.skip }}
|
||||
runs-on: ubuntu-22.04
|
||||
name: be-tests-java-${{ matrix.java-version }}-${{ matrix.edition }}
|
||||
timeout-minutes: 60
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
edition: [oss, ee]
|
||||
java-version: [11, 17, 21]
|
||||
java-version: [21]
|
||||
job:
|
||||
- name: Enterprise Tests
|
||||
edition: ee
|
||||
build-static-viz: 'false'
|
||||
test-args: >-
|
||||
:only '"enterprise/backend/test"'
|
||||
- name: EE App DB Tests (Part 1)
|
||||
edition: ee
|
||||
build-static-viz: 'true'
|
||||
test-args: >-
|
||||
:only '["test" ".clj-kondo/test"]'
|
||||
:partition/total 2
|
||||
:partition/index 0
|
||||
- name: EE App DB Tests (Part 2)
|
||||
edition: ee
|
||||
build-static-viz: 'true'
|
||||
test-args: >-
|
||||
:only '["test" ".clj-kondo/test"]'
|
||||
:partition/total 2
|
||||
:partition/index 1
|
||||
- name: OSS App DB Tests (Part 1)
|
||||
edition: oss
|
||||
build-static-viz: 'true'
|
||||
test-args: >-
|
||||
:only '["test" ".clj-kondo/test"]'
|
||||
:partition/total 2
|
||||
:partition/index 0
|
||||
- name: OSS App DB Tests (Part 2)
|
||||
edition: oss
|
||||
build-static-viz: 'true'
|
||||
test-args: >-
|
||||
:only '["test" ".clj-kondo/test"]'
|
||||
:partition/total 2
|
||||
:partition/index 1
|
||||
name: "Java ${{ matrix.java-version }} ${{ matrix.job.name }}"
|
||||
env:
|
||||
# Only run old migrations tests on pushes to master or release branches. All other branches should skip tests
|
||||
# with the tag `mb/old-migrations-test`. `__ADDITIONAL_EXCLUDED_TAG__` is not used anywhere outside of splicing
|
||||
# it in to the command below.
|
||||
__ADDITIONAL_EXCLUDED_TAG__: >-
|
||||
${{
|
||||
(
|
||||
github.event_name == 'push' &&
|
||||
(
|
||||
github.ref == 'master' ||
|
||||
startsWith(github.ref, 'release-')
|
||||
) &&
|
||||
''
|
||||
) ||
|
||||
':mb/old-migrations-test'
|
||||
}}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Prepare front-end environment
|
||||
if: ${{ matrix.job.build-static-viz == 'true' }}
|
||||
uses: ./.github/actions/prepare-frontend
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
@@ -158,25 +112,28 @@ jobs:
|
||||
# Depending on which files changed, we might either have to build static-viz
|
||||
# from scratch or download the previously built artifact
|
||||
- name: Build static-viz frontend
|
||||
if: needs.files-changed.outputs.backend_all == 'true'
|
||||
if: ${{ matrix.job.build-static-viz == 'true' && !inputs.skip }}
|
||||
run: yarn build-static-viz
|
||||
- name: Download Static Viz Bundle Artifact
|
||||
if: needs.static-viz-files-changed.outputs.static_viz == 'true'
|
||||
if: ${{ matrix.job.build-static-viz == 'true' && !inputs.skip }}
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: static-viz-bundle-${{ github.sha }}
|
||||
path: resources/frontend_client/app/dist
|
||||
|
||||
- name: Run tests
|
||||
- name: "Test Java ${{ matrix.java-version }} ${{ matrix.job.name }}"
|
||||
id: run-java-tests
|
||||
run: clojure -X:dev:ci:test:${{ matrix.edition }}:${{ matrix.edition }}-dev
|
||||
run: >-
|
||||
clojure -X:dev:ci:test:${{ matrix.job.edition }}:${{ matrix.job.edition }}-dev
|
||||
:exclude-tags '[:mb/driver-tests ${{ env.__ADDITIONAL_EXCLUDED_TAG__ }}]'
|
||||
${{ matrix.job.test-args }}
|
||||
|
||||
- name: Upload Test Results
|
||||
uses: ./.github/actions/upload-test-results
|
||||
if: always() && (steps.run-java-tests.conclusion != 'skipped' || steps.run-java-tests-21.conclusion != 'skipped')
|
||||
with:
|
||||
input-path: ./target/junit/
|
||||
output-name: be-tests-java-${{ matrix.java-version }}-${{ matrix.edition }}
|
||||
output-name: be-tests-java-${{ matrix.java-version }}-${{ matrix.job.edition }}
|
||||
bucket: ${{ vars.AWS_S3_TEST_RESULTS_BUCKET }}
|
||||
aws-access-key-id: ${{ secrets.AWS_TEST_RESULTS_ACCESS_KEY_ID }}
|
||||
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
|
||||
@@ -188,74 +145,37 @@ jobs:
|
||||
if: failure()
|
||||
with:
|
||||
path: "target/junit/**/*_test.xml"
|
||||
name: JUnit Test Report be-tests-java-${{ matrix.java-version }}-${{ matrix.edition }}
|
||||
name: JUnit Test Report be-tests-java-${{ matrix.java-version }}-${{ matrix.job.edition }}
|
||||
reporter: java-junit
|
||||
list-suites: failed
|
||||
list-tests: failed
|
||||
fail-on-error: false
|
||||
|
||||
be-tests-stub:
|
||||
needs: [files-changed, static-viz-files-changed, be-tests]
|
||||
if: |
|
||||
always() &&
|
||||
github.event.pull_request.draft == false && needs.be-tests.result == 'skipped'
|
||||
runs-on: ubuntu-22.04
|
||||
name: be-tests-java-${{ matrix.java-version }}-${{ matrix.edition }}
|
||||
timeout-minutes: 5
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
edition: [oss, ee]
|
||||
java-version: [11, 17, 21]
|
||||
steps:
|
||||
- run: |
|
||||
echo "Didn't run due to conditional filtering"
|
||||
|
||||
# checks that all the namespaces we actually ship can be compiled, without any dependencies that we don't ship (such
|
||||
# as `:dev` dependencies). See #27009 for more context.
|
||||
be-check:
|
||||
needs: [files-changed, static-viz-files-changed]
|
||||
if: |
|
||||
!cancelled() &&
|
||||
github.event.pull_request.draft == false &&
|
||||
(needs.files-changed.outputs.backend_all == 'true' || needs.static-viz-files-changed.outputs.static_viz == 'true')
|
||||
if: ${{ !inputs.skip }}
|
||||
runs-on: ubuntu-22.04
|
||||
name: be-check-java-${{ matrix.java-version }}
|
||||
timeout-minutes: 10
|
||||
strategy:
|
||||
matrix:
|
||||
java-version: [11, 17, 21]
|
||||
java-version: [21]
|
||||
name: "Check Java ${{ matrix.java-version }}"
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Prepare backend
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: be-check
|
||||
# TODO -- we should probably also check WITHOUT ee -- do a check with only OSS namespaces on the classpath
|
||||
- name: Check namespaces
|
||||
run: clojure -M:ee:drivers:check
|
||||
|
||||
be-check-stub:
|
||||
needs: [files-changed, static-viz-files-changed, be-check]
|
||||
if: |
|
||||
always() &&
|
||||
github.event.pull_request.draft == false &&
|
||||
needs.be-check.result == 'skipped'
|
||||
runs-on: ubuntu-22.04
|
||||
name: be-check-java-${{ matrix.java-version }}
|
||||
timeout-minutes: 10
|
||||
strategy:
|
||||
matrix:
|
||||
java-version: [11, 17, 21]
|
||||
steps:
|
||||
- run: |
|
||||
echo "Didn't run due to conditional filtering"
|
||||
|
||||
be-cljfmt:
|
||||
needs: [files-changed]
|
||||
if: |
|
||||
!cancelled() && needs.files-changed.outputs.backend_all == 'true'
|
||||
if: ${{ !inputs.skip }}
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 10
|
||||
name: Cljfmt
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Prepare back-end environment
|
||||
@@ -264,3 +184,44 @@ jobs:
|
||||
m2-cache-key: 'cljfmt'
|
||||
- name: Run cljfmt
|
||||
run: clojure -T:cljfmt check
|
||||
|
||||
be-tests-result:
|
||||
needs:
|
||||
- be-linter-eastwood
|
||||
- be-linter-clj-kondo
|
||||
- be-cljfmt
|
||||
- be-check
|
||||
- be-tests
|
||||
if: always() && !cancelled()
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
env:
|
||||
needs: ${{ toJson(needs) }}
|
||||
steps:
|
||||
- name: Check backend job status
|
||||
uses: actions/github-script@v7
|
||||
env:
|
||||
needs: ${{ toJson(needs) }}
|
||||
with:
|
||||
script: | # js
|
||||
const needs = JSON.parse(process.env.needs);
|
||||
const jobs = Object.entries(needs).map(
|
||||
([jobName, jobValues]) => ({
|
||||
name: jobName,
|
||||
result: jobValues.result
|
||||
}));
|
||||
|
||||
// are all jobs skipped or successful?
|
||||
if (jobs.every(job => (job.result === 'skipped' || job.result === 'success'))) {
|
||||
console.log('All jobs are skipped or successful');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// otherwise, something failed
|
||||
console.log('Some backend jobs failed');
|
||||
jobs.forEach((job) => {
|
||||
if (job.result !== 'success') {
|
||||
console.log(`${job.name} - ${job.result}`);
|
||||
}
|
||||
});
|
||||
process.exit(1);
|
||||
|
||||
5
.github/workflows/backport-reminder.yml
vendored
@@ -9,10 +9,11 @@ on:
|
||||
jobs:
|
||||
backport-reminder:
|
||||
name: Decide whether to backport or not
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- uses: jesusvasquez333/verify-pr-label-action@v1.4.0
|
||||
with:
|
||||
github-token: '${{ secrets.GITHUB_TOKEN }}'
|
||||
valid-labels: 'backport, no-backport'
|
||||
valid-labels: 'no-backport, backport, double-backport, triple-backport'
|
||||
disable-reviews: true
|
||||
|
||||
238
.github/workflows/backport.yml
vendored
@@ -1,238 +0,0 @@
|
||||
# Cherry-picks commits from current branch to a specified one in a command "@metabase-bot backport release-x.40.x"
|
||||
name: Backport
|
||||
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
|
||||
jobs:
|
||||
check_pull_request_state:
|
||||
name: Checks whether the PR has been merged
|
||||
if: github.event.issue.pull_request && contains(github.event.comment.body, '@metabase-bot backport')
|
||||
runs-on: ubuntu-22.04
|
||||
outputs:
|
||||
canBackport: ${{ steps.check_pull_request_state.outputs.result }}
|
||||
steps:
|
||||
- uses: actions/github-script@v7
|
||||
id: check_pull_request_state
|
||||
with:
|
||||
script: |
|
||||
const { data: pullRequest } = await github.rest.pulls.get({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
pull_number: context.payload.issue.number
|
||||
});
|
||||
|
||||
const canBackport = pullRequest.state === "closed"
|
||||
if (!canBackport) {
|
||||
await github.rest.issues.createComment({
|
||||
issue_number: context.payload.issue.number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
body: "The backport command can only be used after the pull request has been merged. Please wait until the PR is merged before attempting to backport."
|
||||
});
|
||||
}
|
||||
return canBackport
|
||||
|
||||
create_pull_request:
|
||||
name: Creates a pull request
|
||||
needs: [check_pull_request_state]
|
||||
if: needs.check_pull_request_state.outputs.canBackport == 'true'
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
name: Cherry-pick commits and create PR
|
||||
with:
|
||||
fetch-depth: 0
|
||||
token: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}
|
||||
- name: Verify Membership
|
||||
id: verify-membership
|
||||
uses: ./.github/actions/verify-membership
|
||||
with:
|
||||
github_token: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}
|
||||
organization_name: metabase
|
||||
username: ${{ github.event.comment.user.login }}
|
||||
- run: |
|
||||
result=${{ steps.verify-membership.outputs.is_member }}
|
||||
if [ $result == false ]; then
|
||||
echo User ${{ github.event.comment.user.login }} is not a member of Metabase organization
|
||||
exit 1
|
||||
fi
|
||||
- uses: actions/github-script@v7
|
||||
id: branch_info
|
||||
with:
|
||||
script: |
|
||||
await github.rest.reactions.createForIssueComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
comment_id: context.payload.comment.id,
|
||||
content: 'eyes',
|
||||
});
|
||||
|
||||
// Example: @metabase-bot backport release-x.40.x
|
||||
const [_botName, _command, targetBranch] = context.payload.comment.body.split(" ");
|
||||
console.log(`Target branch is ${targetBranch}`);
|
||||
|
||||
const { data: originalPullRequest } = await github.rest.pulls.get({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
pull_number: context.payload.issue.number,
|
||||
});
|
||||
|
||||
const { data: commits } = await github.rest.pulls.listCommits({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
pull_number: context.payload.issue.number,
|
||||
});
|
||||
|
||||
const targetRef = await github.rest.git.getRef({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
ref: `heads/${targetBranch}`,
|
||||
});
|
||||
|
||||
const backportBranch = `backport-${originalPullRequest.head.ref}-${targetBranch}`
|
||||
|
||||
try {
|
||||
await github.rest.git.getRef({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
ref: `heads/${backportBranch}`,
|
||||
});
|
||||
} catch(e) {
|
||||
if (e.status === 404) {
|
||||
await github.rest.git.createRef({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
ref: `refs/heads/${backportBranch}`,
|
||||
sha: targetRef.data.object.sha,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
backportBranch,
|
||||
targetBranch,
|
||||
originalPullRequest,
|
||||
startSha: commits[0].sha,
|
||||
endSha: commits[commits.length - 1].sha
|
||||
}
|
||||
- id: create_backport_pull_request
|
||||
name: Create backport pull request
|
||||
run: |
|
||||
git config --global user.email "metabase-bot@metabase.com"
|
||||
git config --global user.name "Metabase bot"
|
||||
|
||||
git fetch --all
|
||||
|
||||
git checkout "${BACKPORT_BRANCH}"
|
||||
git reset --hard origin/${TARGET_BRANCH}
|
||||
|
||||
if [[ -z $(git ls-remote --heads origin ${ORIGINAL_HEAD_REF}) ]]; then
|
||||
echo "PR has been merged, searching for a squashed commit in the base branch"
|
||||
echo "searching for a commit in a ${ORIGINAL_BASE_REF} that contains pull request number ${ORIGINAL_PULL_REQUEST_NUMBER}"
|
||||
SQUASHED_COMMIT=$(env -i git log ${ORIGINAL_BASE_REF} --grep="(#${ORIGINAL_PULL_REQUEST_NUMBER})" --format="%H")
|
||||
|
||||
if [ -n "${SQUASHED_COMMIT}" ]; then
|
||||
echo "found commit ${SQUASHED_COMMIT}"
|
||||
else
|
||||
echo "probably a PR wasn't merged with Squash And Merge button, searching again"
|
||||
SQUASHED_COMMIT=$(env -i git log ${ORIGINAL_BASE_REF} --grep="#${ORIGINAL_PULL_REQUEST_NUMBER}" --format="%H")
|
||||
|
||||
if [ -n "${SQUASHED_COMMIT}" ]; then
|
||||
echo "found commit ${SQUASHED_COMMIT}"
|
||||
else
|
||||
echo "No squashed commit found for PR #${ORIGINAL_PULL_REQUEST_NUMBER}"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo "The PR has not been merged"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
git cherry-pick ${SQUASHED_COMMIT} || true
|
||||
|
||||
CONFLICTS=$(git ls-files -u | wc -l)
|
||||
if [ "$CONFLICTS" -gt 0 ]; then
|
||||
git cherry-pick --abort
|
||||
|
||||
echo "Could not cherry pick because of a conflict"
|
||||
echo "has-conflicts=true" >> $GITHUB_OUTPUT
|
||||
|
||||
# Add a shell script for resolving conflicts
|
||||
echo "git reset HEAD~1" > ./backport.sh
|
||||
echo "rm ./backport.sh" >> ./backport.sh
|
||||
echo "git cherry-pick ${SQUASHED_COMMIT}" >> ./backport.sh
|
||||
echo "echo 'Resolve conflicts and force push this branch'" >> ./backport.sh
|
||||
chmod +x ./backport.sh
|
||||
git add ./backport.sh
|
||||
git commit -m "Add backport resolution script"
|
||||
|
||||
PR_BODY=$(cat <<-END
|
||||
#${ORIGINAL_PULL_REQUEST_NUMBER}
|
||||
> [!IMPORTANT]
|
||||
> Manual conflict resolution is required.
|
||||
Checkout the branch and run \`./backport.sh\` script. Force push your changes after cherry-picking.
|
||||
END
|
||||
)
|
||||
else
|
||||
echo "has-conflicts=false" >> $GITHUB_OUTPUT
|
||||
PR_BODY="#${ORIGINAL_PULL_REQUEST_NUMBER}"
|
||||
fi
|
||||
|
||||
git push origin "${BACKPORT_BRANCH}" --force-with-lease
|
||||
|
||||
if [[ $(gh pr list --base "${TARGET_BRANCH}" --head "${BACKPORT_BRANCH}" -s "open") ]]; then
|
||||
echo "PR already exists"
|
||||
else
|
||||
BACKPORT_PR_URL=$(gh pr create --base "${TARGET_BRANCH}" --head "${BACKPORT_BRANCH}" --label "was-backported" --assignee "${GITHUB_ACTOR}" --title "🤖 backported \"${ORIGINAL_TITLE}\"" --body "${PR_BODY}")
|
||||
BACKPORT_PR_NUMBER=${BACKPORT_PR_URL##*/}
|
||||
|
||||
echo "backport_pr_number=$BACKPORT_PR_NUMBER" >> $GITHUB_OUTPUT
|
||||
echo "New PR has been created"
|
||||
fi
|
||||
|
||||
git checkout master
|
||||
env:
|
||||
ORIGINAL_TITLE: ${{ fromJson(steps.branch_info.outputs.result).originalPullRequest.title }}
|
||||
ORIGINAL_BASE_REF: ${{ fromJson(steps.branch_info.outputs.result).originalPullRequest.base.ref }}
|
||||
ORIGINAL_BASE_SHA: ${{ fromJson(steps.branch_info.outputs.result).originalPullRequest.base.sha }}
|
||||
ORIGINAL_HEAD_REF: ${{ fromJson(steps.branch_info.outputs.result).originalPullRequest.head.ref }}
|
||||
ORIGINAL_HEAD_SHA: ${{ fromJson(steps.branch_info.outputs.result).originalPullRequest.head.sha }}
|
||||
ORIGINAL_PULL_REQUEST_NUMBER: ${{ fromJson(steps.branch_info.outputs.result).originalPullRequest.number }}
|
||||
TARGET_BRANCH: ${{ fromJson(steps.branch_info.outputs.result).targetBranch }}
|
||||
BACKPORT_BRANCH: ${{ fromJson(steps.branch_info.outputs.result).backportBranch }}
|
||||
START_SHA: ${{ fromJson(steps.branch_info.outputs.result).startSha }}
|
||||
END_SHA: ${{ fromJson(steps.branch_info.outputs.result).endSha }}
|
||||
GITHUB_TOKEN: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}
|
||||
- name: Auto approve backport PR
|
||||
if: ${{ steps.create_backport_pull_request.outputs.has-conflicts == 'false' }}
|
||||
uses: juliangruber/approve-pull-request-action@v1
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
number: ${{ steps.create_backport_pull_request.outputs.backport_pr_number }}
|
||||
- name: Enable Pull Request Automerge
|
||||
if: ${{ steps.create_backport_pull_request.outputs.has-conflicts == 'false' }}
|
||||
uses: peter-evans/enable-pull-request-automerge@v2
|
||||
with:
|
||||
token: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}
|
||||
pull-request-number: ${{ steps.create_backport_pull_request.outputs.backport_pr_number }}
|
||||
merge-method: squash
|
||||
- uses: ./.github/actions/notify-pull-request
|
||||
if: ${{ steps.create_backport_pull_request.outputs.has-conflicts == 'true' }}
|
||||
with:
|
||||
include-log: false
|
||||
message: Manual conflict resolution is required
|
||||
|
||||
notify_when_failed:
|
||||
runs-on: ubuntu-22.04
|
||||
name: Notify about failure
|
||||
needs: create_pull_request
|
||||
if: ${{ failure() }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ./.github/actions/notify-pull-request
|
||||
with:
|
||||
include-log: true
|
||||
message: something went wrong while creating a backport
|
||||
2
.github/workflows/chromatic.yml
vendored
@@ -43,6 +43,8 @@ jobs:
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: "cljs"
|
||||
- name: Compile CLJS
|
||||
run: NODE_ENV=development yarn build-pure:cljs
|
||||
- name: Publish to Chromatic
|
||||
uses: chromaui/action@v10.2.0
|
||||
env:
|
||||
|
||||
22
.github/workflows/codenotify.yml
vendored
@@ -1,22 +0,0 @@
|
||||
name: Codenotify
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize, ready_for_review]
|
||||
# We're currently notifying developers only for frontend source changes.
|
||||
# Update this glob if that ever changes and we start including backend source code changes.
|
||||
paths:
|
||||
- 'frontend/src/metabase/**'
|
||||
- 'enterprise/frontend/src/metabase-enterprise/**'
|
||||
|
||||
jobs:
|
||||
codenotify:
|
||||
runs-on: ubuntu-22.04
|
||||
name: Codenotify
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
- uses: sourcegraph/codenotify@v0.6.4
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
697
.github/workflows/drivers.yml
vendored
47
.github/workflows/drivers_summary.yml
vendored
@@ -1,47 +0,0 @@
|
||||
name: Driver Tests (Summary)
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: [Driver Tests]
|
||||
types:
|
||||
- completed
|
||||
|
||||
jobs:
|
||||
#
|
||||
# Moving forward we should be able to make just the single 'be-drivers' job be required, as opposed to all the
|
||||
# different jobs in `drivers.yml` (maybe).
|
||||
#
|
||||
driver-tests:
|
||||
runs-on: ubuntu-22.04
|
||||
name: Wait for all driver tests to pass
|
||||
steps:
|
||||
- if: ${{ github.event.workflow_run.conclusion == 'success' }}
|
||||
run: |
|
||||
echo ""
|
||||
echo " _------. "
|
||||
echo " / , \_ "
|
||||
echo " / / /{}\ |o\_ "
|
||||
echo " / \ `--' /-' \ "
|
||||
echo " | \ \ | "
|
||||
echo " | |`-, | "
|
||||
echo " / /__/)/ "
|
||||
echo " | | "
|
||||
echo ""
|
||||
echo "All driver tests have passed (or have been skipped). Cam is very proud of you."
|
||||
- if: ${{ github.event.workflow_run.conclusion == 'failure' }}
|
||||
run: |
|
||||
echo ""
|
||||
echo " .::::::::::. .::::::::::. "
|
||||
echo " .::::''''''::::. .::::''''''::::. "
|
||||
echo " .:::' `::::.... ....::::' `:::. "
|
||||
echo " .::' `:::::::| |:::::::' `::. "
|
||||
echo " .::| |::::::|_ ___ __|::::::| |::. "
|
||||
echo " `--' |::::::|_()__()_|::::::| `--' "
|
||||
echo " ::: |::-o::| |::o-::| ::: "
|
||||
echo " `::. .|::::::| |::::::|. .::' "
|
||||
echo " `:::. .::\-----' `-----/::. .:::' "
|
||||
echo " `::::......::::' `::::......::::' "
|
||||
echo " `::::::::::' `::::::::::' "
|
||||
echo ""
|
||||
echo "Driver tests have failed. You have been sentenced to MetaJail."
|
||||
exit 1
|
||||
@@ -165,8 +165,9 @@ jobs:
|
||||
|
||||
- name: Move tests from the release commit into the repo
|
||||
run: |
|
||||
rm -rf ./e2e/support/helpers/*
|
||||
mv ./sdk-release-e2e/e2e/support/helpers/* ./e2e/support/helpers
|
||||
rm -rf ./e2e/support/*
|
||||
mv ./sdk-release-e2e/e2e/support/* ./e2e/support
|
||||
|
||||
rm -rf ./e2e/test-component/*
|
||||
mv ./sdk-release-e2e/e2e/test-component/* ./e2e/test-component
|
||||
shell: bash
|
||||
@@ -176,11 +177,6 @@ jobs:
|
||||
with:
|
||||
name: metabase-ee-${{ github.event.pull_request.head.sha || github.sha }}-uberjar
|
||||
|
||||
- name: Get the version info
|
||||
run: |
|
||||
jar xf target/uberjar/metabase.jar version.properties
|
||||
mv version.properties resources/
|
||||
|
||||
- name: Prepare front-end environment
|
||||
uses: ./.github/actions/prepare-frontend
|
||||
|
||||
@@ -197,8 +193,14 @@ jobs:
|
||||
- name: Install Embedding SDK package v${{ needs.resolve-sdk-version.outputs.sdk_version }}
|
||||
run: yarn add @metabase/embedding-sdk-react@${{ needs.resolve-sdk-version.outputs.sdk_version }}
|
||||
|
||||
- name: Run E2E tests for Embedding SDK
|
||||
run: yarn run test-cypress-run-component-sdk --browser ${{ steps.cypress-prep.outputs.chrome-path }}
|
||||
- name: Run Metabase
|
||||
run: node e2e/runner/run_cypress_ci.js start
|
||||
|
||||
- name: Make app db snapshot
|
||||
run: node e2e/runner/run_cypress_ci.js snapshot --browser ${{ steps.cypress-prep.outputs.chrome-path }}
|
||||
|
||||
- name: Run component tests for Embedding SDK
|
||||
run: node e2e/runner/run_cypress_ci.js component --browser ${{ steps.cypress-prep.outputs.chrome-path }}
|
||||
|
||||
- name: Upload Test Results
|
||||
uses: ./.github/actions/upload-test-results
|
||||
@@ -228,12 +230,14 @@ jobs:
|
||||
with:
|
||||
script: | #js
|
||||
const {
|
||||
generateReport,
|
||||
parseReport,
|
||||
formatSummary
|
||||
} = require("./.github/scripts/handle-mochawesome-report.js");
|
||||
|
||||
const report = parseReport();
|
||||
const summary = formatSummary(report);
|
||||
const report = await generateReport();
|
||||
const results = parseReport(report);
|
||||
const summary = formatSummary(results);
|
||||
|
||||
await core.summary.addRaw(summary).write();
|
||||
|
||||
|
||||
@@ -86,7 +86,7 @@ jobs:
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: uberjar
|
||||
java-version: "${{ needs.get-build-requirements.outputs.java_version || 11 }}"
|
||||
java-version: "${{ needs.get-build-requirements.outputs.java_version || 21 }}"
|
||||
|
||||
- name: Build uberjar with ./bin/build.sh
|
||||
run: ./bin/build.sh
|
||||
@@ -111,6 +111,7 @@ jobs:
|
||||
CYPRESS_ALL_FEATURES_TOKEN: ${{ secrets.ENTERPRISE_TOKEN }}
|
||||
CYPRESS_NO_FEATURES_TOKEN: ${{ secrets.E2E_STARTER_TOKEN }}
|
||||
CYPRESS_PULL_REQUEST_ID: ${{ github.event.pull_request.number || '' }}
|
||||
CYPRESS_IS_EMBEDDING_SDK: true
|
||||
COMMIT_INFO_MESSAGE: ${{ github.event.pull_request.title || github.event.head_commit.message || github.event.head.sha }}
|
||||
TZ: US/Pacific # to make node match the instance tz
|
||||
CYPRESS_CI: true
|
||||
@@ -129,18 +130,13 @@ jobs:
|
||||
with:
|
||||
name: metabase-ee-${{ github.event.pull_request.head.sha || github.sha }}-uberjar
|
||||
|
||||
- name: Get the version info
|
||||
run: |
|
||||
jar xf target/uberjar/metabase.jar version.properties
|
||||
mv version.properties resources/
|
||||
|
||||
- name: Prepare front-end environment
|
||||
uses: ./.github/actions/prepare-frontend
|
||||
|
||||
- name: Prepare JDK ${{ needs.get-build-requirements.outputs.java_version || 11 }}
|
||||
- name: Prepare JDK ${{ needs.get-build-requirements.outputs.java_version || 21 }}
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: ${{ needs.get-build-requirements.outputs.java_version || 11 }}
|
||||
java-version: ${{ needs.get-build-requirements.outputs.java_version || 21 }}
|
||||
distribution: "temurin"
|
||||
|
||||
- name: Prepare Cypress environment
|
||||
@@ -159,8 +155,14 @@ jobs:
|
||||
- name: Build Embedding SDK package
|
||||
run: yarn build-embedding-sdk
|
||||
|
||||
- name: Run E2E tests for Embedding SDK
|
||||
run: yarn run test-cypress-run-component-sdk --browser ${{ steps.cypress-prep.outputs.chrome-path }}
|
||||
- name: Run Metabase
|
||||
run: node e2e/runner/run_cypress_ci.js start
|
||||
|
||||
- name: Make app db snapshot
|
||||
run: node e2e/runner/run_cypress_ci.js snapshot --browser ${{ steps.cypress-prep.outputs.chrome-path }}
|
||||
|
||||
- name: Run component tests for Embedding SDK
|
||||
run: node e2e/runner/run_cypress_ci.js component --browser ${{ steps.cypress-prep.outputs.chrome-path }}
|
||||
|
||||
- name: Upload Test Results
|
||||
uses: ./.github/actions/upload-test-results
|
||||
@@ -190,12 +192,14 @@ jobs:
|
||||
with:
|
||||
script: | #js
|
||||
const {
|
||||
generateReport,
|
||||
parseReport,
|
||||
formatSummary
|
||||
} = require("./.github/scripts/handle-mochawesome-report.js");
|
||||
|
||||
const report = parseReport();
|
||||
const summary = formatSummary(report);
|
||||
const report = await generateReport();
|
||||
const results = parseReport(report);
|
||||
const summary = formatSummary(results);
|
||||
|
||||
await core.summary.addRaw(summary).write();
|
||||
|
||||
|
||||
2
.github/workflows/e2e-cross-version.yml
vendored
@@ -126,7 +126,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: lts/Hydrogen # 18.x.x
|
||||
node-version: lts/Jod # 22.x.x
|
||||
- run: npm install @slack/web-api
|
||||
- name: notify slack of failure
|
||||
uses: actions/github-script@v7
|
||||
|
||||
63
.github/workflows/e2e-matrix-builder.yml
vendored
@@ -10,6 +10,8 @@ on:
|
||||
outputs:
|
||||
matrix:
|
||||
value: ${{ jobs.build-matrix.outputs.matrix }}
|
||||
regularChunks:
|
||||
value: ${{ jobs.build-matrix.outputs.regularChunks }}
|
||||
|
||||
jobs:
|
||||
build-matrix:
|
||||
@@ -17,68 +19,44 @@ jobs:
|
||||
timeout-minutes: 5
|
||||
outputs:
|
||||
matrix: ${{ steps.matrix.outputs.config }}
|
||||
regularChunks: ${{ steps.matrix.outputs.regularChunks }}
|
||||
steps:
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '20.x'
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
sparse-checkout: e2e
|
||||
- name: get test file names
|
||||
id: test-files
|
||||
shell: bash
|
||||
run: |
|
||||
echo "::set-output name=filenames::$(find e2e/test/scenarios -name '*.cy.spec.*' | tr '\n' ',')"
|
||||
- run: yarn add underscore
|
||||
node-version: '22.x'
|
||||
- uses: actions/github-script@v7
|
||||
id: matrix
|
||||
env:
|
||||
chunks: ${{ inputs.chunks }}
|
||||
with:
|
||||
script: | # js
|
||||
const _ = require('underscore');
|
||||
|
||||
const java = 21;
|
||||
const defaultRunner = "ubuntu-22.04";
|
||||
|
||||
// these are special and shouldn't be chunked out arbitrarily
|
||||
const blacklist = [
|
||||
"/embedding-sdk/",
|
||||
"/cross-version/"
|
||||
];
|
||||
|
||||
const defaultOptions = {
|
||||
"java-version": java,
|
||||
runner: defaultRunner,
|
||||
specs: "./e2e/test/scenarios/**/*.cy.spec.*",
|
||||
edition: "ee",
|
||||
};
|
||||
|
||||
const allSpecs = "./e2e/test/scenarios/**/*.cy.spec.*";
|
||||
|
||||
// see config.js function getSplittableSpecs for logic that excludes some tests from auto splitting
|
||||
const specialTests = [
|
||||
{ name: "embedding-sdk", specs: "./e2e/test/scenarios/embedding-sdk/**.cy.spec.*" },
|
||||
{ name: "oss-subset", edition: 'oss', tags: "@OSS" },
|
||||
{ name: "slow", tags: "@slow" },
|
||||
{ name: "mongo", tags: "@mongo" },
|
||||
{ name: "oss-subset", edition: 'oss', tags: "@OSS @smoke+-@EE", specs: allSpecs },
|
||||
{ name: "mongo", tags: "@mongo", specs: allSpecs },
|
||||
];
|
||||
|
||||
const fileNames = "${{ steps.test-files.outputs.filenames }}"
|
||||
.split(",")
|
||||
.filter(Boolean)
|
||||
.filter(testPath => !blacklist.some(blacklisted => testPath.includes(blacklisted)));
|
||||
const inputChunks = Number(process.env.chunks);
|
||||
const regularChunks = inputChunks - specialTests.length;
|
||||
|
||||
const fileCount = fileNames.length;
|
||||
|
||||
// subtract the special tests since they all get their own runners
|
||||
const chunkSize = fileCount / (Number('${{ inputs.chunks }}') - specialTests.length);
|
||||
|
||||
|
||||
|
||||
const chunkedFiles = _.chunk(fileNames, chunkSize);
|
||||
|
||||
const regularTests = chunkedFiles.map((files, index) => ({
|
||||
name: `e2e-group-${index + 1}`,
|
||||
specs: files.join(","),
|
||||
tags: '',
|
||||
}));
|
||||
const regularTests = new Array(regularChunks).fill(1)
|
||||
.map((files, index) => ({
|
||||
name: `e2e-group-${index + 1}`,
|
||||
}));
|
||||
|
||||
// regular chunks need to come before special chunks
|
||||
const testSets = [...regularTests, ...specialTests];
|
||||
|
||||
const config = testSets.map((options) => ({
|
||||
@@ -86,6 +64,9 @@ jobs:
|
||||
...options,
|
||||
}));
|
||||
|
||||
console.log("matrix config", config);
|
||||
|
||||
core.setOutput("regularChunks", JSON.stringify(regularChunks));
|
||||
core.setOutput("config", JSON.stringify({ include: config }));
|
||||
|
||||
console.log({ regularChunks });
|
||||
console.log("matrix config", config);
|
||||
|
||||
@@ -97,12 +97,16 @@ jobs:
|
||||
uses: ./.github/actions/prepare-cypress
|
||||
- name: Run Snowplow micro
|
||||
uses: ./.github/actions/run-snowplow-micro
|
||||
- name: Run Metabase
|
||||
run: node e2e/runner/run_cypress_ci.js start
|
||||
- name: Generate database snapshots
|
||||
run: node e2e/runner/run_cypress_ci.js snapshot
|
||||
|
||||
# For all options and fine-grained control, take a look at the documentation
|
||||
# https://github.com/cypress-io/cypress/tree/develop/npm/grep
|
||||
- name: Stress-test ${{ github.event.inputs.spec }} ${{ github.event.inputs.burn_in }} times
|
||||
run: |
|
||||
yarn run test-cypress-run \
|
||||
node e2e/runner/run_cypress_ci.js e2e \
|
||||
--spec '${{ github.event.inputs.spec }}' \
|
||||
--env burn=${{ github.event.inputs.burn_in }},grep='${{ github.event.inputs.grep }}' \
|
||||
--config-file e2e/support/cypress-stress-test.config.js \
|
||||
|
||||
53
.github/workflows/e2e-test.yml
vendored
@@ -22,6 +22,12 @@ on:
|
||||
required: false
|
||||
type: string
|
||||
default: ubuntu-22.04
|
||||
total_chunks: # number of chunks
|
||||
required: false
|
||||
type: number
|
||||
split_index: # index of the chunk
|
||||
required: false
|
||||
type: number
|
||||
|
||||
jobs:
|
||||
e2e-tests:
|
||||
@@ -32,12 +38,17 @@ jobs:
|
||||
MB_EDITION: ${{ inputs.edition }}
|
||||
DISPLAY: ""
|
||||
QA_DB_ENABLED: true
|
||||
PR_NUMBER: ${{ github.event.pull_request.number || '' }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
HASH: ${{ github.event.pull_request.head.sha || github.sha }}-${{ github.run_attempt }}
|
||||
JOB_NAME: ${{ inputs.name }}
|
||||
# Any env starting with `CYPRESS_` will be available to all Cypress tests via `Cypress.env()`
|
||||
# Example: you can get `CYPRESS_FOO` with `Cypress.env("FOO")`
|
||||
CYPRESS_ALL_FEATURES_TOKEN: ${{ secrets.ENTERPRISE_TOKEN }}
|
||||
CYPRESS_NO_FEATURES_TOKEN: ${{ secrets.E2E_STARTER_TOKEN }}
|
||||
CYPRESS_PULL_REQUEST_ID: ${{ github.event.pull_request.number || '' }}
|
||||
COMMIT_INFO_MESSAGE: ${{ github.event.pull_request.title || github.event.head_commit.message || github.event.head.sha }}
|
||||
MB_EXPERIMENTAL_SEARCH_BLOCK_ON_QUEUE: true
|
||||
MB_SNOWPLOW_AVAILABLE: true
|
||||
MB_SNOWPLOW_URL: "http://localhost:9090" # Snowplow micro
|
||||
TZ: US/Pacific # to make node match the instance tz
|
||||
@@ -47,7 +58,7 @@ jobs:
|
||||
mongo: ${{ inputs.name == 'mongo' }}
|
||||
postgres: ${{ inputs.name != 'mongo' }}
|
||||
mysql: ${{ inputs.name != 'mongo' }}
|
||||
openldap: ${{ contains(inputs.specs, 'ldap') }}
|
||||
openldap: true
|
||||
maildev: true
|
||||
webhook: true
|
||||
steps:
|
||||
@@ -74,11 +85,6 @@ jobs:
|
||||
with:
|
||||
name: metabase-${{ inputs.edition }}-${{ github.event.pull_request.head.sha || github.sha }}-uberjar
|
||||
|
||||
- name: Get the version info
|
||||
run: |
|
||||
jar xf target/uberjar/metabase.jar version.properties
|
||||
mv version.properties resources/
|
||||
|
||||
- name: Prepare front-end environment
|
||||
uses: ./.github/actions/prepare-frontend
|
||||
|
||||
@@ -95,20 +101,33 @@ jobs:
|
||||
- name: Run Snowplow micro
|
||||
uses: ./.github/actions/run-snowplow-micro
|
||||
|
||||
- name: Run EE Cypress tests on ${{ inputs.name }}
|
||||
if: ${{ !inputs.tags }}
|
||||
- name: Run Metabase
|
||||
run: node e2e/runner/run_cypress_ci.js start
|
||||
|
||||
- name: Generate database snapshots
|
||||
run: node e2e/runner/run_cypress_ci.js snapshot
|
||||
|
||||
- name: Run auto-split Cypress tests on ${{ inputs.name }}
|
||||
if: ${{ !inputs.specs }}
|
||||
env:
|
||||
SPLIT: ${{ inputs.total_chunks }}
|
||||
SPLIT_INDEX: ${{ inputs.split_index }}
|
||||
SPLIT_FILE: "./e2e/support/timings.json"
|
||||
SPLIT_OUTPUT_FILE: "newTimes.json"
|
||||
SPLIT_TIME_THRESHOLD: 5.0
|
||||
# do not write cypress-split summary to github
|
||||
SPLIT_SUMMARY: false
|
||||
shell: bash
|
||||
run: |
|
||||
yarn run test-cypress-run \
|
||||
--env grepTags="-@slow+-@mongo+-@flaky+-@OSS --@quarantine",grepOmitFiltered=true \
|
||||
--spec '${{ inputs.specs }}' \
|
||||
--browser ${{ steps.cypress-prep.outputs.chrome-path }}
|
||||
node e2e/runner/run_cypress_ci.js e2e \
|
||||
--env grepTags="-@mongo+-@flaky+-@OSS --@quarantine",grepOmitFiltered=true \
|
||||
--browser ${{ steps.cypress-prep.outputs.chrome-path }}
|
||||
|
||||
- name: Run Tagged EE Cypress tests on ${{ inputs.name }}
|
||||
if: ${{ inputs.tags }}
|
||||
if: ${{ inputs.specs }}
|
||||
shell: bash
|
||||
run: |
|
||||
yarn run test-cypress-run \
|
||||
node e2e/runner/run_cypress_ci.js e2e \
|
||||
--env grepTags="${{inputs.tags}} --@quarantine",grepOmitFiltered=true \
|
||||
--spec '${{ inputs.specs }}' \
|
||||
--browser ${{ steps.cypress-prep.outputs.chrome-path }}
|
||||
@@ -141,11 +160,13 @@ jobs:
|
||||
with:
|
||||
script: | #js
|
||||
const {
|
||||
generateReport,
|
||||
parseReport,
|
||||
formatSummary
|
||||
} = require("./.github/scripts/handle-mochawesome-report.js");
|
||||
|
||||
const report = parseReport();
|
||||
const summary = formatSummary(report);
|
||||
const report = await generateReport();
|
||||
const results = parseReport(report);
|
||||
const summary = formatSummary(results);
|
||||
|
||||
await core.summary.addRaw(summary).write();
|
||||
|
||||
80
.github/workflows/e2e-tests.yml
vendored
@@ -1,33 +1,17 @@
|
||||
name: E2E Tests
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "master"
|
||||
- "release-**"
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, ready_for_review]
|
||||
workflow_call:
|
||||
inputs:
|
||||
skip:
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref && github.ref || github.run_id }}
|
||||
group: ${{ github.workflow }}-${{ github.head_ref && github.ref || github.run_id }}-e2e
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
files-changed:
|
||||
name: Check which files changed
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 3
|
||||
outputs:
|
||||
e2e_all: ${{ steps.changes.outputs.e2e_all }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Test which files changed
|
||||
uses: dorny/paths-filter@v3.0.0
|
||||
id: changes
|
||||
with:
|
||||
token: ${{ github.token }}
|
||||
filters: .github/file-paths.yaml
|
||||
|
||||
e2e-matrix-builder:
|
||||
uses: ./.github/workflows/e2e-matrix-builder.yml
|
||||
with:
|
||||
@@ -64,13 +48,9 @@ jobs:
|
||||
node_version: requirements.node,
|
||||
};
|
||||
|
||||
|
||||
build:
|
||||
needs: [files-changed, get-build-requirements]
|
||||
if: |
|
||||
!cancelled() &&
|
||||
github.event.pull_request.draft == false &&
|
||||
needs.files-changed.outputs.e2e_all == 'true'
|
||||
needs: [get-build-requirements]
|
||||
if: ${{ !cancelled() && !inputs.skip }}
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 25
|
||||
strategy:
|
||||
@@ -91,7 +71,7 @@ jobs:
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: uberjar
|
||||
java-version: "${{ needs.get-build-requirements.outputs.java_version || 11 }}"
|
||||
java-version: "${{ needs.get-build-requirements.outputs.java_version || 21 }}"
|
||||
|
||||
- name: Build uberjar with ./bin/build.sh
|
||||
run: ./bin/build.sh
|
||||
@@ -101,10 +81,43 @@ jobs:
|
||||
with:
|
||||
name: metabase-${{ matrix.edition }}-${{ github.event.pull_request.head.sha || github.sha }}-uberjar
|
||||
|
||||
reset-e2e-test-comment:
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- name: Remove test results comment
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: | # js
|
||||
const { owner, repo } = context.repo;
|
||||
|
||||
const { data: comments } = await github.rest.issues.listComments({
|
||||
owner,
|
||||
repo,
|
||||
issue_number: context.issue.number,
|
||||
}).catch(console.error);
|
||||
|
||||
if (!comments) {
|
||||
return;
|
||||
}
|
||||
|
||||
const comment = comments.find((comment) => comment.body.includes('## e2e tests failed on '));
|
||||
|
||||
if (comment) {
|
||||
await github.rest.issues.deleteComment({
|
||||
owner,
|
||||
repo,
|
||||
comment_id: comment.id,
|
||||
});
|
||||
}
|
||||
|
||||
e2e-tests:
|
||||
name: ${{ matrix.name }}-${{ matrix.edition }}
|
||||
uses: ./.github/workflows/e2e-test.yml
|
||||
needs: [build, e2e-matrix-builder]
|
||||
needs:
|
||||
- e2e-matrix-builder
|
||||
- build
|
||||
if: |
|
||||
!cancelled() && needs.build.result == 'success'
|
||||
strategy:
|
||||
@@ -115,6 +128,8 @@ jobs:
|
||||
name: ${{ matrix.name }}
|
||||
edition: ${{ matrix.edition }}
|
||||
specs: ${{ matrix.specs }}
|
||||
total_chunks: ${{ fromJson(needs.e2e-matrix-builder.outputs.regularChunks) }}
|
||||
split_index: ${{ strategy.job-index }}
|
||||
tags: ${{ matrix.tags }}
|
||||
runner: ${{ matrix.runner }}
|
||||
|
||||
@@ -129,9 +144,12 @@ jobs:
|
||||
with:
|
||||
name: Flaky
|
||||
tags: "@flaky"
|
||||
specs: "./e2e/test/scenarios/**/*.cy.spec.*"
|
||||
|
||||
e2e-tests-result:
|
||||
needs: [e2e-tests, flaky-e2e-tests]
|
||||
needs:
|
||||
- e2e-tests
|
||||
- flaky-e2e-tests
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
name: e2e-tests-result
|
||||
|
||||
36
.github/workflows/flake-issue-creator.yml
vendored
@@ -1,36 +0,0 @@
|
||||
name: Flake Issue Creator
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '0 6 * * 1-5' # every weekday at 1am US eastern time
|
||||
|
||||
jobs:
|
||||
flake-issue-creator:
|
||||
# don't run this workflow on a cron for forks
|
||||
if: ${{ github.event_name != 'schedule' || github.repository == 'metabase/metabase' }}
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
sparse-checkout: release
|
||||
- name: Prepare build scripts
|
||||
run: cd ${{ github.workspace }}/release && yarn --frozen-lockfile && yarn build
|
||||
- name: Update flake issues
|
||||
uses: actions/github-script@v7
|
||||
env:
|
||||
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
|
||||
with:
|
||||
script: | # js
|
||||
const { updateFlakeIssues } = require('${{ github.workspace }}/release/dist/index.cjs');
|
||||
|
||||
if (!process.env.SLACK_BOT_TOKEN) {
|
||||
throw new Error('SLACK_BOT_TOKEN is required');
|
||||
}
|
||||
|
||||
await updateFlakeIssues({
|
||||
github,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
});
|
||||
37
.github/workflows/flake-status.yml
vendored
@@ -1,37 +0,0 @@
|
||||
name: Flake Status Report
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '0 6 * * 2,5' # Tuesdays and Fridays at 1am US eastern time
|
||||
|
||||
jobs:
|
||||
flake-status-report:
|
||||
# don't run this workflow on a cron for forks
|
||||
if: ${{ github.event_name != 'schedule' || github.repository == 'metabase/metabase' }}
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
sparse-checkout: release
|
||||
- name: Prepare build scripts
|
||||
run: cd ${{ github.workspace }}/release && yarn --frozen-lockfile && yarn build
|
||||
- name: Post Flake Status Report
|
||||
uses: actions/github-script@v7
|
||||
env:
|
||||
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
|
||||
with:
|
||||
script: | # js
|
||||
const { summarizeFlakes } = require('${{ github.workspace }}/release/dist/index.cjs');
|
||||
|
||||
if (!process.env.SLACK_BOT_TOKEN) {
|
||||
throw new Error('SLACK_BOT_TOKEN is required');
|
||||
}
|
||||
|
||||
await summarizeFlakes({
|
||||
github,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
channelName: 'engineering-ci'
|
||||
});
|
||||
83
.github/workflows/frontend.yml
vendored
@@ -1,37 +1,19 @@
|
||||
name: Frontend
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "master"
|
||||
- "release-**"
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, ready_for_review]
|
||||
workflow_call:
|
||||
inputs:
|
||||
skip:
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref && github.ref || github.run_id }}
|
||||
group: ${{ github.workflow }}-${{ github.head_ref && github.ref || github.run_id }}-frontend
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
files-changed:
|
||||
name: Check which files changed
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 3
|
||||
outputs:
|
||||
frontend_all: ${{ steps.changes.outputs.frontend_all }}
|
||||
e2e_specs: ${{ steps.changes.outputs.e2e_specs }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Test which files changed
|
||||
uses: dorny/paths-filter@v3.0.0
|
||||
id: changes
|
||||
with:
|
||||
token: ${{ github.token }}
|
||||
filters: .github/file-paths.yaml
|
||||
|
||||
fe-lint:
|
||||
needs: files-changed
|
||||
if: needs.files-changed.outputs.frontend_all == 'true' || needs.files-changed.outputs.e2e_specs == 'true'
|
||||
if: ${{ !inputs.skip }}
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
@@ -44,14 +26,15 @@ jobs:
|
||||
m2-cache-key: "cljs"
|
||||
- name: Compile CLJS
|
||||
run: yarn build-pure:cljs
|
||||
- name: Find CSS variables that are used but never defined
|
||||
run: yarn find-never-defined-css-variables
|
||||
- name: Run Prettier formatting linter
|
||||
run: yarn run lint-prettier-pure
|
||||
- name: Run ESLint linter
|
||||
run: yarn run lint-eslint-pure
|
||||
|
||||
fe-type-check:
|
||||
needs: files-changed
|
||||
if: needs.files-changed.outputs.frontend_all == 'true'
|
||||
if: ${{ !inputs.skip }}
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
@@ -68,8 +51,7 @@ jobs:
|
||||
name: Check types
|
||||
|
||||
fe-tests-unit:
|
||||
needs: files-changed
|
||||
if: github.event.pull_request.draft == false && needs.files-changed.outputs.frontend_all == 'true'
|
||||
if: ${{ !inputs.skip }}
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
@@ -109,8 +91,7 @@ jobs:
|
||||
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
|
||||
|
||||
fe-tests-timezones:
|
||||
needs: files-changed
|
||||
if: github.event.pull_request.draft == false && needs.files-changed.outputs.frontend_all == 'true'
|
||||
if: ${{ !inputs.skip }}
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
@@ -123,3 +104,43 @@ jobs:
|
||||
m2-cache-key: "cljs"
|
||||
- name: Run frontend timezones tests
|
||||
run: yarn run test-timezones
|
||||
|
||||
fe-tests-result:
|
||||
needs:
|
||||
- fe-lint
|
||||
- fe-type-check
|
||||
- fe-tests-unit
|
||||
- fe-tests-timezones
|
||||
if: always() && !cancelled()
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
env:
|
||||
needs: ${{ toJson(needs) }}
|
||||
steps:
|
||||
- name: Check frontend job status
|
||||
uses: actions/github-script@v7
|
||||
env:
|
||||
needs: ${{ toJson(needs) }}
|
||||
with:
|
||||
script: | # js
|
||||
const needs = JSON.parse(process.env.needs);
|
||||
const jobs = Object.entries(needs).map(
|
||||
([jobName, jobValues]) => ({
|
||||
name: jobName,
|
||||
result: jobValues.result
|
||||
}));
|
||||
|
||||
// are all jobs skipped or successful?
|
||||
if (jobs.every(job => (job.result === 'skipped' || job.result === 'success'))) {
|
||||
console.log('All jobs are skipped or successful');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// otherwise, something failed
|
||||
console.log('Some frontend jobs failed');
|
||||
jobs.forEach((job) => {
|
||||
if (job.result !== 'success') {
|
||||
console.log(`${job.name} - ${job.result}`);
|
||||
}
|
||||
});
|
||||
process.exit(1);
|
||||
|
||||
53
.github/workflows/generative-query-test.yml
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
name: Generative Query Test
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
seed:
|
||||
description: 'Seed value (empty = random; logged)'
|
||||
type: number
|
||||
iterations:
|
||||
description: 'Number of test iterations (overrides `seconds`)'
|
||||
type: number
|
||||
seconds:
|
||||
description: 'No further iteration after _this_ number of seconds since test started'
|
||||
ref:
|
||||
description: 'Ref to run generative tests on'
|
||||
default: qgen-milestone-1
|
||||
|
||||
jobs:
|
||||
generative-query-test:
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 90
|
||||
name: Generative Query Test
|
||||
env:
|
||||
CI: 'true'
|
||||
MB_GENTEST_SEED: ${{ inputs.seed }}
|
||||
MB_GENTEST_LIMIT_ITERATIONS: ${{ inputs.iterations }}
|
||||
MB_GENTEST_LIMIT_SECONDS: ${{ inputs.seconds }}
|
||||
# TODO: Remove in favor of cp root with further tests
|
||||
MB_GENTEST_RUN: true
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ inputs.ref }}
|
||||
- name: Prepare front-end environment
|
||||
uses: ./.github/actions/prepare-frontend
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: generative-query-test
|
||||
|
||||
- name: Run test
|
||||
run: clojure -X:dev:ci:test:ee:ee-dev :only 'metabase.query-processor-test.generative-test'
|
||||
|
||||
- name: Publish Test Report (JUnit)
|
||||
uses: dorny/test-reporter@v1
|
||||
if: failure()
|
||||
with:
|
||||
path: "target/junit/**/*_test.xml"
|
||||
name: JUnit Test Report (Generative Query test)
|
||||
reporter: java-junit
|
||||
list-suites: failed
|
||||
list-tests: failed
|
||||
fail-on-error: false
|
||||
4
.github/workflows/links.yml
vendored
@@ -19,7 +19,7 @@ jobs:
|
||||
uses: lycheeverse/lychee-action@v2
|
||||
with:
|
||||
fail: false
|
||||
args: docs --config ./lychee/config.toml --verbose --no-progress
|
||||
args: docs --config ./.lychee/config.toml --verbose --no-progress
|
||||
format: markdown
|
||||
|
||||
- name: Create Issue From File
|
||||
@@ -27,6 +27,6 @@ jobs:
|
||||
uses: peter-evans/create-issue-from-file@v5
|
||||
with:
|
||||
title: Link Checker Report
|
||||
content-filepath: ./lychee/out.md
|
||||
content-filepath: ./.lychee/out.md
|
||||
labels: "Type:Documentation"
|
||||
assignees: jeff-bruemmer
|
||||
|
||||
17
.github/workflows/loki.yml
vendored
@@ -49,29 +49,16 @@ jobs:
|
||||
m2-cache-key: "cljs"
|
||||
|
||||
- name: Compile CLJS
|
||||
run: yarn build-pure:cljs
|
||||
run: NODE_ENV=development yarn build-pure:cljs
|
||||
|
||||
- name: Build Storybook
|
||||
# We won't be able to use Storybook play's `userEvent` with production build
|
||||
# see https://github.com/storybookjs/storybook/issues/19758
|
||||
run: NODE_ENV=development yarn build-storybook
|
||||
|
||||
- name: Serve Storybook
|
||||
run: yarn http-server storybook-static -p 6006 &
|
||||
shell: bash
|
||||
|
||||
- name: Wait for Storybook to become available
|
||||
run: |
|
||||
echo "Waiting for Storybook to be served..."
|
||||
while ! curl --silent --fail http://localhost:6006; do
|
||||
sleep 5
|
||||
echo "Retrying..."
|
||||
done
|
||||
echo "Storybook is being served!"
|
||||
|
||||
- name: Run Loki Visual Tests
|
||||
run: |
|
||||
yarn test-visual:loki
|
||||
yarn loki --requireReference --reactUri file:./storybook-static --chromeFlags='--headless --disable-gpu' --verboseRenderer
|
||||
|
||||
- name: Generate Visual Report on Failure
|
||||
if: failure()
|
||||
|
||||
28
.github/workflows/pre-release.yml
vendored
@@ -100,7 +100,7 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
edition: [oss, ee]
|
||||
java-version: [11, 17, 21]
|
||||
java-version: [21]
|
||||
steps:
|
||||
- name: Prepare JRE (Java Run-time Environment)
|
||||
uses: actions/setup-java@v4
|
||||
@@ -168,11 +168,29 @@ jobs:
|
||||
run: |
|
||||
jar xf metabase.jar version.properties
|
||||
mv version.properties resources/
|
||||
- name: Run a few important Cypress tests as sanity check
|
||||
|
||||
- name: Move jar
|
||||
run: mkdir -p ./target/uberjar && cp metabase.jar ./target/uberjar/metabase.jar
|
||||
|
||||
- name: Run Metabase
|
||||
run: node e2e/runner/run_cypress_ci.js start
|
||||
|
||||
- name: Make app db snapshot
|
||||
run: node e2e/runner/run_cypress_ci.js snapshot
|
||||
|
||||
- name: Run a few important OSS Cypress tests as sanity check
|
||||
if: ${{ matrix.edition == 'oss' }}
|
||||
run: |
|
||||
mkdir -p ./target/uberjar && cp metabase.jar ./target/uberjar/metabase.jar
|
||||
yarn test-cypress-run \
|
||||
--env grepTags="@smoke",grepOmitFiltered=true \
|
||||
node e2e/runner/run_cypress_ci.js e2e \
|
||||
--env grepTags="@smoke+-@EE",grepOmitFiltered=true \
|
||||
--spec './e2e/test/scenarios/**/*.cy.spec.(js|ts)' \
|
||||
--browser ${{ steps.cypress-prep.outputs.chrome-path }}
|
||||
|
||||
- name: Run a few important EE Cypress tests as sanity check
|
||||
if: ${{ matrix.edition == 'ee' }}
|
||||
run: |
|
||||
node e2e/runner/run_cypress_ci.js e2e \
|
||||
--env grepTags="@smoke+-@OSS",grepOmitFiltered=true \
|
||||
--spec './e2e/test/scenarios/**/*.cy.spec.(js|ts)' \
|
||||
--browser ${{ steps.cypress-prep.outputs.chrome-path }}
|
||||
|
||||
|
||||
13
.github/workflows/release-embedding-sdk.yml
vendored
@@ -13,6 +13,7 @@ on:
|
||||
- master
|
||||
- release-x.51.x
|
||||
- release-x.52.x
|
||||
- release-x.53.x
|
||||
|
||||
concurrency:
|
||||
# We want to ensure only one job is running at a time per branch because
|
||||
@@ -211,12 +212,16 @@ jobs:
|
||||
|
||||
- name: Create a PR updating readme + published version, and changelog (using GitHub Metabase Automation account)
|
||||
run: |
|
||||
# TODO: Remove this step once github includes the new gh CLI version 2.65.0
|
||||
eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
|
||||
brew install gh
|
||||
|
||||
git checkout -b update-sdk-version-${{ env.sdk_version }}
|
||||
git commit -a -m 'Update Readme version references and published npm version to ${{ env.sdk_version }}'
|
||||
git push origin HEAD
|
||||
gh pr create --base ${{ inputs.branch }}\
|
||||
--assignee "${GITHUB_ACTOR}"\
|
||||
--title "Update SDK version to ${{ env.sdk_version }}"\
|
||||
--title "docs(sdk): Update SDK version to ${{ env.sdk_version }}"\
|
||||
--body "Update Readme version references and published npm package version to ${{ env.sdk_version }}"
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}
|
||||
@@ -256,10 +261,10 @@ jobs:
|
||||
run: |
|
||||
echo //registry.npmjs.org/:_authToken=${{ secrets.NPM_RELEASE_TOKEN }} > .npmrc
|
||||
# Please keep the value in sync with `inputs.branch`'s release branch
|
||||
npm publish --tag ${{fromJson('{"master": "nightly", "release-x.51.x": "51-stable", "release-x.52.x": "52-stable"}')[inputs.branch]}}
|
||||
npm publish --tag ${{fromJson('{"master": "nightly", "release-x.51.x": "51-stable", "release-x.52.x": "52-stable", "release-x.53.x": "53-stable"}')[inputs.branch]}}
|
||||
|
||||
- name: Add `latest` tag to the latest release branch (`release-x.52.x`) deployment
|
||||
if: ${{ inputs.branch == 'release-x.52.x' }}
|
||||
- name: Add `latest` tag to the latest release branch (`release-x.53.x`) deployment
|
||||
if: ${{ inputs.branch == 'release-x.53.x' }}
|
||||
working-directory: sdk
|
||||
run: |
|
||||
npm dist-tag add @metabase/embedding-sdk-react@${{ env.sdk_version }} latest
|
||||
|
||||
2
.github/workflows/release-patch.yml
vendored
@@ -9,7 +9,7 @@ on:
|
||||
type: number
|
||||
required: true
|
||||
schedule:
|
||||
- cron: '15 0 * * 2-6' # every weekday at 7/8:15 pm Eastern Time
|
||||
- cron: '0 21 * * 1-5' # every weekday at 4 pm EST/5 pm EDT
|
||||
|
||||
jobs:
|
||||
auto-patch-trigger:
|
||||
|
||||
8
.github/workflows/rerun-workflows.yml
vendored
@@ -2,7 +2,7 @@ name: Re-run Flaky Workflows
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: [Backend, Driver Tests, E2E Tests, Frontend, Backend-Cloverage]
|
||||
workflows: [Run tests]
|
||||
types: [completed]
|
||||
branches: [master, 'release-x.**', 'backport-**']
|
||||
|
||||
@@ -25,7 +25,7 @@ jobs:
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: lts/Hydrogen # 18.x.x
|
||||
node-version: lts/Jod # 22.x.x
|
||||
- run: npm install @slack/web-api
|
||||
- name: Trigger a re-run
|
||||
uses: actions/github-script@v7
|
||||
@@ -61,10 +61,10 @@ jobs:
|
||||
});
|
||||
|
||||
const failedJobs = jobInfo.data.jobs
|
||||
.filter(job => job.status === "completed" && job.conclusion === "failure");
|
||||
.filter(job => job.status === "completed" && job.conclusion === "failure" && !job.name.includes("-tests-result"));
|
||||
|
||||
// don't bother slack if only the flaky job failed
|
||||
if (failedJobs.every(job => job.name.includes("flaky"))) {
|
||||
if (failedJobs.every(job => job.name.toLowerCase().includes("flaky"))) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
86
.github/workflows/run-tests.yml
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
name: Run tests
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "master"
|
||||
- "release-**"
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened]
|
||||
|
||||
jobs:
|
||||
files-changed:
|
||||
name: Check which files changed
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 5
|
||||
outputs:
|
||||
e2e_all: ${{ steps.changes.outputs.e2e_all }}
|
||||
backend_all: ${{ steps.changes.outputs.backend_all }}
|
||||
frontend_all: ${{ steps.changes.outputs.frontend_all }}
|
||||
frontend_sources: ${{ steps.changes.outputs.frontend_sources }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Test which files changed
|
||||
uses: dorny/paths-filter@v3.0.0
|
||||
id: changes
|
||||
with:
|
||||
token: ${{ github.token }}
|
||||
filters: .github/file-paths.yaml
|
||||
|
||||
static-viz-files-changed:
|
||||
name: Check whether static-viz files changed
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 10
|
||||
outputs:
|
||||
static_viz: ${{ steps.static_viz.outputs.static_viz }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Prepare front-end environment
|
||||
uses: ./.github/actions/prepare-frontend
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: "files-changed"
|
||||
- name: Build static-viz frontend
|
||||
run: yarn build-static-viz
|
||||
- name: Upload Static Viz Bundle Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: static-viz-bundle-${{ github.sha }}
|
||||
path: resources/frontend_client/app/dist
|
||||
|
||||
- name: Check for static viz changes
|
||||
uses: dorny/paths-filter@v3.0.0
|
||||
id: static_viz
|
||||
with:
|
||||
token: ${{ github.token }}
|
||||
filters: .github/static-viz-sources.yaml
|
||||
|
||||
backend-tests:
|
||||
if: ${{ !cancelled() }}
|
||||
needs: [files-changed, static-viz-files-changed]
|
||||
uses: ./.github/workflows/backend.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
skip: ${{ needs.files-changed.outputs.backend_all != 'true' && needs.static-viz-files-changed.outputs.static_viz != 'true' }}
|
||||
|
||||
driver-tests:
|
||||
needs: files-changed
|
||||
uses: ./.github/workflows/drivers.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
skip: ${{ needs.files-changed.outputs.backend_all != 'true' }}
|
||||
|
||||
frontend-tests:
|
||||
needs: files-changed
|
||||
uses: ./.github/workflows/frontend.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
skip: ${{ needs.files-changed.outputs.frontend_all != 'true' }}
|
||||
|
||||
e2e-tests:
|
||||
needs: files-changed
|
||||
uses: ./.github/workflows/e2e-tests.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
skip: ${{ needs.files-changed.outputs.e2e_all != 'true' }}
|
||||
4
.github/workflows/snyk.yml
vendored
@@ -9,7 +9,7 @@ on:
|
||||
- '**/deps.edn'
|
||||
- '**/package.json'
|
||||
- '.github/workflows/snyk.yml'
|
||||
- '.github/scripts/write-poms.xml'
|
||||
- '.github/scripts/write-poms.sh'
|
||||
schedule:
|
||||
- cron: '0 5 * * *'
|
||||
|
||||
@@ -35,6 +35,6 @@ jobs:
|
||||
continue-on-error: true
|
||||
run: snyk test --all-projects --sarif-file-output=snyk.sarif
|
||||
- name: Upload result to GitHub Code Scanning
|
||||
uses: github/codeql-action/upload-sarif@v2
|
||||
uses: github/codeql-action/upload-sarif@v3
|
||||
with:
|
||||
sarif_file: snyk.sarif
|
||||
|
||||
19
.github/workflows/stale.yml
vendored
@@ -1,20 +1,25 @@
|
||||
name: 'Close Stale PRs'
|
||||
name: Close Stale PRs
|
||||
on:
|
||||
schedule:
|
||||
- cron: '00 1 * * *'
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
issues: write
|
||||
|
||||
jobs:
|
||||
close-stale-prs:
|
||||
# don't run this workflow on a cron for forks
|
||||
if: ${{ github.event_name != 'schedule' || github.repository == 'metabase/metabase' }}
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- uses: actions/stale@v6
|
||||
- uses: actions/stale@v9
|
||||
with:
|
||||
stale-pr-message: 'This pull request has had no activity for one year, it will be closed in 1 week if no further activity occurs.'
|
||||
close-pr-message: 'This pull request was closed because it had no activity for more than one year.'
|
||||
days-before-pr-stale: 365
|
||||
days-before-pr-close: 7
|
||||
stale-pr-message: 'This pull request has had no activity for 90 days, it will be closed in 2 weeks if no further activity occurs.'
|
||||
close-pr-message: 'This pull request was closed because it had no activity for more than 90 days.'
|
||||
days-before-issue-stale: -1 # never auto-close issues
|
||||
days-before-pr-stale: 90
|
||||
days-before-pr-close: 14
|
||||
operations-per-run: 999
|
||||
|
||||
89
.github/workflows/uberjar.yml
vendored
@@ -43,9 +43,7 @@ jobs:
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: uberjar
|
||||
# Build with Java 11 so they compiled code doesn't try to use Java >11 classes... see
|
||||
# https://metaboat.slack.com/archives/C5XHN8GLW/p1731517744549619?thread_ts=1731504670.951389&cid=C5XHN8GLW
|
||||
java-version: 11
|
||||
java-version: 21
|
||||
- name: Build
|
||||
run: ./bin/build.sh
|
||||
- name: Prepare uberjar artifact
|
||||
@@ -61,7 +59,7 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
edition: [ee, oss]
|
||||
java-version: [11, 17, 21]
|
||||
java-version: [21]
|
||||
steps:
|
||||
- name: Prepare JRE (Java Run-time Environment)
|
||||
uses: actions/setup-java@v4
|
||||
@@ -135,7 +133,7 @@ jobs:
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: bin/docker/.
|
||||
platforms: linux/amd64
|
||||
platforms: linux/amd64,linux/arm64
|
||||
network: host
|
||||
tags: localhost:5000/metabase-dev:${{ steps.extract_branch.outputs.branch }}-${{ matrix.edition }}
|
||||
build-args: |
|
||||
@@ -148,7 +146,7 @@ jobs:
|
||||
- name: Is Docker running?
|
||||
run: docker ps
|
||||
- name: Wait for Metabase to start and reach 100% health
|
||||
run: while ! curl -s 'http://localhost:3000/api/health' | grep '{"status":"ok"}'; do sleep 1; done
|
||||
run: while ! curl 'http://localhost:3000/api/health' | grep '{"status":"ok"}'; do sleep 1; done
|
||||
timeout-minutes: 3
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
@@ -156,30 +154,75 @@ jobs:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Retag and push images if master (ee)
|
||||
- name: Retag and push images if master (ee) - should be cached at this point
|
||||
if: ${{ (github.ref_name == 'master') && matrix.edition == 'ee' }}
|
||||
run: docker tag localhost:5000/metabase-dev:${{ steps.extract_branch.outputs.branch }}-ee ${{ github.repository_owner }}/metabase-enterprise-head:latest && docker push ${{ github.repository_owner }}/metabase-enterprise-head:latest
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: bin/docker/.
|
||||
platforms: linux/amd64,linux/arm64
|
||||
network: host
|
||||
tags: ${{ github.repository_owner }}/metabase-enterprise-head:latest
|
||||
build-args: |
|
||||
GIT_COMMIT_SHA=${{ github.sha }}
|
||||
no-cache: false
|
||||
push: true
|
||||
|
||||
# TODO: remove when we're done testing metabot
|
||||
- name: Retag and push images if metabot-v3-second-try (ee)
|
||||
- name: Retag and push images if metabot-v3-second-try (ee) - should be cached at this point
|
||||
if: ${{ (github.ref_name == 'metabot-v3-second-try') && matrix.edition == 'ee' }}
|
||||
run: docker tag localhost:5000/metabase-dev:${{ steps.extract_branch.outputs.branch }}-ee ${{ github.repository_owner }}/metabase-enterprise-head:metabot && docker push ${{ github.repository_owner }}/metabase-enterprise-head:metabot
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: bin/docker/.
|
||||
platforms: linux/amd64,linux/arm64
|
||||
network: host
|
||||
tags: ${{ github.repository_owner }}/metabase-enterprise-head:metabot
|
||||
build-args: |
|
||||
GIT_COMMIT_SHA=${{ github.sha }}
|
||||
no-cache: false
|
||||
push: true
|
||||
|
||||
- name: Retag and push images if master (oss)
|
||||
- name: Retag and push images if master (oss) - should be cached at this point
|
||||
if: ${{ (github.ref_name == 'master') && matrix.edition == 'oss' }}
|
||||
run: docker tag localhost:5000/metabase-dev:${{ steps.extract_branch.outputs.branch }}-oss ${{ github.repository_owner }}/metabase-head:latest && docker push ${{ github.repository_owner }}/metabase-head:latest
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: bin/docker/.
|
||||
platforms: linux/amd64,linux/arm64
|
||||
network: host
|
||||
tags: ${{ github.repository_owner }}/metabase-head:latest
|
||||
build-args: |
|
||||
GIT_COMMIT_SHA=${{ github.sha }}
|
||||
no-cache: false
|
||||
push: true
|
||||
|
||||
- name: Retag and push images if master (ee-extra)
|
||||
- name: Retag and push images if master (ee-extra) - should be cached at this point
|
||||
if: ${{ (github.ref_name == 'master') && matrix.edition == 'ee-extra' }}
|
||||
run: docker tag localhost:5000/metabase-dev:${{ steps.extract_branch.outputs.branch }}-ee-extra ${{ secrets.METABASE_EE_EXTRA_CONTAINER_REGISTRY }}/metabase-enterprise-head:latest && docker push ${{ secrets.METABASE_EE_EXTRA_CONTAINER_REGISTRY }}/metabase-enterprise-head:latest
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: bin/docker/.
|
||||
platforms: linux/amd64,linux/arm64
|
||||
network: host
|
||||
tags: ${{ secrets.METABASE_EE_EXTRA_CONTAINER_REGISTRY }}/metabase-enterprise-head:latest
|
||||
build-args: |
|
||||
GIT_COMMIT_SHA=${{ github.sha }}
|
||||
no-cache: false
|
||||
push: true
|
||||
|
||||
- name: Retag and push images if dev branch
|
||||
- name: Retag and push images if dev branch - should be cached at this point
|
||||
if: ${{ !(startsWith(github.ref_name,'master') || startsWith(github.ref_name,'backport')) && matrix.edition == 'ee' }}
|
||||
run: docker tag localhost:5000/metabase-dev:${{ steps.extract_branch.outputs.branch }}-ee ${{ github.repository_owner }}/metabase-dev:${{ steps.extract_branch.outputs.branch }} && docker push ${{ github.repository_owner }}/metabase-dev:${{ steps.extract_branch.outputs.branch }}
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: bin/docker/.
|
||||
platforms: linux/amd64,linux/arm64
|
||||
network: host
|
||||
tags: ${{ github.repository_owner }}/metabase-dev:${{ steps.extract_branch.outputs.branch }}
|
||||
build-args: |
|
||||
GIT_COMMIT_SHA=${{ github.sha }}
|
||||
no-cache: false
|
||||
push: true
|
||||
|
||||
- name: Run Trivy vulnerability scanner if master (ee)
|
||||
if: ${{ (github.ref_name == 'master') && matrix.edition == 'ee' }}
|
||||
uses: aquasecurity/trivy-action@0.28.0
|
||||
uses: aquasecurity/trivy-action@0.29.0
|
||||
env:
|
||||
TRIVY_OFFLINE_SCAN: true
|
||||
with:
|
||||
@@ -190,7 +233,7 @@ jobs:
|
||||
|
||||
- name: Run Trivy vulnerability scanner if master (oss)
|
||||
if: ${{ (github.ref_name == 'master') && matrix.edition == 'oss' }}
|
||||
uses: aquasecurity/trivy-action@0.28.0
|
||||
uses: aquasecurity/trivy-action@0.29.0
|
||||
env:
|
||||
TRIVY_OFFLINE_SCAN: true
|
||||
with:
|
||||
@@ -201,7 +244,7 @@ jobs:
|
||||
|
||||
- name: Run Trivy vulnerability scanner if dev branch
|
||||
if: ${{ !(startsWith(github.ref_name,'master') || startsWith(github.ref_name,'backport')) && matrix.edition == 'ee' }}
|
||||
uses: aquasecurity/trivy-action@0.28.0
|
||||
uses: aquasecurity/trivy-action@0.29.0
|
||||
env:
|
||||
TRIVY_OFFLINE_SCAN: true
|
||||
with:
|
||||
@@ -212,19 +255,19 @@ jobs:
|
||||
|
||||
- name: Upload Trivy scan results to GitHub Security tab if master (ee)
|
||||
if: ${{ (github.ref_name == 'master') && matrix.edition == 'ee' }}
|
||||
uses: github/codeql-action/upload-sarif@v2
|
||||
uses: github/codeql-action/upload-sarif@v3
|
||||
with:
|
||||
sarif_file: 'trivy-results.sarif'
|
||||
|
||||
- name: Upload Trivy scan results to GitHub Security tab if master (oss)
|
||||
if: ${{ (github.ref_name == 'master') && matrix.edition == 'oss' }}
|
||||
uses: github/codeql-action/upload-sarif@v2
|
||||
uses: github/codeql-action/upload-sarif@v3
|
||||
with:
|
||||
sarif_file: 'trivy-results.sarif'
|
||||
|
||||
- name: Upload Trivy scan results to GitHub Security tab if dev branch
|
||||
if: ${{ !(startsWith(github.ref_name,'master') || startsWith(github.ref_name,'backport')) && matrix.edition == 'ee' }}
|
||||
uses: github/codeql-action/upload-sarif@v2
|
||||
uses: github/codeql-action/upload-sarif@v3
|
||||
with:
|
||||
sarif_file: 'trivy-results.sarif'
|
||||
|
||||
@@ -287,7 +330,7 @@ jobs:
|
||||
- name: Is Docker with Ubuntu running?
|
||||
run: docker ps
|
||||
- name: Wait for Ubuntu-based Metabase container to start and reach 100% health
|
||||
run: while ! curl -s 'http://localhost:3001/api/health' | grep '{"status":"ok"}'; do sleep 1; done
|
||||
run: while ! curl 'http://localhost:3001/api/health' | grep '{"status":"ok"}'; do sleep 1; done
|
||||
timeout-minutes: 3
|
||||
- name: Login to Docker Hub
|
||||
if: ${{ github.ref_name == 'master' }}
|
||||
|
||||
4
.gitignore
vendored
@@ -21,6 +21,7 @@
|
||||
/*.trace.db
|
||||
/.babel_cache
|
||||
/.env
|
||||
/.envrc
|
||||
/.lein-env
|
||||
/.lein-failures
|
||||
/.lein-plugins
|
||||
@@ -97,6 +98,7 @@ modules/drivers/*/.lsp/*
|
||||
.clj-kondo/*
|
||||
!.clj-kondo/README.md
|
||||
!.clj-kondo/config.edn
|
||||
!.clj-kondo/config/
|
||||
!.clj-kondo/src/
|
||||
!.clj-kondo/test/
|
||||
!.clj-kondo/macros/
|
||||
@@ -116,3 +118,5 @@ modules/drivers/*/.lsp/*
|
||||
|
||||
# swc
|
||||
.swc/
|
||||
|
||||
*storybook.log
|
||||
|
||||
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 48 KiB |
|
After Width: | Height: | Size: 44 KiB |
|
After Width: | Height: | Size: 43 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 42 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 88 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 10 KiB |