@metabase/cli 0.5.6 → 0.5.7-alpha.bryan-rci-6-coverage.6f886fd

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (284) hide show
  1. package/dist/{add-collection-C_PXX4ls.mjs → add-collection-C7c6Y3T3.mjs} +3 -3
  2. package/dist/{alert-C8-KXr_o.mjs → alert-J0qLs6rc.mjs} +7 -7
  3. package/dist/{alerts-BXEyXQRl.mjs → alerts-mjDIdof3.mjs} +6 -6
  4. package/dist/api-key-Bw2jDvT4.mjs +13 -0
  5. package/dist/{append-DHsRfdyS.mjs → append-yaTEz2AE.mjs} +4 -4
  6. package/dist/{archive-CU9OhyrM.mjs → archive-B93SkIvs.mjs} +4 -4
  7. package/dist/{archive-BHhKF2_r.mjs → archive-BmU6DnFz.mjs} +4 -4
  8. package/dist/{archive-1u8702EH.mjs → archive-CbtQNK96.mjs} +3 -3
  9. package/dist/{archive-DxLrdlxM.mjs → archive-Cg67G-qa.mjs} +3 -3
  10. package/dist/{archive-BofgzTAr.mjs → archive-CgcNck0G.mjs} +3 -3
  11. package/dist/{archive-BfCuJyWK.mjs → archive-DYdHrm6V.mjs} +3 -3
  12. package/dist/{archive-eINikapF.mjs → archive-Dg9eMYU6.mjs} +3 -3
  13. package/dist/{archive-Cm3GcZRd.mjs → archive-DrCoSvio.mjs} +3 -3
  14. package/dist/{archive-D87H0xOc.mjs → archive-DzXi2Frh.mjs} +3 -3
  15. package/dist/{archive-DyB65bNo.mjs → archive-P-y61Wi_.mjs} +3 -3
  16. package/dist/{archive-Lgd6irTm.mjs → archive-VZ0dgYTd.mjs} +5 -5
  17. package/dist/{archive-78gVBFu3.mjs → archive-rhxBPOrL.mjs} +3 -3
  18. package/dist/{auth-CeSe2l6R.mjs → auth-CxN5tDg1.mjs} +5 -5
  19. package/dist/{branches-iu9tRXr6.mjs → branches-1ZK62u6h.mjs} +3 -3
  20. package/dist/{breaking-DicKTkii.mjs → breaking-Bv4wZN9X.mjs} +5 -5
  21. package/dist/{broken-70_zMy0L.mjs → broken-BU7MrnHI.mjs} +6 -6
  22. package/dist/{bulk-discard-values-Bsdq0Aid.mjs → bulk-discard-values-6TLs4p2e.mjs} +5 -5
  23. package/dist/{bulk-edit-vWzm2uEj.mjs → bulk-edit-CYnFA1xm.mjs} +3 -3
  24. package/dist/{bulk-rescan-values-qTNZkMRH.mjs → bulk-rescan-values-T__5XlPh.mjs} +4 -4
  25. package/dist/{bulk-sync-schema-neL4AxaB.mjs → bulk-sync-schema-V1Tpqvxg.mjs} +4 -4
  26. package/dist/{cancel-DsyTp_jV.mjs → cancel-RTd-Bg5f.mjs} +3 -3
  27. package/dist/{cancel-task-DMlaD81O.mjs → cancel-task-B6GpgrME.mjs} +2 -2
  28. package/dist/card-BlSUKf2e.mjs +25 -0
  29. package/dist/{cards-DLEx1zfQ.mjs → cards-hYVyzntk.mjs} +4 -4
  30. package/dist/ci-CPRKvyWe.mjs +9 -0
  31. package/dist/cli.mjs +43 -39
  32. package/dist/{client-BN93yUlt.mjs → client-C_5K9lZA.mjs} +16 -11
  33. package/dist/collection-CeaSalia.mjs +21 -0
  34. package/dist/{collection-namespace-C0JcSEwN.mjs → collection-namespace-D0_-6eWp.mjs} +1 -1
  35. package/dist/{content-translation-C2V3jNV7.mjs → content-translation-Bux3aWnt.mjs} +3 -3
  36. package/dist/{copy-C4Nf6Sqt.mjs → copy-B8HnAc11.mjs} +4 -4
  37. package/dist/{copy-9iOg50lN.mjs → copy-BAP_y6s1.mjs} +4 -4
  38. package/dist/{copy-flags-DZ5Cy-Gk.mjs → copy-flags-VQzi7vqf.mjs} +1 -1
  39. package/dist/{create-BafMBtrH.mjs → create-B0l5arU2.mjs} +2 -2
  40. package/dist/{create-C1DBXOxh.mjs → create-BOn7IisH.mjs} +2 -2
  41. package/dist/{create-CWMC90-0.mjs → create-BUPy6vmU.mjs} +2 -2
  42. package/dist/{create-VPzYsXKz.mjs → create-BWrIVbLC.mjs} +2 -2
  43. package/dist/{create-B5h_621T.mjs → create-BcbdVQr_.mjs} +2 -2
  44. package/dist/{create-DJzWxTOV.mjs → create-Bckej8a2.mjs} +3 -3
  45. package/dist/{create-BNgkKeY4.mjs → create-BfD4GgYA.mjs} +2 -2
  46. package/dist/{create-DDEKafSb2.mjs → create-BmEECHlW2.mjs} +4 -4
  47. package/dist/{create-il08Ub78.mjs → create-CH2ebn9r.mjs} +4 -4
  48. package/dist/{create-ZKrdArmQ.mjs → create-CUcwiQgH.mjs} +2 -2
  49. package/dist/{create-BUmS6B9_.mjs → create-C_5-HH9u.mjs} +3 -3
  50. package/dist/{create-vN4sgCHU.mjs → create-CzVYAVbb.mjs} +3 -3
  51. package/dist/{create-CBk4CFjA.mjs → create-D70fh_7H.mjs} +2 -2
  52. package/dist/{create-9p0vyQkK.mjs → create-DF7jPhn1.mjs} +2 -2
  53. package/dist/{create-DBWbf0DF.mjs → create-DNkqcne5.mjs} +2 -2
  54. package/dist/{create-D_AwGujc.mjs → create-Dd_NNxYT.mjs} +2 -2
  55. package/dist/{create-BtExn-0P.mjs → create-DqtqJZa8.mjs} +2 -2
  56. package/dist/create-Ds6gZXFm.mjs +48 -0
  57. package/dist/{create-D6eWvVcd.mjs → create-Z3UZdGTY.mjs} +3 -3
  58. package/dist/{create-branch-D56lVQNd.mjs → create-branch-CQyWpIxd.mjs} +2 -2
  59. package/dist/{create-BDBHkgLv.mjs → create-qCZ9z3II.mjs} +2 -2
  60. package/dist/{csv-D50rzoTk.mjs → csv-CFL145Ta.mjs} +4 -4
  61. package/dist/{current-task-CpPUJYbQ.mjs → current-task-l8KZ0nv8.mjs} +2 -2
  62. package/dist/dashboard-CIOXUaBJ.mjs +35 -0
  63. package/dist/{data-action-DLj9cgpu.mjs → data-action-Co_Yf1uC.mjs} +23 -5
  64. package/dist/{data-action-CuvI17XF.mjs → data-action-DAw6WRTH.mjs} +43 -10
  65. package/dist/data-action-_7UX21i9.mjs +24 -0
  66. package/dist/{data-app-3cmb-x-I.mjs → data-app-CxQNqhV2.mjs} +10 -10
  67. package/dist/{data-app-project-DUCJcvfJ.mjs → data-app-project-B_zd-YrJ.mjs} +1 -1
  68. package/dist/{db-BO1aJAAn.mjs → db-DlDWN6UP.mjs} +8 -8
  69. package/dist/{delete-DXL1orAc.mjs → delete-3KVEIg6-.mjs} +4 -4
  70. package/dist/{delete-DU1K-Cy4.mjs → delete-BlLyxBY_.mjs} +4 -4
  71. package/dist/{delete-8qsotOGB.mjs → delete-BmPR3qB0.mjs} +4 -4
  72. package/dist/{delete-CTtToAYO.mjs → delete-CcY_tcx4.mjs} +4 -4
  73. package/dist/{delete-DuVEKGA5.mjs → delete-CfkSkxHN.mjs} +4 -4
  74. package/dist/{delete-BSCnAB2g.mjs → delete-D3D0CTo-.mjs} +3 -3
  75. package/dist/{delete-ByYgGnoo.mjs → delete-Dj0ImrZL.mjs} +4 -4
  76. package/dist/{delete-DwNkDTga.mjs → delete-DweFD4-0.mjs} +4 -4
  77. package/dist/{delete-DHJ3ea0o.mjs → delete-Eje0xxEa.mjs} +4 -4
  78. package/dist/{delete-DU-Kinm4.mjs → delete-YFXRPnnb.mjs} +4 -4
  79. package/dist/{delete-runtime-DOOy3gzH.mjs → delete-runtime-C05-0fcn.mjs} +1 -1
  80. package/dist/{delete-table-RAznoioi.mjs → delete-table-BqpeGdMY.mjs} +4 -4
  81. package/dist/{dependencies-CKT460jf.mjs → dependencies-DhA1jbDT.mjs} +5 -5
  82. package/dist/{dependency-DcM96XJ-.mjs → dependency-BPCRTBKd.mjs} +1 -1
  83. package/dist/dependency-BPwCXzX4.mjs +15 -0
  84. package/dist/{dependents-D85CaupB.mjs → dependents-4KgDZ4tl.mjs} +6 -6
  85. package/dist/{dirty-BnuuGVxz.mjs → dirty-DWwwmOmi.mjs} +3 -3
  86. package/dist/{discard-values-CXyBp5pq.mjs → discard-values-6nmAd4kW.mjs} +5 -5
  87. package/dist/document-CC60L29U.mjs +20 -0
  88. package/dist/{download--RQk3dyK.mjs → download-ZCfcKa2L.mjs} +2 -2
  89. package/dist/{eid-BwhUajT8.mjs → eid-CjLvyBgT.mjs} +2 -2
  90. package/dist/{entry-flags-DS_MMJbV.mjs → entry-flags-2u45mDJ4.mjs} +1 -1
  91. package/dist/{events-DuHSrJuz.mjs → events-B_UxJw3Z.mjs} +4 -4
  92. package/dist/{execute-BjWeMJ0l.mjs → execute-Dg94sYQd.mjs} +11 -7
  93. package/dist/{export-C_G6D1MF.mjs → export-BdLB30iy.mjs} +3 -3
  94. package/dist/{export-flags-iXfEILf7.mjs → export-flags-DvdxpRMt.mjs} +1 -1
  95. package/dist/{export-preflight-DeqCCYP0.mjs → export-preflight-ChaWosZf.mjs} +2 -2
  96. package/dist/field-ClWwbYtG.mjs +21 -0
  97. package/dist/{fields-Ds2PnxA7.mjs → fields-B1cPeIGv.mjs} +4 -4
  98. package/dist/{filter-flags-ezqqsOQL.mjs → filter-flags-BEz2s28-.mjs} +1 -1
  99. package/dist/{fks-CCKTcQ4c.mjs → fks-DgvW6D_7.mjs} +5 -5
  100. package/dist/{get-R4_vq3U9.mjs → get-B69NUYR0.mjs} +4 -4
  101. package/dist/{get-D7Uq4t19.mjs → get-B94nj2uY.mjs} +2 -2
  102. package/dist/{get-8gu6wblt.mjs → get-BK7nxbPU.mjs} +2 -2
  103. package/dist/{get-CJEE2ApL.mjs → get-BM9AFJAi.mjs} +2 -2
  104. package/dist/{get-D_eGmu67.mjs → get-BYNEZFNj.mjs} +5 -5
  105. package/dist/{get-BB0b96ox.mjs → get-BxrS4Vi8.mjs} +4 -4
  106. package/dist/{get-CDA-g71Z.mjs → get-C_bCGVsR.mjs} +3 -3
  107. package/dist/{get-D3k4Pyfn.mjs → get-Ck2LNXxw.mjs} +3 -3
  108. package/dist/{get-C6qjCvoM.mjs → get-CmWe9xq9.mjs} +5 -5
  109. package/dist/{get-DkEOLIF5.mjs → get-D4oXmJTn.mjs} +5 -5
  110. package/dist/{get-D3kYRX7B.mjs → get-DC1lAsH_.mjs} +3 -3
  111. package/dist/{get-DVctVDj6.mjs → get-DIR9LODa.mjs} +4 -4
  112. package/dist/{get-CGrfQxXy.mjs → get-DStLX5Ah.mjs} +3 -3
  113. package/dist/{get-BOcwk9jz.mjs → get-DckpwiZG.mjs} +4 -4
  114. package/dist/{get-DXH0zRv1.mjs → get-DkSvigdw.mjs} +3 -3
  115. package/dist/{get-B_Vz5OMY.mjs → get-Dsm_2AXn.mjs} +3 -3
  116. package/dist/{get-v_BtTCdl.mjs → get-DuVVF8xb.mjs} +3 -3
  117. package/dist/{get-B_5Y65cZ.mjs → get-Ljt0QVR0.mjs} +3 -3
  118. package/dist/{get-xJTVgvSu.mjs → get-UNjwy8OI.mjs} +3 -3
  119. package/dist/{get-CTwU2SwT.mjs → get-VrzY4qxg.mjs} +2 -2
  120. package/dist/{get-Du0KCtaC.mjs → get-jphhROdg.mjs} +3 -3
  121. package/dist/{get-DSQSwjDw.mjs → get-n9udbUQS.mjs} +3 -3
  122. package/dist/{get-run-Ds50O2Rn.mjs → get-run-D5vfGnIN.mjs} +4 -4
  123. package/dist/git-sync-Bc9pf1LL.mjs +29 -0
  124. package/dist/glossary-CAzA-OIR.mjs +14 -0
  125. package/dist/{graph-DeGkHvI5.mjs → graph-CvIhSOEe.mjs} +4 -4
  126. package/dist/{group--6adAsqG.mjs → group-KiKh0UFs.mjs} +1 -1
  127. package/dist/{has-remote-changes-DUCn8d5k.mjs → has-remote-changes-57yJkr3b.mjs} +2 -2
  128. package/dist/{import-Bnun0H8L.mjs → import-HHsz_zDq.mjs} +3 -3
  129. package/dist/{is-dirty-BRdzj548.mjs → is-dirty-CxX_4rBC.mjs} +2 -2
  130. package/dist/{items-BmFznkYw.mjs → items-B2NR1_u3.mjs} +3 -3
  131. package/dist/{library-Cy8n_GoQ.mjs → library-DXvOVBTe.mjs} +5 -5
  132. package/dist/{list-B8WxIHZh.mjs → list-B44qweQa.mjs} +3 -3
  133. package/dist/{list-DwA83Hut.mjs → list-BK4VwtKe.mjs} +3 -3
  134. package/dist/{list-D7oLTX1F.mjs → list-BTpj7dv4.mjs} +5 -5
  135. package/dist/{list-CucyGz_M.mjs → list-BU72dCx0.mjs} +3 -3
  136. package/dist/{list-BXgbS3xg.mjs → list-BsQHh8w4.mjs} +3 -3
  137. package/dist/{list-DQNmzmbE.mjs → list-Bwi5npRx.mjs} +3 -3
  138. package/dist/{list-BJaTl4Z3.mjs → list-C6A-Eqgv.mjs} +5 -5
  139. package/dist/{list-B8FE0mi7.mjs → list-CNoCRL4D.mjs} +3 -3
  140. package/dist/{list-DCooGGd-.mjs → list-CY54buuD.mjs} +4 -4
  141. package/dist/{list-CgiBw3H-.mjs → list-CcZAP1sH.mjs} +5 -5
  142. package/dist/{list-emgvzTcQ.mjs → list-CtW9rAs4.mjs} +3 -3
  143. package/dist/{list-DqvwXEY3.mjs → list-DEQvaioL.mjs} +5 -5
  144. package/dist/{list-ChPsUv0M.mjs → list-DJ0_FcgB.mjs} +6 -6
  145. package/dist/{list-Hkl1mEcn.mjs → list-DJogq3Ez.mjs} +3 -3
  146. package/dist/{list-DkJsUigU.mjs → list-DMbtH6tY.mjs} +3 -3
  147. package/dist/{list-DVdfoOmD.mjs → list-DQ5BDB52.mjs} +4 -4
  148. package/dist/{list-hrR_sluM.mjs → list-DhCSllG2.mjs} +3 -3
  149. package/dist/{list-uDe8e-8m.mjs → list-DiN5mPrk.mjs} +3 -3
  150. package/dist/{list-jfnzEgFg.mjs → list-Dv8U4e-C.mjs} +3 -3
  151. package/dist/{list-jPZgEqWH.mjs → list-JS7ASJc-.mjs} +4 -4
  152. package/dist/{list-zIJcjZwa.mjs → list-L4_At_o9.mjs} +3 -3
  153. package/dist/{list-CnQnHNwI.mjs → list-l09h4Zp6.mjs} +3 -3
  154. package/dist/{list-Cv9U6hop.mjs → list-rA9U_VyF.mjs} +3 -3
  155. package/dist/{login-DMpRrZoJ.mjs → login-DVLN1666.mjs} +5 -5
  156. package/dist/{logout-DEB_Rs3z.mjs → logout-BiZxbftK.mjs} +2 -2
  157. package/dist/{measure-Dop8G1p3.mjs → measure-B7Ud8GU1.mjs} +6 -6
  158. package/dist/{notification-BEJaEZS2.mjs → notification-Bj45MgWm.mjs} +1 -1
  159. package/dist/{parameter-values-CuNu1kDf.mjs → parameter-values-BwaIYczs.mjs} +3 -3
  160. package/dist/{parse-id-EXZan40V.mjs → parse-id-BXkvTl89.mjs} +1 -1
  161. package/dist/{path-6xIAWlup.mjs → path-BbR0QB1I.mjs} +4 -4
  162. package/dist/{poll-uailHW3t.mjs → poll-D5eA9cN2.mjs} +1 -1
  163. package/dist/{preflight-4iy2qzsh.mjs → preflight-BJ5Bve-N.mjs} +1 -1
  164. package/dist/process-cDa9fEBe.mjs +144 -0
  165. package/dist/{publish-D7tndpBc.mjs → publish-d_WnLoJD.mjs} +3 -3
  166. package/dist/{pulse-CPSpum5U.mjs → pulse-DhddeMMG.mjs} +1 -1
  167. package/dist/{query-Do1Ms0k9.mjs → query-DFb-XQNz.mjs} +3 -3
  168. package/dist/{query-C_6GZwbJ.mjs → query-Dkod9Tev.mjs} +4 -4
  169. package/dist/{remapping-B5Z3Ustf.mjs → remapping-clW2Rgcz.mjs} +3 -3
  170. package/dist/{remove-collection-p9OgcXQ0.mjs → remove-collection-CjRtrkLW.mjs} +3 -3
  171. package/dist/{render-C3ygE5nO.mjs → render-C_Oy6cF5.mjs} +1 -1
  172. package/dist/{replace-D3I8Cb6E.mjs → replace-8hEY7br8.mjs} +4 -4
  173. package/dist/{requirement-check-DWGbJZUM.mjs → requirement-check-B7MNfiXv.mjs} +2 -2
  174. package/dist/{rescan-values-DgUwDmwZ.mjs → rescan-values-0owEJyWj.mjs} +4 -4
  175. package/dist/{rescan-values-DwYuiNzi.mjs → rescan-values-DaEu5sVZ.mjs} +3 -3
  176. package/dist/{run-BtRi59Hd.mjs → run-BlCJ0MYm.mjs} +4 -4
  177. package/dist/{run-qAs_RthF.mjs → run-CXv_3NQt.mjs} +3 -3
  178. package/dist/{run-Dr-DsQVO.mjs → run-Cr7QHB5S.mjs} +6 -6
  179. package/dist/run-Dc3u_olU.mjs +819 -0
  180. package/dist/{runs-hulvKxUw.mjs → runs-624fiVP3.mjs} +5 -5
  181. package/dist/{runtime-CEAFobLj.mjs → runtime-DsfR_yrb.mjs} +2 -2
  182. package/dist/{scaffold-CO9Oea2N.mjs → scaffold-D4Jo6VQc.mjs} +4 -4
  183. package/dist/{schema-D5AhDYTD.mjs → schema-DXsx2_Mk.mjs} +2 -2
  184. package/dist/{schema-tables-KIsDvvGs.mjs → schema-tables-Bat1bYLS.mjs} +5 -5
  185. package/dist/{schemas-DuGltR33.mjs → schemas-B8bgnxOA.mjs} +4 -4
  186. package/dist/{search-CM3ybv8O.mjs → search-BslDGFtS.mjs} +4 -4
  187. package/dist/{search-BJPNMvnK.mjs → search-fXh_MkLZ.mjs} +4 -4
  188. package/dist/{segment-BROyKyC3.mjs → segment-Bb7JTPmv.mjs} +6 -6
  189. package/dist/{send-cSr60J2Z.mjs → send-YnL6iiOt.mjs} +3 -3
  190. package/dist/{set-DpBA6eOn.mjs → set-CydWEHNW.mjs} +2 -2
  191. package/dist/{set-active-DaGUZCbh.mjs → set-active-C-x_A0AY.mjs} +2 -2
  192. package/dist/{set-bundle-CgJuQ3fe.mjs → set-bundle-DaHlkEYA.mjs} +3 -3
  193. package/dist/{set-data-actions-CyuKhCDs.mjs → set-data-actions-C3NwuCSF.mjs} +3 -3
  194. package/dist/{set-enabled-DxxlZePU.mjs → set-enabled-CjUOudzn.mjs} +2 -2
  195. package/dist/{set-sensitivity-BBkuW5wQ.mjs → set-sensitivity-DAodU0MG.mjs} +3 -3
  196. package/dist/{setting-BixEhGR2.mjs → setting-Bil7qFf0.mjs} +4 -4
  197. package/dist/{setup-DqAjBhZz.mjs → setup-B8GRygkY.mjs} +2 -2
  198. package/dist/{skill-list-BoJITnw8.mjs → skill-list-4LagdTq5.mjs} +1 -1
  199. package/dist/{skills-ByZWUsPC.mjs → skills-CW1wIl0c.mjs} +3 -3
  200. package/dist/{skills-CPNaSE_d.mjs → skills-DYfZF1GA.mjs} +4 -39
  201. package/dist/snippet-D9g83-mO.mjs +19 -0
  202. package/dist/{stash-BMitlOt0.mjs → stash-T0WRHnFD.mjs} +3 -3
  203. package/dist/{status-BxYGT5I4.mjs → status-BRMzSa12.mjs} +3 -3
  204. package/dist/{status-4ewKKM1J.mjs → status-CW1bsfaP.mjs} +2 -2
  205. package/dist/{subscription-9WV3hwAq.mjs → subscription-Edc8UK2V.mjs} +6 -6
  206. package/dist/{subscriptions-EVIRobQM.mjs → subscriptions-DMiWl84r.mjs} +6 -6
  207. package/dist/{summary-CaWLpvcZ.mjs → summary-CFnwsMoV.mjs} +3 -3
  208. package/dist/{sync-schema-BntqB-68.mjs → sync-schema-COvbx-g4.mjs} +4 -4
  209. package/dist/{sync-schema-Dt0zekZR.mjs → sync-schema-VzwA_5tH.mjs} +4 -4
  210. package/dist/table-CC-rFakp.mjs +26 -0
  211. package/dist/{table-BNA9Or05.mjs → table-DFbkLSgK.mjs} +1 -1
  212. package/dist/{table-selector-flags-BpFFoSaT.mjs → table-selector-flags-BhZo8RHH.mjs} +2 -2
  213. package/dist/timeline-C2ZUL_9F.mjs +21 -0
  214. package/dist/{timeline-event-CaXRyGXH.mjs → timeline-event-BqM82_7L.mjs} +6 -6
  215. package/dist/transform-BtB6iOJ9.mjs +28 -0
  216. package/dist/{transform-DKPtUV54.mjs → transform-CKeLIqoc.mjs} +1 -1
  217. package/dist/transform-job-I2Q5f0yN.mjs +22 -0
  218. package/dist/{transform-tag-QBmEYxZi.mjs → transform-tag-CxXDADhM.mjs} +5 -5
  219. package/dist/transform-test-B6jvvXeh.mjs +16 -0
  220. package/dist/{transform-test-C49ZTK7M.mjs → transform-test-C0c4zjcf.mjs} +1 -1
  221. package/dist/{transform-test-Bexa_K89.mjs → transform-test-DHTxBt4k.mjs} +2 -2
  222. package/dist/{transforms-yuckjEH-.mjs → transforms-WyRUDM1j.mjs} +5 -5
  223. package/dist/{transport-3xv524C_.mjs → transport-Byycx3RW.mjs} +3 -3
  224. package/dist/{tree-DhZWC6AW.mjs → tree-CMeV4bI8.mjs} +2 -2
  225. package/dist/{typed-schema-9umakTr7.mjs → typed-schema-DsGXH-La.mjs} +3 -3
  226. package/dist/{unpublish-BmrZNEcs.mjs → unpublish-EaVPnnZ5.mjs} +3 -3
  227. package/dist/{unreferenced-C0dYogu7.mjs → unreferenced-BvE7ke0M.mjs} +5 -5
  228. package/dist/{update-BIDjJnEh.mjs → update--uKYjq9_.mjs} +4 -4
  229. package/dist/{update-BsCY9WoI.mjs → update-B8EnadKJ.mjs} +3 -3
  230. package/dist/{update-DoZZ-pii.mjs → update-BDghcetp.mjs} +3 -3
  231. package/dist/{update-Dr66Dv3x.mjs → update-BPhLIVs9.mjs} +2 -2
  232. package/dist/{update-CzCc5og7.mjs → update-BSWoKNrf.mjs} +3 -3
  233. package/dist/{update-DRH78xMc.mjs → update-Bb1HPTH2.mjs} +4 -4
  234. package/dist/{update-D_9HdXGt.mjs → update-BgQ9TU63.mjs} +5 -5
  235. package/dist/{update-DTvdH8rF.mjs → update-BtWR4ri9.mjs} +3 -3
  236. package/dist/{update-B0j7R5BU.mjs → update-CFYVJJqw.mjs} +3 -3
  237. package/dist/{update-D4s8mpef.mjs → update-CNzu9eG1.mjs} +5 -5
  238. package/dist/{update-Gv4cQsS3.mjs → update-CT9e8m-I.mjs} +3 -3
  239. package/dist/{update-nZkZHbL5.mjs → update-DZPo69an.mjs} +4 -4
  240. package/dist/{update-DIsbIcWv.mjs → update-Dcwpy8BO.mjs} +3 -3
  241. package/dist/{update-BtyHjKV6.mjs → update-DjBJQCNg.mjs} +3 -3
  242. package/dist/{update-DuJ7Pu5t.mjs → update-DrY4i6eO.mjs} +4 -4
  243. package/dist/{update-CsYMNm1n.mjs → update-DwGo58Kc.mjs} +4 -4
  244. package/dist/{update-CqqZHGBZ.mjs → update-DyXj5mTv.mjs} +3 -3
  245. package/dist/{update-dashcard-fWxyfSG5.mjs → update-dashcard-BhT2FBd4.mjs} +3 -3
  246. package/dist/{update-DVEqN-uO.mjs → update-t2zdccd5.mjs} +5 -5
  247. package/dist/{update-eL6rSQvo2.mjs → update-wh2EjN242.mjs} +3 -3
  248. package/dist/{update-zKgO1dbJ.mjs → update-xYxKw2UB.mjs} +3 -3
  249. package/dist/{upgrade-PIUDxb6V.mjs → upgrade-BqBjnjjU.mjs} +3 -3
  250. package/dist/upload-C0GfBUvp.mjs +13 -0
  251. package/dist/{upload-KuHgzGJU.mjs → upload-D0zRTkyv.mjs} +1 -1
  252. package/dist/{upload-B6S0Vqgn.mjs → upload-kM0-7Bx2.mjs} +3 -3
  253. package/dist/{uuid-BPr2deuu.mjs → uuid-DsuYe9z7.mjs} +2 -2
  254. package/dist/{values-DHvfVT9h.mjs → values-kLEvyjSy.mjs} +3 -3
  255. package/dist/{verify-D9i63gmK.mjs → verify-ChvmI4lq.mjs} +3 -3
  256. package/dist/{verify-DS0REVed.mjs → verify-CvYsiaqY.mjs} +3 -3
  257. package/dist/{verify-CvGdvC7R.mjs → verify-D27n5y3t.mjs} +3 -3
  258. package/dist/{wait-DrOL01Y_.mjs → wait-DioDMGLJ.mjs} +4 -4
  259. package/dist/{wait-flags-DT1zA69Z.mjs → wait-flags-Qqvlb3Rv.mjs} +2 -2
  260. package/dist/{window-D1w7B0vh.mjs → window-BoW2xWwm.mjs} +1 -1
  261. package/dist/yaml-QoEP-7KU.mjs +38 -0
  262. package/package.json +1 -1
  263. package/skill-data/core/SKILL.md +1 -1
  264. package/skill-data/data-action/SKILL.md +50 -18
  265. package/skill-data/data-app-actions/SKILL.md +11 -5
  266. package/dist/api-key-DgEtUdtr.mjs +0 -13
  267. package/dist/card-uZeDk5uH.mjs +0 -25
  268. package/dist/collection-Cowt7nWW.mjs +0 -21
  269. package/dist/create-CA9c4U1m.mjs +0 -47
  270. package/dist/dashboard-CrD7w0mE.mjs +0 -35
  271. package/dist/data-action-p-8TbHAj.mjs +0 -24
  272. package/dist/dependency-B1wYuRR1.mjs +0 -15
  273. package/dist/document-BHXXSx3u.mjs +0 -20
  274. package/dist/field-C02nW-20.mjs +0 -21
  275. package/dist/git-sync-Dje-mnMh.mjs +0 -29
  276. package/dist/glossary-TBjFyeRN.mjs +0 -14
  277. package/dist/process-BQC3mK2k.mjs +0 -71
  278. package/dist/snippet-CK5QjPXs.mjs +0 -19
  279. package/dist/table-BAOSPOlO.mjs +0 -26
  280. package/dist/timeline-CyIVLhsz.mjs +0 -21
  281. package/dist/transform-C8ZiOTWq.mjs +0 -28
  282. package/dist/transform-job-BKX10IUY.mjs +0 -22
  283. package/dist/transform-test-DMShXj--.mjs +0 -16
  284. package/dist/upload-Dzn5OAbv.mjs +0 -13
@@ -0,0 +1,819 @@
1
+ import { c as InternalError, h as ValidationError, o as ConfigError, r as isPlainObject, s as FailedResultError } from "./predicates-0C0TsWcJ.mjs";
2
+ import { at as connectionFlags, d as serializeJson, dt as profileFlag, p as writeJsonLine, q as HttpError, t as interruptSignal } from "./cli.mjs";
3
+ import { t as defineMetabaseCommand } from "./runtime-DsfR_yrb.mjs";
4
+ import { i as TransformTestRefusalCode } from "./transform-test-DHTxBt4k.mjs";
5
+ import { i as runProcessBinary, r as runProcess, t as ProcessNotFoundError } from "./process-cDa9fEBe.mjs";
6
+ import { t as parseYaml } from "./yaml-QoEP-7KU.mjs";
7
+ import { z } from "zod";
8
+ import { writeFile } from "node:fs/promises";
9
+ import { randomUUID } from "node:crypto";
10
+ import { isDeepStrictEqual } from "node:util";
11
+ import { performance } from "node:perf_hooks";
12
+ //#region src/core/ci-coverage.ts
13
+ function byName(a, b) {
14
+ return a.name.localeCompare(b.name);
15
+ }
16
+ function assessCoverage(inputs) {
17
+ const logicAtBase = /* @__PURE__ */ new Map();
18
+ for (const { base } of inputs.changes) if (base?.kind === "transform") logicAtBase.set(base.entityId, base.logic);
19
+ const changed = /* @__PURE__ */ new Map();
20
+ for (const { head } of inputs.changes) {
21
+ if (head?.kind !== "transform" || inputs.testedAtHead.has(head.entityId)) continue;
22
+ const before = logicAtBase.get(head.entityId);
23
+ if (before === void 0) changed.set(head.entityId, {
24
+ entityId: head.entityId,
25
+ name: head.name,
26
+ change: "new"
27
+ });
28
+ else if (!isDeepStrictEqual(before, head.logic)) changed.set(head.entityId, {
29
+ entityId: head.entityId,
30
+ name: head.name,
31
+ change: "edited"
32
+ });
33
+ }
34
+ const untouchedUntested = [];
35
+ for (const [entityId, name] of inputs.transformsAtHead) if (!inputs.testedAtHead.has(entityId) && !changed.has(entityId)) untouchedUntested.push({
36
+ entityId,
37
+ name
38
+ });
39
+ return {
40
+ untestedChanges: [...changed.values()].toSorted(byName),
41
+ untouchedUntested: untouchedUntested.toSorted(byName)
42
+ };
43
+ }
44
+ const UNTOUCHED_CHECK_ID = "untouched";
45
+ function untouchedWarnings(untouched) {
46
+ if (untouched.length === 0) return [];
47
+ return [{
48
+ code: "no-tests-untouched",
49
+ message: `${untouched.length === 1 ? "1 transform whose logic this change did not touch has" : `${untouched.length} transforms whose logic this change did not touch have`} no tests: ${untouched.map((transform) => transform.name).join(", ")}`
50
+ }];
51
+ }
52
+ function coverageStage(assessment) {
53
+ return {
54
+ name: "lint",
55
+ run: async (report) => {
56
+ for (const transform of assessment.untestedChanges) report({
57
+ check: {
58
+ kind: "coverage",
59
+ id: transform.entityId,
60
+ label: transform.name
61
+ },
62
+ verdict: "failed",
63
+ warnings: [],
64
+ ms: 0,
65
+ detail: {
66
+ change: transform.change,
67
+ message: `${transform.name} is ${transform.change} in this change and has no transform tests`
68
+ }
69
+ });
70
+ const untouched = assessment.untouchedUntested;
71
+ report({
72
+ check: {
73
+ kind: "coverage",
74
+ id: UNTOUCHED_CHECK_ID,
75
+ label: "Transforms whose logic this change did not touch"
76
+ },
77
+ verdict: "passed",
78
+ warnings: untouchedWarnings(untouched),
79
+ ms: 0,
80
+ detail: { untested: untouched.map((transform) => ({
81
+ entity_id: transform.entityId,
82
+ name: transform.name
83
+ })) }
84
+ });
85
+ }
86
+ };
87
+ }
88
+ const StageName = z.enum(["lint", "unit"]);
89
+ const Verdict = z.enum([
90
+ "passed",
91
+ "failed",
92
+ "error",
93
+ "refused"
94
+ ]);
95
+ const StageStatus = z.enum([
96
+ "passed",
97
+ "failed",
98
+ "errored",
99
+ "skipped"
100
+ ]);
101
+ const JobState = StageStatus.exclude(["skipped"]);
102
+ const CiWarning = z.object({
103
+ code: z.string(),
104
+ message: z.string()
105
+ });
106
+ const CheckedTransform = z.object({
107
+ entity_id: z.string(),
108
+ name: z.string()
109
+ });
110
+ const Snapshot = z.object({
111
+ base: z.string(),
112
+ head: z.string()
113
+ });
114
+ const Check = z.object({
115
+ kind: z.enum([
116
+ "coverage",
117
+ "yaml",
118
+ "cycles",
119
+ "broken-refs",
120
+ "transform-test"
121
+ ]),
122
+ id: z.string(),
123
+ label: z.string()
124
+ });
125
+ const EventEnvelope = z.object({
126
+ seq: z.number().int().nonnegative(),
127
+ job: z.string(),
128
+ at: z.iso.datetime()
129
+ });
130
+ const JobStart = EventEnvelope.extend({
131
+ type: z.literal("job.start"),
132
+ v: z.literal(1),
133
+ snapshot: Snapshot,
134
+ checked: z.array(CheckedTransform),
135
+ warnings: z.array(CiWarning)
136
+ });
137
+ const StageStart = EventEnvelope.extend({
138
+ type: z.literal("stage.start"),
139
+ stage: StageName
140
+ });
141
+ const CheckResult = EventEnvelope.extend({
142
+ type: z.literal("check.result"),
143
+ stage: StageName,
144
+ check: Check,
145
+ verdict: Verdict,
146
+ warnings: z.array(CiWarning),
147
+ ms: z.number().nonnegative(),
148
+ detail: z.unknown()
149
+ });
150
+ const StageEnd = EventEnvelope.extend({
151
+ type: z.literal("stage.end"),
152
+ stage: StageName,
153
+ status: StageStatus
154
+ });
155
+ const JobEnd = EventEnvelope.extend({
156
+ type: z.literal("job.end"),
157
+ state: JobState,
158
+ counts: z.object({
159
+ checks: z.number().int(),
160
+ warnings: z.number().int()
161
+ })
162
+ });
163
+ const CiEvent = z.discriminatedUnion("type", [
164
+ JobStart,
165
+ StageStart,
166
+ CheckResult,
167
+ StageEnd,
168
+ JobEnd
169
+ ]);
170
+ function createEmitter(options) {
171
+ let seq = 0;
172
+ return (body) => {
173
+ const parsed = CiEvent.safeParse({
174
+ ...body,
175
+ seq,
176
+ job: options.job,
177
+ at: options.now().toISOString()
178
+ });
179
+ if (!parsed.success) throw new InternalError(`ci event "${body.type}" does not match its schema: ${parsed.error.message}`);
180
+ seq += 1;
181
+ options.write(parsed.data);
182
+ };
183
+ }
184
+ function stageStatus(verdicts) {
185
+ if (verdicts.includes("failed")) return "failed";
186
+ if (verdicts.includes("refused") || verdicts.includes("error")) return "errored";
187
+ return "passed";
188
+ }
189
+ async function runStages(stages, emit) {
190
+ let state = "passed";
191
+ let checks = 0;
192
+ let warnings = 0;
193
+ for (const stage of stages) {
194
+ if (state !== "passed") {
195
+ emit({
196
+ type: "stage.end",
197
+ stage: stage.name,
198
+ status: "skipped"
199
+ });
200
+ continue;
201
+ }
202
+ emit({
203
+ type: "stage.start",
204
+ stage: stage.name
205
+ });
206
+ const verdicts = [];
207
+ await stage.run((check) => {
208
+ verdicts.push(check.verdict);
209
+ checks += 1;
210
+ warnings += check.warnings.length;
211
+ emit({
212
+ type: "check.result",
213
+ stage: stage.name,
214
+ ...check
215
+ });
216
+ });
217
+ state = stageStatus(verdicts);
218
+ emit({
219
+ type: "stage.end",
220
+ stage: stage.name,
221
+ status: state
222
+ });
223
+ }
224
+ return {
225
+ state,
226
+ checks,
227
+ warnings
228
+ };
229
+ }
230
+ //#endregion
231
+ //#region src/core/ci-affected.ts
232
+ const SINGLE_PATH_STATUSES = /* @__PURE__ */ new Map([
233
+ ["A", "added"],
234
+ ["M", "modified"],
235
+ ["D", "deleted"],
236
+ ["T", "modified"]
237
+ ]);
238
+ const RENAME_STATUS = "R";
239
+ const COPY_STATUS = "C";
240
+ function nameStatusError(message) {
241
+ return new InternalError(`git diff --name-status -z: ${message}`);
242
+ }
243
+ function requireToken(token, what) {
244
+ if (token === void 0 || token === "") throw nameStatusError(`missing ${what}`);
245
+ return token;
246
+ }
247
+ function parseNameStatus(output) {
248
+ if (output === "") return [];
249
+ if (!output.endsWith("\0")) throw nameStatusError("truncated: the output does not end in a NUL");
250
+ const tokens = output.slice(0, -1).split("\0");
251
+ const entries = [];
252
+ let index = 0;
253
+ while (index < tokens.length) {
254
+ const code = requireToken(tokens[index], "a status");
255
+ const missingPath = `a path for status "${code}"`;
256
+ const first = tokens[index + 1];
257
+ const second = tokens[index + 2];
258
+ const letter = code.charAt(0);
259
+ const single = SINGLE_PATH_STATUSES.get(letter);
260
+ if (single !== void 0) {
261
+ entries.push({
262
+ status: single,
263
+ path: requireToken(first, missingPath)
264
+ });
265
+ index += 2;
266
+ continue;
267
+ }
268
+ if (letter === RENAME_STATUS) {
269
+ entries.push({
270
+ status: "renamed",
271
+ path: requireToken(second, missingPath),
272
+ oldPath: requireToken(first, missingPath)
273
+ });
274
+ index += 3;
275
+ continue;
276
+ }
277
+ if (letter === COPY_STATUS) {
278
+ entries.push({
279
+ status: "added",
280
+ path: requireToken(second, missingPath)
281
+ });
282
+ index += 3;
283
+ continue;
284
+ }
285
+ throw nameStatusError(`unexpected status "${code}"`);
286
+ }
287
+ return entries;
288
+ }
289
+ const PORCELAIN_STATUS_WIDTH = 2;
290
+ const PORCELAIN_SOURCE_STATUSES = /* @__PURE__ */ new Set(["R", "C"]);
291
+ function parseStatusPorcelain(output) {
292
+ if (output === "") return [];
293
+ if (!output.endsWith("\0")) throw new InternalError("git status --porcelain -z: truncated: the output does not end in a NUL");
294
+ const paths = [];
295
+ let sourceFollows = false;
296
+ for (const record of output.slice(0, -1).split("\0")) {
297
+ if (sourceFollows) {
298
+ sourceFollows = false;
299
+ continue;
300
+ }
301
+ const status = record.slice(0, PORCELAIN_STATUS_WIDTH);
302
+ const path = record.slice(3);
303
+ if (status.length !== PORCELAIN_STATUS_WIDTH || record.charAt(PORCELAIN_STATUS_WIDTH) !== " " || path === "") throw new InternalError(`git status --porcelain -z: malformed entry "${record}"`);
304
+ paths.push(path);
305
+ sourceFollows = [...status].some((letter) => PORCELAIN_SOURCE_STATUSES.has(letter));
306
+ }
307
+ return paths;
308
+ }
309
+ const SERDES_META_KEY = "serdes/meta";
310
+ const TransformDocument = z.object({
311
+ entity_id: z.string().min(1),
312
+ name: z.string().min(1),
313
+ source: z.unknown(),
314
+ target: z.unknown()
315
+ }).loose();
316
+ const TransformTestDocument = z.object({ transform_id: z.string().min(1) }).loose();
317
+ const SerdesMeta = z.array(z.object({ model: z.string() }).loose()).min(1);
318
+ function serdesModel(path, document) {
319
+ if (!isPlainObject(document) || !(SERDES_META_KEY in document)) return null;
320
+ const meta = SerdesMeta.safeParse(document[SERDES_META_KEY]);
321
+ if (!meta.success) throw new ValidationError(`${path}: ${SERDES_META_KEY} must be a non-empty list of entries with a model`, {
322
+ source: path,
323
+ zodIssues: meta.error.issues
324
+ });
325
+ const last = meta.data.at(-1);
326
+ if (last === void 0) throw new InternalError(`${path}: ${SERDES_META_KEY} passed a non-empty check but has no entries`);
327
+ return last.model;
328
+ }
329
+ function classifyContentFile(path, document) {
330
+ const model = serdesModel(path, document);
331
+ if (model === "Transform") {
332
+ const transform = TransformDocument.safeParse(document);
333
+ if (!transform.success) throw new ValidationError(`${path}: a Transform must have an entity_id, a name, a source and a target`, {
334
+ source: path,
335
+ zodIssues: transform.error.issues
336
+ });
337
+ return {
338
+ kind: "transform",
339
+ entityId: transform.data.entity_id,
340
+ name: transform.data.name,
341
+ logic: {
342
+ source: transform.data.source,
343
+ target: transform.data.target
344
+ }
345
+ };
346
+ }
347
+ if (model === "TransformTest") {
348
+ const test = TransformTestDocument.safeParse(document);
349
+ if (!test.success) throw new ValidationError(`${path}: a TransformTest must name its transform_id`, {
350
+ source: path,
351
+ zodIssues: test.error.issues
352
+ });
353
+ return {
354
+ kind: "transform-test",
355
+ transformId: test.data.transform_id
356
+ };
357
+ }
358
+ return { kind: "other" };
359
+ }
360
+ function transformEntityId(file) {
361
+ return file?.kind === "transform" ? file.entityId : null;
362
+ }
363
+ function affectedTransforms(changes) {
364
+ const touched = /* @__PURE__ */ new Set();
365
+ const atHead = /* @__PURE__ */ new Set();
366
+ const atBase = /* @__PURE__ */ new Set();
367
+ for (const { base, head } of changes) {
368
+ const headId = transformEntityId(head);
369
+ const baseId = transformEntityId(base);
370
+ if (headId !== null) {
371
+ touched.add(headId);
372
+ atHead.add(headId);
373
+ }
374
+ if (baseId !== null) atBase.add(baseId);
375
+ for (const side of [base, head]) if (side?.kind === "transform-test") touched.add(side.transformId);
376
+ }
377
+ return [...touched].filter((entityId) => atHead.has(entityId) || !atBase.has(entityId));
378
+ }
379
+ const CONTENT_FILE_EXTENSIONS = [".yaml", ".yml"];
380
+ function isContentPath(path) {
381
+ return CONTENT_FILE_EXTENSIONS.some((extension) => path.endsWith(extension));
382
+ }
383
+ function uncommittedContentWarning(paths) {
384
+ const content = paths.filter(isContentPath);
385
+ if (content.length === 0) return null;
386
+ return {
387
+ code: "uncommitted-content",
388
+ message: `${content.length === 1 ? "1 content file is" : `${content.length} content files are`} not committed, so CI did not check: ${content.join(", ")}`
389
+ };
390
+ }
391
+ //#endregion
392
+ //#region src/runtime/git.ts
393
+ const GIT = "git";
394
+ const NO_MATCH_EXIT_CODE = 1;
395
+ const NO_MERGE_BASE_EXIT_CODE = 1;
396
+ const UNKNOWN_REF_EXIT_CODE = 1;
397
+ async function withGit(spawn) {
398
+ try {
399
+ return await spawn();
400
+ } catch (error) {
401
+ if (error instanceof ProcessNotFoundError) throw new ConfigError("git is not installed or not on PATH");
402
+ throw error;
403
+ }
404
+ }
405
+ function runGit(repo, args) {
406
+ return withGit(() => runProcess(GIT, [
407
+ "-C",
408
+ repo,
409
+ ...args
410
+ ]));
411
+ }
412
+ async function git(repo, args) {
413
+ const result = await runGit(repo, args);
414
+ if (result.exitCode !== 0) throw new ConfigError(`git ${args.join(" ")} failed in ${repo}: ${result.stderr.trim()}`);
415
+ return result.stdout;
416
+ }
417
+ async function repositoryRoot(repo) {
418
+ const result = await runGit(repo, ["rev-parse", "--show-toplevel"]);
419
+ if (result.exitCode !== 0) throw new ConfigError(`--repo ${repo} is not inside a git work tree: ${result.stderr.trim()}`);
420
+ return result.stdout.trim();
421
+ }
422
+ async function resolveCommit(repo, ref, flag) {
423
+ const result = await runGit(repo, [
424
+ "rev-parse",
425
+ "--verify",
426
+ "--quiet",
427
+ "--end-of-options",
428
+ `${ref}^{commit}`
429
+ ]);
430
+ if (result.exitCode === UNKNOWN_REF_EXIT_CODE) throw new ConfigError(`${flag} ${ref} is not a commit in ${repo}`);
431
+ if (result.exitCode !== 0) throw new ConfigError(`git rev-parse failed in ${repo}: ${result.stderr.trim()}`);
432
+ return result.stdout.trim();
433
+ }
434
+ async function checkedOutCommit(repo) {
435
+ const result = await runGit(repo, [
436
+ "rev-parse",
437
+ "--verify",
438
+ "--quiet",
439
+ "HEAD"
440
+ ]);
441
+ if (result.exitCode === UNKNOWN_REF_EXIT_CODE) return null;
442
+ if (result.exitCode !== 0) throw new ConfigError(`git rev-parse HEAD failed in ${repo}: ${result.stderr.trim()}`);
443
+ return result.stdout.trim();
444
+ }
445
+ async function mergeBase(repo, base, head) {
446
+ const result = await runGit(repo, [
447
+ "merge-base",
448
+ base,
449
+ head
450
+ ]);
451
+ if (result.exitCode === NO_MERGE_BASE_EXIT_CODE) throw new ConfigError(`--base and --head share no history in ${repo}: the clone may be shallow (fetch the full history, e.g. actions/checkout with fetch-depth: 0), or the histories are unrelated`);
452
+ if (result.exitCode !== 0) throw new ConfigError(`git merge-base failed in ${repo}: ${result.stderr.trim()}`);
453
+ return result.stdout.trim();
454
+ }
455
+ function diffNameStatus(repo, from, to) {
456
+ return git(repo, [
457
+ "diff",
458
+ "--name-status",
459
+ "-z",
460
+ "-M",
461
+ from,
462
+ to
463
+ ]);
464
+ }
465
+ function statusPorcelain(repo) {
466
+ return git(repo, [
467
+ "status",
468
+ "--porcelain",
469
+ "-z",
470
+ "--untracked-files=all"
471
+ ]);
472
+ }
473
+ function readFileAt(repo, commit, path) {
474
+ return git(repo, [
475
+ "cat-file",
476
+ "blob",
477
+ `${commit}:${path}`
478
+ ]);
479
+ }
480
+ async function filesMatching(repo, commit, pattern, pathspecs) {
481
+ const result = await runGit(repo, [
482
+ "grep",
483
+ "--no-color",
484
+ "-z",
485
+ "-l",
486
+ "-E",
487
+ "-e",
488
+ pattern,
489
+ commit,
490
+ "--",
491
+ ...pathspecs
492
+ ]);
493
+ if (result.exitCode === NO_MATCH_EXIT_CODE) return [];
494
+ if (result.exitCode !== 0) throw new ConfigError(`git grep failed in ${repo}: ${result.stderr.trim()}`);
495
+ const prefix = `${commit}:`;
496
+ return result.stdout.split("\0").filter((entry) => entry !== "").map((entry) => {
497
+ if (!entry.startsWith(prefix)) throw new InternalError(`git grep printed "${entry}", which does not start with ${prefix}`);
498
+ return entry.slice(prefix.length);
499
+ });
500
+ }
501
+ const NEWLINE = 10;
502
+ const utf8 = new TextDecoder("utf-8");
503
+ async function readFilesAt(repo, commit, paths) {
504
+ const files = /* @__PURE__ */ new Map();
505
+ if (paths.length === 0) return files;
506
+ const multiline = paths.find((path) => path.includes("\n"));
507
+ if (multiline !== void 0) throw new ConfigError(`cannot read ${JSON.stringify(multiline)}: a path with a newline cannot be batched`);
508
+ const result = await withGit(() => runProcessBinary(GIT, [
509
+ "-C",
510
+ repo,
511
+ "cat-file",
512
+ "--batch"
513
+ ], { stdin: paths.map((path) => `${commit}:${path}\n`).join("") }));
514
+ if (result.exitCode !== 0) throw new ConfigError(`git cat-file --batch failed in ${repo}: ${result.stderr.trim()}`);
515
+ const output = result.stdout;
516
+ let offset = 0;
517
+ for (const path of paths) {
518
+ const headerEnd = output.indexOf(NEWLINE, offset);
519
+ if (headerEnd === -1) throw new InternalError(`git cat-file --batch stopped before ${path}`);
520
+ const header = utf8.decode(output.subarray(offset, headerEnd)).split(" ");
521
+ const size = Number(header[2]);
522
+ if (header[1] !== "blob" || !Number.isInteger(size)) throw new InternalError(`${path} is not a file at ${commit}, though git listed it there`);
523
+ const start = headerEnd + 1;
524
+ if (output[start + size] !== NEWLINE) throw new InternalError(`git cat-file --batch framed ${path} with ${size} bytes, but no newline follows them`);
525
+ files.set(path, utf8.decode(output.subarray(start, start + size)));
526
+ offset = start + size + 1;
527
+ }
528
+ if (offset !== output.length) throw new InternalError("git cat-file --batch printed more than the paths it was asked for");
529
+ return files;
530
+ }
531
+ //#endregion
532
+ //#region src/commands/ci/job-plan.ts
533
+ const CONTENT_PATHSPECS = CONTENT_FILE_EXTENSIONS.map((extension) => `*${extension}`);
534
+ async function classifyAt(repo, commit, path) {
535
+ if (path === null || !isContentPath(path)) return null;
536
+ return classifyContentFile(path, parseYaml(await readFileAt(repo, commit, path), z.unknown(), { source: `${commit}:${path}` }));
537
+ }
538
+ function basePath(entry) {
539
+ if (entry.status === "added") return null;
540
+ return entry.status === "renamed" ? entry.oldPath : entry.path;
541
+ }
542
+ function headPath(entry) {
543
+ return entry.status === "deleted" ? null : entry.path;
544
+ }
545
+ async function classifyChange(repo, forkPoint, head, entry) {
546
+ const [baseSide, headSide] = await Promise.all([classifyAt(repo, forkPoint, basePath(entry)), classifyAt(repo, head, headPath(entry))]);
547
+ return {
548
+ base: baseSide,
549
+ head: headSide
550
+ };
551
+ }
552
+ const TRANSFORM_MODEL_PATTERN = `model["']?:[[:space:]]*["']?Transform`;
553
+ function record(atHead, file) {
554
+ if (file?.kind === "transform") atHead.names.set(file.entityId, file.name);
555
+ else if (file?.kind === "transform-test") atHead.tested.add(file.transformId);
556
+ }
557
+ async function scanHead(repo, head, changes, changedPaths) {
558
+ const atHead = {
559
+ names: /* @__PURE__ */ new Map(),
560
+ tested: /* @__PURE__ */ new Set()
561
+ };
562
+ for (const change of changes) record(atHead, change.head);
563
+ const unchanged = (await filesMatching(repo, head, TRANSFORM_MODEL_PATTERN, CONTENT_PATHSPECS)).filter((path) => !changedPaths.has(path));
564
+ for (const [path, text] of await readFilesAt(repo, head, unchanged)) record(atHead, classifyContentFile(path, parseYaml(text, z.unknown(), { source: `${head}:${path}` })));
565
+ return atHead;
566
+ }
567
+ async function planJob(repoPath, baseRef, headRef) {
568
+ const repo = await repositoryRoot(repoPath);
569
+ const [base, head, checkout] = await Promise.all([
570
+ resolveCommit(repo, baseRef, "--base"),
571
+ resolveCommit(repo, headRef, "--head"),
572
+ checkedOutCommit(repo)
573
+ ]);
574
+ const forkPoint = await mergeBase(repo, base, head);
575
+ const entries = parseNameStatus(await diffNameStatus(repo, forkPoint, head));
576
+ const changes = await Promise.all(entries.map((entry) => classifyChange(repo, forkPoint, head, entry)));
577
+ const atHead = await scanHead(repo, head, changes, new Set(entries.map((entry) => entry.path)));
578
+ const checked = [];
579
+ const warnings = [];
580
+ for (const entityId of affectedTransforms(changes)) {
581
+ const name = atHead.names.get(entityId);
582
+ if (name === void 0) {
583
+ warnings.push({
584
+ code: "missing-transform",
585
+ message: `a changed transform test covers transform ${entityId}, which is not in the repo at ${head}`
586
+ });
587
+ continue;
588
+ }
589
+ checked.push({
590
+ entity_id: entityId,
591
+ name
592
+ });
593
+ }
594
+ const coverage = assessCoverage({
595
+ changes,
596
+ transformsAtHead: atHead.names,
597
+ testedAtHead: atHead.tested
598
+ });
599
+ if (head === checkout) {
600
+ const uncommitted = uncommittedContentWarning(parseStatusPorcelain(await statusPorcelain(repo)));
601
+ if (uncommitted !== null) warnings.push(uncommitted);
602
+ }
603
+ return {
604
+ snapshot: {
605
+ base,
606
+ head
607
+ },
608
+ checked,
609
+ warnings,
610
+ coverage
611
+ };
612
+ }
613
+ //#endregion
614
+ //#region src/commands/ci/job.ts
615
+ async function runJob(options) {
616
+ const events = [];
617
+ const emit = createEmitter({
618
+ job: options.job,
619
+ now: options.now,
620
+ write: (event) => {
621
+ events.push(event);
622
+ options.write(event);
623
+ }
624
+ });
625
+ const plan = await planJob(options.repo, options.base, options.head);
626
+ emit({
627
+ type: "job.start",
628
+ v: 1,
629
+ snapshot: plan.snapshot,
630
+ checked: plan.checked,
631
+ warnings: plan.warnings
632
+ });
633
+ const outcome = await runStages(await options.stages(plan), emit);
634
+ emit({
635
+ type: "job.end",
636
+ state: outcome.state,
637
+ counts: {
638
+ checks: outcome.checks,
639
+ warnings: outcome.warnings + plan.warnings.length
640
+ }
641
+ });
642
+ if (options.resultsPath !== null) await writeFile(options.resultsPath, serializeJson(events, false) + "\n", "utf8");
643
+ return outcome.state;
644
+ }
645
+ //#endregion
646
+ //#region src/core/ci-unit.ts
647
+ function testVerdict(result) {
648
+ const statuses = new Set(result.expectations.map((expectation) => expectation.status));
649
+ if (statuses.has("failed")) return "failed";
650
+ if (statuses.has("error")) return "error";
651
+ return "passed";
652
+ }
653
+ function testRefusal(error) {
654
+ if (!(error instanceof HttpError)) return null;
655
+ const code = TransformTestRefusalCode.safeParse(error.errorCode);
656
+ if (!code.success) return null;
657
+ return {
658
+ error_code: code.data,
659
+ message: error.serverMessage ?? error.message
660
+ };
661
+ }
662
+ const CHANGE_FAILURE_CODES = /* @__PURE__ */ new Set(["transform-test.transform-failed", "transform-test.unparseable-source"]);
663
+ function refusalVerdict(refusal) {
664
+ return CHANGE_FAILURE_CODES.has(refusal.error_code) ? "failed" : "refused";
665
+ }
666
+ //#endregion
667
+ //#region src/commands/ci/unit-stage.ts
668
+ const TEST_TIMEOUT_MS = 12e4;
669
+ const OK_STATUS = "ok";
670
+ const LOOKUP_KIND_BY_STATUS = /* @__PURE__ */ new Map([["not-found", "not-found"], ["invalid-format", "invalid-entity-id"]]);
671
+ function transformLookup(entityId, entry) {
672
+ if (entry?.status === OK_STATUS && entry.id !== void 0) return {
673
+ kind: "found",
674
+ id: entry.id
675
+ };
676
+ const kind = entry === void 0 ? void 0 : LOOKUP_KIND_BY_STATUS.get(entry.status);
677
+ if (kind === void 0) throw new InternalError(`eid translation answered ${entityId} with ${JSON.stringify(entry ?? null)}`);
678
+ return { kind };
679
+ }
680
+ function clientPort(client) {
681
+ return {
682
+ lookUpTransforms: async (entityIds) => {
683
+ const result = await client.eidTranslation.translate({ entity_ids: { transform: [...entityIds] } });
684
+ const lookups = /* @__PURE__ */ new Map();
685
+ for (const entityId of entityIds) lookups.set(entityId, transformLookup(entityId, result.entity_ids[entityId]));
686
+ return lookups;
687
+ },
688
+ listTests: async (transformId) => (await client.transformTest.list({ "transform-id": transformId })).data,
689
+ runTest: (testId) => client.transformTest.run(testId, {
690
+ timeoutMs: TEST_TIMEOUT_MS,
691
+ signal: interruptSignal
692
+ }),
693
+ nowMs: () => performance.now()
694
+ };
695
+ }
696
+ const MISSING_TRANSFORM_DETAIL = {
697
+ "not-found": {
698
+ error_code: "ci.transform-not-on-instance",
699
+ message: "the transform is in the branch but not on the Metabase instance; load the branch into it first"
700
+ },
701
+ "invalid-entity-id": {
702
+ error_code: "ci.invalid-entity-id",
703
+ message: "the transform's entity_id in the branch is not a valid entity id"
704
+ }
705
+ };
706
+ function unitStage(checked, connect) {
707
+ return {
708
+ name: "unit",
709
+ run: async (report) => {
710
+ const port = await connect();
711
+ const lookups = await port.lookUpTransforms(checked.map((transform) => transform.entity_id));
712
+ for (const transform of checked) {
713
+ const lookup = lookups.get(transform.entity_id);
714
+ if (lookup === void 0) throw new InternalError(`no lookup for transform ${transform.entity_id}`);
715
+ if (lookup.kind !== "found") {
716
+ report({
717
+ check: {
718
+ kind: "transform-test",
719
+ id: transform.entity_id,
720
+ label: transform.name
721
+ },
722
+ verdict: "refused",
723
+ warnings: [],
724
+ ms: 0,
725
+ detail: MISSING_TRANSFORM_DETAIL[lookup.kind]
726
+ });
727
+ continue;
728
+ }
729
+ const tests = await port.listTests(lookup.id);
730
+ for (const test of tests.toSorted((a, b) => a.id - b.id)) {
731
+ const check = {
732
+ kind: "transform-test",
733
+ id: String(test.id),
734
+ label: `${transform.name}: ${test.name}`
735
+ };
736
+ const started = port.nowMs();
737
+ try {
738
+ const result = await port.runTest(test.id);
739
+ report({
740
+ check,
741
+ verdict: testVerdict(result),
742
+ warnings: [],
743
+ ms: port.nowMs() - started,
744
+ detail: result
745
+ });
746
+ } catch (error) {
747
+ const refusal = testRefusal(error);
748
+ if (refusal === null) throw error;
749
+ report({
750
+ check,
751
+ verdict: refusalVerdict(refusal),
752
+ warnings: [],
753
+ ms: port.nowMs() - started,
754
+ detail: refusal
755
+ });
756
+ }
757
+ }
758
+ }
759
+ }
760
+ };
761
+ }
762
+ //#endregion
763
+ //#region src/commands/ci/run.ts
764
+ var run_default = defineMetabaseCommand({
765
+ meta: {
766
+ name: "run",
767
+ description: "Check the transforms a branch changed, writing one JSON event per line"
768
+ },
769
+ details: "Compares --head with its merge base with --base, finds the transforms whose files or tests changed, and runs their transform tests on the Metabase instance of --profile, which must already hold the branch's content. Only committed content is checked: when --head is the checked-out commit, a content file that is modified or untracked in the working tree is listed in an `uncommitted-content` warning instead. Writes one JSON event per line (`job.start`, then each stage and check, then `job.end`); `job.start.checked` lists the transforms the job covered, and each transform test's result is passed through as the check's `detail`. Exits 1 when the job does not pass; `job.end.state` says whether a check failed (`failed`: fix the transform) or could not run (`errored`: fix the test or the setup). A crash stops the stream before `job.end` and writes no --results file.",
770
+ requires: [
771
+ "eidTranslation.translate",
772
+ "transformTest.list",
773
+ "transformTest.run"
774
+ ],
775
+ args: {
776
+ ...profileFlag,
777
+ ...connectionFlags,
778
+ base: {
779
+ type: "string",
780
+ description: "Ref the branch is compared against",
781
+ required: true
782
+ },
783
+ head: {
784
+ type: "string",
785
+ description: "Ref to check",
786
+ default: "HEAD"
787
+ },
788
+ repo: {
789
+ type: "string",
790
+ description: "Path to the git repository",
791
+ default: "."
792
+ },
793
+ results: {
794
+ type: "string",
795
+ description: "Also write every event to this JSON file"
796
+ }
797
+ },
798
+ outputSchema: CiEvent,
799
+ examples: ["mb ci run --base origin/main", "mb ci run --base origin/main --results results.json"],
800
+ async run({ args, getClient }) {
801
+ const state = await runJob({
802
+ repo: args.repo,
803
+ base: args.base,
804
+ head: args.head,
805
+ stages: async (plan) => {
806
+ const lint = coverageStage(plan.coverage);
807
+ if (plan.checked.length === 0) return [lint];
808
+ return [lint, unitStage(plan.checked, async () => clientPort(await getClient()))];
809
+ },
810
+ job: randomUUID(),
811
+ now: () => /* @__PURE__ */ new Date(),
812
+ write: writeJsonLine,
813
+ resultsPath: args.results ?? null
814
+ });
815
+ if (state !== "passed") throw new FailedResultError(`ci job ${state}`);
816
+ }
817
+ });
818
+ //#endregion
819
+ export { run_default as default };